Skip to content

Commit

Permalink
Adds tests for default columns using unified database patterns
Browse files Browse the repository at this point in the history
  • Loading branch information
3commascapital committed Oct 8, 2024
1 parent 1c2e219 commit 2b8c4f5
Show file tree
Hide file tree
Showing 4 changed files with 176 additions and 65 deletions.
171 changes: 171 additions & 0 deletions packages/core/src/database/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
} from "@/utils/checkpoint.js";
import { wait } from "@/utils/wait.js";
import { sql } from "kysely";
import { hexToBytes, zeroAddress } from "viem";
import { beforeEach, expect, test } from "vitest";
import { type Database, createDatabase } from "./index.js";

Expand Down Expand Up @@ -58,6 +59,40 @@ const schemaTwo = createSchema((p) => ({
}),
}));

const dogWithDefaults = createSchema((p) => ({
Dog: p.createTable({
id: p.string().default("0"),
name: p.string().default("firstname"),
age: p.int().default(5).optional(),
bigAge: p.bigint().default(5n).optional(),
bowl: p.hex().default(zeroAddress),
toys: p.json().default({
bone: "sofa",
ball: "bed",
}),
commands: p.json().default([
"sit",
"stay",
{
paw: {
right: true,
left: false,
},
},
]),
}),
}));

type Dog = {
id: string;
name: string;
age: string;
bigAge: bigint;
bowl: string;
toys: {};
commands: (string | {})[];
};

function createCheckpoint(index: number): Checkpoint {
return { ...zeroCheckpoint, blockTimestamp: index };
}
Expand Down Expand Up @@ -759,6 +794,97 @@ test("revert() updates versions with intermediate logs", async (context) => {
await cleanup();
});

test("information about columns can be queried", async (context) => {
const database = createDatabase({
common: context.common,
schema: dogWithDefaults,
databaseConfig: context.databaseConfig,
});
await database.setup({ buildId: "abc" });

const defaults = await getTableDefaults(database, "Dog");
const dogTable = dogWithDefaults.Dog.table;
for (const [column, metadata] of Object.entries(defaults)) {
expect(dogTable[column as keyof typeof dogTable]).not.to.be.empty;
expect(metadata.default).to.be.toBeTypeOf("string");
expect(metadata.type).to.be.toBeTypeOf("string");
}
await database.kill();
});

test("default values are populated during insertion", async (context) => {
const database = createDatabase({
common: context.common,
schema: dogWithDefaults,
databaseConfig: context.databaseConfig,
});
await database.setup({ buildId: "abc" });

const { rows } = await database.qb.internal.executeQuery<Dog[]>(
(database.dialect === "sqlite"
? sql`
INSERT INTO Dog
DEFAULT VALUES
RETURNING *
`
: sql`INSERT INTO "Dog"(id, name, age, "bigAge", bowl, toys)
VALUES(DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT)
RETURNING *`
).compile(database.qb.internal),
);
const sqliteRows = [
{
id: "0",
name: "firstname",
age: 5,
bigAge: "5",
bowl: `\\x${zeroAddress.slice(2)}`,
commands: JSON.stringify([
"sit",
"stay",
{
paw: {
right: true,
left: false,
},
},
]),
toys: JSON.stringify({
bone: "sofa",
ball: "bed",
}),
},
];
const pgRows = [
{
id: "0",
name: "firstname",
age: 5,
bigAge: 5n,
bowl: Buffer.from(hexToBytes(zeroAddress)),
commands: [
"sit",
"stay",
{
paw: {
right: true,
left: false,
},
},
],
toys: {
bone: "sofa",
ball: "bed",
},
},
];
expect(rows).to.deep.equal(
database.dialect === "sqlite" ? sqliteRows : pgRows,
);

await database.kill();
});

async function getUserTableNames(database: Database) {
const { rows } = await database.qb.internal.executeQuery<{ name: string }>(
database.dialect === "sqlite"
Expand Down Expand Up @@ -793,3 +919,48 @@ async function getUserIndexNames(database: Database, tableName: string) {
);
return rows.map((r) => r.name);
}

async function getTableDefaults(db: Database, tableName: string) {
if (db.dialect === "sqlite") {
const { rows } = await db.qb.internal.executeQuery<{
name: string;
type: string;
dflt_value: string | null;
}>(
sql`SELECT * from ${sql.raw(db.namespace)}.pragma_table_info('${sql.raw(tableName)}')`.compile(
db.qb.internal,
),
);
return rows.reduce(
(obj, column) => {
obj[column.name] = {
type: column.type,
default: column.dflt_value,
};
return obj;
},
{} as Record<string, { type: string; default: any }>,
);
} else {
const { rows } = await db.qb.internal.executeQuery<{
column_name: string;
data_type: string;
column_default: string;
}>(
sql`SELECT *
FROM information_schema.columns
WHERE table_schema = '${sql.raw(db.namespace)}'
AND table_name = '${sql.raw(tableName)}'`.compile(db.qb.internal),
);
return rows.reduce(
(obj, column) => {
obj[column.column_name] = {
type: column.data_type,
default: column.column_default,
};
return obj;
},
{} as Record<string, { type: string; default: any }>,
);
}
}
4 changes: 4 additions & 0 deletions packages/core/src/database/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { NonRetryableError } from "@/common/errors.js";
import type { DatabaseConfig } from "@/config/database.js";
import type { Schema } from "@/schema/common.js";
import {
applyDefault,
getEnums,
getTables,
isEnumColumn,
Expand Down Expand Up @@ -698,6 +699,7 @@ export const createDatabase = (args: {
columnName,
"text",
(col) => {
col = applyDefault(col, column);
if (isOptionalColumn(column) === false)
col = col.notNull();
if (isListColumn(column) === false) {
Expand Down Expand Up @@ -729,6 +731,7 @@ export const createDatabase = (args: {
columnName,
"jsonb",
(col) => {
col = applyDefault(col, column);
if (isOptionalColumn(column) === false)
col = col.notNull();
return col;
Expand All @@ -742,6 +745,7 @@ export const createDatabase = (args: {
? scalarToSqliteType
: scalarToPostgresType)[column[" scalar"]],
(col) => {
col = applyDefault(col, column);
if (isOptionalColumn(column) === false)
col = col.notNull();
if (columnName === "id") col = col.primaryKey();
Expand Down
64 changes: 0 additions & 64 deletions packages/core/src/database/schemas-test.ts

This file was deleted.

2 changes: 1 addition & 1 deletion packages/core/src/indexing-store/utils/encoding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ function decodeValue({
return value === 1;
} else if (column[" scalar"] === "hex") {
return bytesToHex(value as Uint8Array);
} else if (column[" scalar"] === "bigint" && encoding === "sqlite") {
} else if (column[" scalar"] === "bigint" && dialect === "sqlite") {
return decodeToBigInt(value as string);
} else {
return value as UserValue;
Expand Down

0 comments on commit 2b8c4f5

Please sign in to comment.