import type { Column, InferSelectModel } from "drizzle-orm"; import type { ForeignKey as MysqlForeignKey, MySqlTableWithColumns, } from "drizzle-orm/mysql-core"; import type { ForeignKey as SqliteForeignKey, SQLiteTableWithColumns, } from "drizzle-orm/sqlite-core"; import { expect, expectTypeOf, test } from "vitest"; import { objectEntries } from "@homarr/common"; import * as mysqlSchema from "../schema/mysql"; import * as sqliteSchema from "../schema/sqlite"; test("schemas should match", () => { expectTypeOf().toEqualTypeOf(); expectTypeOf().toEqualTypeOf(); expectTypeOf().toEqualTypeOf(); expectTypeOf().toEqualTypeOf(); objectEntries(sqliteSchema).forEach(([tableName, sqliteTable]) => { Object.entries(sqliteTable).forEach( ([columnName, sqliteColumn]: [string, object]) => { if (!("isUnique" in sqliteColumn)) return; if (!("uniqueName" in sqliteColumn)) return; if (!("primary" in sqliteColumn)) return; const mysqlTable = mysqlSchema[tableName]; const mysqlColumn = mysqlTable[ columnName as keyof typeof mysqlTable ] as object; if (!("isUnique" in mysqlColumn)) return; if (!("uniqueName" in mysqlColumn)) return; if (!("primary" in mysqlColumn)) return; expect( sqliteColumn.isUnique, `expect unique of column ${columnName} in table ${tableName} to be the same for both schemas`, ).toEqual(mysqlColumn.isUnique); expect( sqliteColumn.uniqueName, `expect uniqueName of column ${columnName} in table ${tableName} to be the same for both schemas`, ).toEqual(mysqlColumn.uniqueName); expect( sqliteColumn.primary, `expect primary of column ${columnName} in table ${tableName} to be the same for both schemas`, ).toEqual(mysqlColumn.primary); }, ); const mysqlTable = mysqlSchema[tableName]; const sqliteForeignKeys = sqliteTable[ Symbol.for("drizzle:SQLiteInlineForeignKeys") as keyof typeof sqliteTable ] as SqliteForeignKey[] | undefined; const mysqlForeignKeys = mysqlTable[ Symbol.for("drizzle:MySqlInlineForeignKeys") as keyof typeof mysqlTable ] as MysqlForeignKey[] | undefined; if (!sqliteForeignKeys && !mysqlForeignKeys) return; expect( mysqlForeignKeys, `mysql foreign key for ${tableName} to be defined`, ).toBeDefined(); expect( sqliteForeignKeys, `sqlite foreign key for ${tableName} to be defined`, ).toBeDefined(); expect( sqliteForeignKeys!.length, `expect number of foreign keys in table ${tableName} to be the same for both schemas`, ).toEqual(mysqlForeignKeys!.length); sqliteForeignKeys?.forEach((sqliteForeignKey) => { sqliteForeignKey.getName(); const mysqlForeignKey = mysqlForeignKeys!.find( (key) => key.getName() === sqliteForeignKey.getName(), ); expect( mysqlForeignKey, `expect foreign key ${sqliteForeignKey.getName()} to be defined in mysql schema`, ).toBeDefined(); expect( sqliteForeignKey.onDelete, `expect foreign key (${sqliteForeignKey.getName()}) onDelete to be the same for both schemas`, ).toEqual(mysqlForeignKey!.onDelete); expect( sqliteForeignKey.onUpdate, `expect foreign key (${sqliteForeignKey.getName()}) onUpdate to be the same for both schemas`, ).toEqual(mysqlForeignKey!.onUpdate); sqliteForeignKey.reference().foreignColumns.forEach((column) => { expect( mysqlForeignKey! .reference() .foreignColumns.map((column) => column.name), `expect foreign key (${sqliteForeignKey.getName()}) columns to be the same for both schemas`, ).toContainEqual(column.name); }); expect( Object.keys(sqliteForeignKey.reference().foreignTable), `expect foreign key (${sqliteForeignKey.getName()}) table to be the same for both schemas`, ).toEqual(Object.keys(mysqlForeignKey!.reference().foreignTable)); }); }); }); type SqliteTables = { // eslint-disable-next-line @typescript-eslint/no-explicit-any [K in keyof typeof sqliteSchema]: (typeof sqliteSchema)[K] extends SQLiteTableWithColumns ? InferSelectModel<(typeof sqliteSchema)[K]> : never; }; type MysqlTables = { // eslint-disable-next-line @typescript-eslint/no-explicit-any [K in keyof typeof mysqlSchema]: (typeof mysqlSchema)[K] extends MySqlTableWithColumns ? InferSelectModel<(typeof mysqlSchema)[K]> : never; }; // eslint-disable-next-line @typescript-eslint/no-explicit-any type InferColumnConfig> = T extends Column ? Omit : never; type SqliteConfig = { // eslint-disable-next-line @typescript-eslint/no-explicit-any [K in keyof typeof sqliteSchema]: (typeof sqliteSchema)[K] extends SQLiteTableWithColumns ? { [C in keyof (typeof sqliteSchema)[K]["_"]["config"]["columns"]]: InferColumnConfig< (typeof sqliteSchema)[K]["_"]["config"]["columns"][C] >; } : never; }; type MysqlConfig = { // eslint-disable-next-line @typescript-eslint/no-explicit-any [K in keyof typeof mysqlSchema]: (typeof mysqlSchema)[K] extends MySqlTableWithColumns ? { [C in keyof (typeof mysqlSchema)[K]["_"]["config"]["columns"]]: InferColumnConfig< (typeof mysqlSchema)[K]["_"]["config"]["columns"][C] >; } : never; };