better-auth
Version:
The most comprehensive authentication framework for TypeScript.
1 lines • 26.3 kB
Source Map (JSON)
{"version":3,"file":"get-migration.mjs","names":["logger","toBeCreated: {\n\t\ttable: string;\n\t\tfields: Record<string, DBFieldAttribute>;\n\t\torder: number;\n\t}[]","toBeAdded: {\n\t\ttable: string;\n\t\tfields: Record<string, DBFieldAttribute>;\n\t\torder: number;\n\t}[]","toBeAddedFields: Record<string, DBFieldAttribute>","migrations: (\n\t\t| AlterTableColumnAlteringBuilder\n\t\t| ReturnType<AlterTableBuilder[\"addIndex\"]>\n\t\t| CreateTableBuilder<string, string>\n\t\t| CreateIndexBuilder\n\t)[]","typeMap: Record<\n\t\t\tStringOnlyUnion<DBFieldType> | \"id\" | \"foreignKeyId\",\n\t\t\tRecord<KyselyDatabaseType, ColumnDataType | RawBuilder<unknown>>\n\t\t>","toBeIndexed: CreateIndexBuilder[]"],"sources":["../../src/db/get-migration.ts"],"sourcesContent":["import type { BetterAuthOptions } from \"@better-auth/core\";\nimport type { DBFieldAttribute, DBFieldType } from \"@better-auth/core/db\";\nimport { getAuthTables } from \"@better-auth/core/db\";\nimport {\n\tinitGetFieldName,\n\tinitGetModelName,\n} from \"@better-auth/core/db/adapter\";\nimport { createLogger } from \"@better-auth/core/env\";\nimport type {\n\tAlterTableBuilder,\n\tAlterTableColumnAlteringBuilder,\n\tColumnDataType,\n\tCreateIndexBuilder,\n\tCreateTableBuilder,\n\tKysely,\n\tRawBuilder,\n} from \"kysely\";\nimport { sql } from \"kysely\";\nimport { createKyselyAdapter } from \"../adapters/kysely-adapter/dialect\";\nimport type { KyselyDatabaseType } from \"../adapters/kysely-adapter/types\";\nimport { getSchema } from \"./get-schema\";\n\nconst postgresMap = {\n\tstring: [\"character varying\", \"varchar\", \"text\", \"uuid\"],\n\tnumber: [\n\t\t\"int4\",\n\t\t\"integer\",\n\t\t\"bigint\",\n\t\t\"smallint\",\n\t\t\"numeric\",\n\t\t\"real\",\n\t\t\"double precision\",\n\t],\n\tboolean: [\"bool\", \"boolean\"],\n\tdate: [\"timestamptz\", \"timestamp\", \"date\"],\n\tjson: [\"json\", \"jsonb\"],\n};\nconst mysqlMap = {\n\tstring: [\"varchar\", \"text\", \"uuid\"],\n\tnumber: [\n\t\t\"integer\",\n\t\t\"int\",\n\t\t\"bigint\",\n\t\t\"smallint\",\n\t\t\"decimal\",\n\t\t\"float\",\n\t\t\"double\",\n\t],\n\tboolean: [\"boolean\", \"tinyint\"],\n\tdate: [\"timestamp\", \"datetime\", \"date\"],\n\tjson: [\"json\"],\n};\n\nconst sqliteMap = {\n\tstring: [\"TEXT\"],\n\tnumber: [\"INTEGER\", \"REAL\"],\n\tboolean: [\"INTEGER\", \"BOOLEAN\"], // 0 or 1\n\tdate: [\"DATE\", \"INTEGER\"],\n\tjson: [\"TEXT\"],\n};\n\nconst mssqlMap = {\n\tstring: [\"varchar\", \"nvarchar\", \"uniqueidentifier\"],\n\tnumber: [\"int\", \"bigint\", \"smallint\", \"decimal\", \"float\", \"double\"],\n\tboolean: [\"bit\", \"smallint\"],\n\tdate: [\"datetime2\", \"date\", \"datetime\"],\n\tjson: [\"varchar\", \"nvarchar\"],\n};\n\nconst map = {\n\tpostgres: postgresMap,\n\tmysql: mysqlMap,\n\tsqlite: sqliteMap,\n\tmssql: mssqlMap,\n};\n\nexport function matchType(\n\tcolumnDataType: string,\n\tfieldType: DBFieldType,\n\tdbType: KyselyDatabaseType,\n) {\n\tfunction normalize(type: string) {\n\t\treturn type.toLowerCase().split(\"(\")[0]!.trim();\n\t}\n\tif (fieldType === \"string[]\" || fieldType === \"number[]\") {\n\t\treturn columnDataType.toLowerCase().includes(\"json\");\n\t}\n\tconst types = map[dbType]!;\n\tconst expected = Array.isArray(fieldType)\n\t\t? types[\"string\"].map((t) => t.toLowerCase())\n\t\t: types[fieldType]!.map((t) => t.toLowerCase());\n\treturn expected.includes(normalize(columnDataType));\n}\n\n/**\n * Get the current PostgreSQL schema (search_path) for the database connection\n * Returns the first schema in the search_path, defaulting to 'public' if not found\n */\nasync function getPostgresSchema(db: Kysely<unknown>): Promise<string> {\n\ttry {\n\t\tconst result = await sql<{ search_path: string }>`SHOW search_path`.execute(\n\t\t\tdb,\n\t\t);\n\t\tif (result.rows[0]?.search_path) {\n\t\t\t// search_path can be a comma-separated list like \"$user, public\" or '\"$user\", public'\n\t\t\t// We want the first non-variable schema\n\t\t\tconst schemas = result.rows[0].search_path\n\t\t\t\t.split(\",\")\n\t\t\t\t.map((s) => s.trim())\n\t\t\t\t// Remove quotes and filter out variables like $user\n\t\t\t\t.map((s) => s.replace(/^[\"']|[\"']$/g, \"\"))\n\t\t\t\t.filter((s) => !s.startsWith(\"$\"));\n\t\t\treturn schemas[0] || \"public\";\n\t\t}\n\t} catch {\n\t\t// If query fails, fall back to public schema\n\t}\n\treturn \"public\";\n}\n\nexport async function getMigrations(config: BetterAuthOptions) {\n\tconst betterAuthSchema = getSchema(config);\n\tconst logger = createLogger(config.logger);\n\n\tlet { kysely: db, databaseType: dbType } = await createKyselyAdapter(config);\n\n\tif (!dbType) {\n\t\tlogger.warn(\n\t\t\t\"Could not determine database type, defaulting to sqlite. Please provide a type in the database options to avoid this.\",\n\t\t);\n\t\tdbType = \"sqlite\";\n\t}\n\n\tif (!db) {\n\t\tlogger.error(\n\t\t\t\"Only kysely adapter is supported for migrations. You can use `generate` command to generate the schema, if you're using a different adapter.\",\n\t\t);\n\t\tprocess.exit(1);\n\t}\n\n\t// For PostgreSQL, detect and log the current schema being used\n\tlet currentSchema = \"public\";\n\tif (dbType === \"postgres\") {\n\t\tcurrentSchema = await getPostgresSchema(db);\n\t\tlogger.debug(\n\t\t\t`PostgreSQL migration: Using schema '${currentSchema}' (from search_path)`,\n\t\t);\n\n\t\t// Verify the schema exists\n\t\ttry {\n\t\t\tconst schemaCheck = await sql<{ schema_name: string }>`\n\t\t\t\tSELECT schema_name \n\t\t\t\tFROM information_schema.schemata \n\t\t\t\tWHERE schema_name = ${currentSchema}\n\t\t\t`.execute(db);\n\n\t\t\tif (!schemaCheck.rows[0]) {\n\t\t\t\tlogger.warn(\n\t\t\t\t\t`Schema '${currentSchema}' does not exist. Tables will be inspected from available schemas. Consider creating the schema first or checking your database configuration.`,\n\t\t\t\t);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tlogger.debug(\n\t\t\t\t`Could not verify schema existence: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t);\n\t\t}\n\t}\n\n\tconst allTableMetadata = await db.introspection.getTables();\n\n\t// For PostgreSQL, filter tables to only those in the target schema\n\tlet tableMetadata = allTableMetadata;\n\tif (dbType === \"postgres\") {\n\t\t// Get tables with their schema information\n\t\ttry {\n\t\t\tconst tablesInSchema = await sql<{\n\t\t\t\ttable_name: string;\n\t\t\t}>`\n\t\t\t\tSELECT table_name \n\t\t\t\tFROM information_schema.tables \n\t\t\t\tWHERE table_schema = ${currentSchema}\n\t\t\t\tAND table_type = 'BASE TABLE'\n\t\t\t`.execute(db);\n\n\t\t\tconst tableNamesInSchema = new Set(\n\t\t\t\ttablesInSchema.rows.map((row) => row.table_name),\n\t\t\t);\n\n\t\t\t// Filter to only tables that exist in the target schema\n\t\t\ttableMetadata = allTableMetadata.filter(\n\t\t\t\t(table) =>\n\t\t\t\t\ttable.schema === currentSchema && tableNamesInSchema.has(table.name),\n\t\t\t);\n\n\t\t\tlogger.debug(\n\t\t\t\t`Found ${tableMetadata.length} table(s) in schema '${currentSchema}': ${tableMetadata.map((t) => t.name).join(\", \") || \"(none)\"}`,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tlogger.warn(\n\t\t\t\t`Could not filter tables by schema. Using all discovered tables. Error: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t);\n\t\t\t// Fall back to using all tables if schema filtering fails\n\t\t}\n\t}\n\tconst toBeCreated: {\n\t\ttable: string;\n\t\tfields: Record<string, DBFieldAttribute>;\n\t\torder: number;\n\t}[] = [];\n\tconst toBeAdded: {\n\t\ttable: string;\n\t\tfields: Record<string, DBFieldAttribute>;\n\t\torder: number;\n\t}[] = [];\n\n\tfor (const [key, value] of Object.entries(betterAuthSchema)) {\n\t\tconst table = tableMetadata.find((t) => t.name === key);\n\t\tif (!table) {\n\t\t\tconst tIndex = toBeCreated.findIndex((t) => t.table === key);\n\t\t\tconst tableData = {\n\t\t\t\ttable: key,\n\t\t\t\tfields: value.fields,\n\t\t\t\torder: value.order || Infinity,\n\t\t\t};\n\n\t\t\tconst insertIndex = toBeCreated.findIndex(\n\t\t\t\t(t) => (t.order || Infinity) > tableData.order,\n\t\t\t);\n\n\t\t\tif (insertIndex === -1) {\n\t\t\t\tif (tIndex === -1) {\n\t\t\t\t\ttoBeCreated.push(tableData);\n\t\t\t\t} else {\n\t\t\t\t\ttoBeCreated[tIndex]!.fields = {\n\t\t\t\t\t\t...toBeCreated[tIndex]!.fields,\n\t\t\t\t\t\t...value.fields,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ttoBeCreated.splice(insertIndex, 0, tableData);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tlet toBeAddedFields: Record<string, DBFieldAttribute> = {};\n\t\tfor (const [fieldName, field] of Object.entries(value.fields)) {\n\t\t\tconst column = table.columns.find((c) => c.name === fieldName);\n\t\t\tif (!column) {\n\t\t\t\ttoBeAddedFields[fieldName] = field;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (matchType(column.dataType, field.type, dbType)) {\n\t\t\t\tcontinue;\n\t\t\t} else {\n\t\t\t\tlogger.warn(\n\t\t\t\t\t`Field ${fieldName} in table ${key} has a different type in the database. Expected ${field.type} but got ${column.dataType}.`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tif (Object.keys(toBeAddedFields).length > 0) {\n\t\t\ttoBeAdded.push({\n\t\t\t\ttable: key,\n\t\t\t\tfields: toBeAddedFields,\n\t\t\t\torder: value.order || Infinity,\n\t\t\t});\n\t\t}\n\t}\n\n\tconst migrations: (\n\t\t| AlterTableColumnAlteringBuilder\n\t\t| ReturnType<AlterTableBuilder[\"addIndex\"]>\n\t\t| CreateTableBuilder<string, string>\n\t\t| CreateIndexBuilder\n\t)[] = [];\n\n\tconst useUUIDs = config.advanced?.database?.generateId === \"uuid\";\n\tconst useNumberId =\n\t\tconfig.advanced?.database?.useNumberId ||\n\t\tconfig.advanced?.database?.generateId === \"serial\";\n\n\tfunction getType(field: DBFieldAttribute, fieldName: string) {\n\t\tconst type = field.type;\n\t\tconst provider = dbType || \"sqlite\";\n\t\ttype StringOnlyUnion<T> = T extends string ? T : never;\n\t\tconst typeMap: Record<\n\t\t\tStringOnlyUnion<DBFieldType> | \"id\" | \"foreignKeyId\",\n\t\t\tRecord<KyselyDatabaseType, ColumnDataType | RawBuilder<unknown>>\n\t\t> = {\n\t\t\tstring: {\n\t\t\t\tsqlite: \"text\",\n\t\t\t\tpostgres: \"text\",\n\t\t\t\tmysql: field.unique\n\t\t\t\t\t? \"varchar(255)\"\n\t\t\t\t\t: field.references\n\t\t\t\t\t\t? \"varchar(36)\"\n\t\t\t\t\t\t: field.sortable\n\t\t\t\t\t\t\t? \"varchar(255)\"\n\t\t\t\t\t\t\t: field.index\n\t\t\t\t\t\t\t\t? \"varchar(255)\"\n\t\t\t\t\t\t\t\t: \"text\",\n\t\t\t\tmssql:\n\t\t\t\t\tfield.unique || field.sortable\n\t\t\t\t\t\t? \"varchar(255)\"\n\t\t\t\t\t\t: field.references\n\t\t\t\t\t\t\t? \"varchar(36)\"\n\t\t\t\t\t\t\t: // mssql deprecated `text`, and the alternative is `varchar(max)`.\n\t\t\t\t\t\t\t\t// Kysely type interface doesn't support `text`, so we set this to `varchar(8000)` as\n\t\t\t\t\t\t\t\t// that's the max length for `varchar`\n\t\t\t\t\t\t\t\t\"varchar(8000)\",\n\t\t\t},\n\t\t\tboolean: {\n\t\t\t\tsqlite: \"integer\",\n\t\t\t\tpostgres: \"boolean\",\n\t\t\t\tmysql: \"boolean\",\n\t\t\t\tmssql: \"smallint\",\n\t\t\t},\n\t\t\tnumber: {\n\t\t\t\tsqlite: field.bigint ? \"bigint\" : \"integer\",\n\t\t\t\tpostgres: field.bigint ? \"bigint\" : \"integer\",\n\t\t\t\tmysql: field.bigint ? \"bigint\" : \"integer\",\n\t\t\t\tmssql: field.bigint ? \"bigint\" : \"integer\",\n\t\t\t},\n\t\t\tdate: {\n\t\t\t\tsqlite: \"date\",\n\t\t\t\tpostgres: \"timestamptz\",\n\t\t\t\tmysql: \"timestamp(3)\",\n\t\t\t\tmssql: sql`datetime2(3)`,\n\t\t\t},\n\t\t\tjson: {\n\t\t\t\tsqlite: \"text\",\n\t\t\t\tpostgres: \"jsonb\",\n\t\t\t\tmysql: \"json\",\n\t\t\t\tmssql: \"varchar(8000)\",\n\t\t\t},\n\t\t\tid: {\n\t\t\t\tpostgres: useNumberId\n\t\t\t\t\t? sql`integer GENERATED BY DEFAULT AS IDENTITY`\n\t\t\t\t\t: useUUIDs\n\t\t\t\t\t\t? \"uuid\"\n\t\t\t\t\t\t: \"text\",\n\t\t\t\tmysql: useNumberId\n\t\t\t\t\t? \"integer\"\n\t\t\t\t\t: useUUIDs\n\t\t\t\t\t\t? \"varchar(36)\"\n\t\t\t\t\t\t: \"varchar(36)\",\n\t\t\t\tmssql: useNumberId\n\t\t\t\t\t? \"integer\"\n\t\t\t\t\t: useUUIDs\n\t\t\t\t\t\t? \"varchar(36)\"\n\t\t\t\t\t\t: \"varchar(36)\",\n\t\t\t\tsqlite: useNumberId ? \"integer\" : \"text\",\n\t\t\t},\n\t\t\tforeignKeyId: {\n\t\t\t\tpostgres: useNumberId ? \"integer\" : useUUIDs ? \"uuid\" : \"text\",\n\t\t\t\tmysql: useNumberId\n\t\t\t\t\t? \"integer\"\n\t\t\t\t\t: useUUIDs\n\t\t\t\t\t\t? \"varchar(36)\"\n\t\t\t\t\t\t: \"varchar(36)\",\n\t\t\t\tmssql: useNumberId\n\t\t\t\t\t? \"integer\"\n\t\t\t\t\t: useUUIDs\n\t\t\t\t\t\t? \"varchar(36)\" /* Should be using `UNIQUEIDENTIFIER` but Kysely doesn't support it */\n\t\t\t\t\t\t: \"varchar(36)\",\n\t\t\t\tsqlite: useNumberId ? \"integer\" : \"text\",\n\t\t\t},\n\t\t\t\"string[]\": {\n\t\t\t\tsqlite: \"text\",\n\t\t\t\tpostgres: \"jsonb\",\n\t\t\t\tmysql: \"json\",\n\t\t\t\tmssql: \"varchar(8000)\",\n\t\t\t},\n\t\t\t\"number[]\": {\n\t\t\t\tsqlite: \"text\",\n\t\t\t\tpostgres: \"jsonb\",\n\t\t\t\tmysql: \"json\",\n\t\t\t\tmssql: \"varchar(8000)\",\n\t\t\t},\n\t\t} as const;\n\t\tif (fieldName === \"id\" || field.references?.field === \"id\") {\n\t\t\tif (fieldName === \"id\") {\n\t\t\t\treturn typeMap.id[provider];\n\t\t\t}\n\t\t\treturn typeMap.foreignKeyId[provider];\n\t\t}\n\t\tif (Array.isArray(type)) {\n\t\t\treturn \"text\";\n\t\t}\n\t\tif (!(type in typeMap)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Unsupported field type '${String(type)}' for field '${fieldName}'. Allowed types are: string, number, boolean, date, string[], number[]. If you need to store structured data, store it as a JSON string (type: \"string\") or split it into primitive fields. See https://better-auth.com/docs/advanced/schema#additional-fields`,\n\t\t\t);\n\t\t}\n\t\treturn typeMap[type][provider];\n\t}\n\tconst getModelName = initGetModelName({\n\t\tschema: getAuthTables(config),\n\t\tusePlural: false,\n\t});\n\tconst getFieldName = initGetFieldName({\n\t\tschema: getAuthTables(config),\n\t\tusePlural: false,\n\t});\n\n\t// Helper function to safely resolve model and field names, falling back to\n\t// user-supplied strings for external tables not in the BetterAuth schema\n\tfunction getReferencePath(model: string, field: string): string {\n\t\ttry {\n\t\t\tconst modelName = getModelName(model);\n\t\t\tconst fieldName = getFieldName({ model, field });\n\t\t\treturn `${modelName}.${fieldName}`;\n\t\t} catch {\n\t\t\t// If resolution fails (external table), fall back to user-supplied references\n\t\t\treturn `${model}.${field}`;\n\t\t}\n\t}\n\n\tif (toBeAdded.length) {\n\t\tfor (const table of toBeAdded) {\n\t\t\tfor (const [fieldName, field] of Object.entries(table.fields)) {\n\t\t\t\tconst type = getType(field, fieldName);\n\t\t\t\tlet builder = db.schema.alterTable(table.table);\n\n\t\t\t\tif (field.index) {\n\t\t\t\t\tconst index = db.schema\n\t\t\t\t\t\t.alterTable(table.table)\n\t\t\t\t\t\t.addIndex(`${table.table}_${fieldName}_idx`);\n\t\t\t\t\tmigrations.push(index);\n\t\t\t\t}\n\n\t\t\t\tlet built = builder.addColumn(fieldName, type, (col) => {\n\t\t\t\t\tcol = field.required !== false ? col.notNull() : col;\n\t\t\t\t\tif (field.references) {\n\t\t\t\t\t\tcol = col\n\t\t\t\t\t\t\t.references(\n\t\t\t\t\t\t\t\tgetReferencePath(\n\t\t\t\t\t\t\t\t\tfield.references.model,\n\t\t\t\t\t\t\t\t\tfield.references.field,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.onDelete(field.references.onDelete || \"cascade\");\n\t\t\t\t\t}\n\t\t\t\t\tif (field.unique) {\n\t\t\t\t\t\tcol = col.unique();\n\t\t\t\t\t}\n\t\t\t\t\tif (\n\t\t\t\t\t\tfield.type === \"date\" &&\n\t\t\t\t\t\ttypeof field.defaultValue === \"function\" &&\n\t\t\t\t\t\t(dbType === \"postgres\" || dbType === \"mysql\" || dbType === \"mssql\")\n\t\t\t\t\t) {\n\t\t\t\t\t\tif (dbType === \"mysql\") {\n\t\t\t\t\t\t\tcol = col.defaultTo(sql`CURRENT_TIMESTAMP(3)`);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tcol = col.defaultTo(sql`CURRENT_TIMESTAMP`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn col;\n\t\t\t\t});\n\t\t\t\tmigrations.push(built);\n\t\t\t}\n\t\t}\n\t}\n\n\tlet toBeIndexed: CreateIndexBuilder[] = [];\n\n\tif (config.advanced?.database?.useNumberId) {\n\t\tlogger.warn(\n\t\t\t\"`useNumberId` is deprecated. Please use `generateId` with `serial` instead.\",\n\t\t);\n\t}\n\n\tif (toBeCreated.length) {\n\t\tfor (const table of toBeCreated) {\n\t\t\tconst idType = getType({ type: useNumberId ? \"number\" : \"string\" }, \"id\");\n\t\t\tlet dbT = db.schema\n\t\t\t\t.createTable(table.table)\n\t\t\t\t.addColumn(\"id\", idType, (col) => {\n\t\t\t\t\tif (useNumberId) {\n\t\t\t\t\t\tif (dbType === \"postgres\") {\n\t\t\t\t\t\t\t// Identity column is already specified in the type via sql template tag\n\t\t\t\t\t\t\treturn col.primaryKey().notNull();\n\t\t\t\t\t\t} else if (dbType === \"sqlite\") {\n\t\t\t\t\t\t\treturn col.primaryKey().notNull();\n\t\t\t\t\t\t} else if (dbType === \"mssql\") {\n\t\t\t\t\t\t\treturn col.identity().primaryKey().notNull();\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn col.autoIncrement().primaryKey().notNull();\n\t\t\t\t\t}\n\t\t\t\t\tif (useUUIDs) {\n\t\t\t\t\t\tif (dbType === \"postgres\") {\n\t\t\t\t\t\t\treturn col\n\t\t\t\t\t\t\t\t.primaryKey()\n\t\t\t\t\t\t\t\t.defaultTo(sql`pg_catalog.gen_random_uuid()`)\n\t\t\t\t\t\t\t\t.notNull();\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn col.primaryKey().notNull();\n\t\t\t\t\t}\n\t\t\t\t\treturn col.primaryKey().notNull();\n\t\t\t\t});\n\n\t\t\tfor (const [fieldName, field] of Object.entries(table.fields)) {\n\t\t\t\tconst type = getType(field, fieldName);\n\t\t\t\tdbT = dbT.addColumn(fieldName, type, (col) => {\n\t\t\t\t\tcol = field.required !== false ? col.notNull() : col;\n\t\t\t\t\tif (field.references) {\n\t\t\t\t\t\tcol = col\n\t\t\t\t\t\t\t.references(\n\t\t\t\t\t\t\t\tgetReferencePath(\n\t\t\t\t\t\t\t\t\tfield.references.model,\n\t\t\t\t\t\t\t\t\tfield.references.field,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.onDelete(field.references.onDelete || \"cascade\");\n\t\t\t\t\t}\n\n\t\t\t\t\tif (field.unique) {\n\t\t\t\t\t\tcol = col.unique();\n\t\t\t\t\t}\n\t\t\t\t\tif (\n\t\t\t\t\t\tfield.type === \"date\" &&\n\t\t\t\t\t\ttypeof field.defaultValue === \"function\" &&\n\t\t\t\t\t\t(dbType === \"postgres\" || dbType === \"mysql\" || dbType === \"mssql\")\n\t\t\t\t\t) {\n\t\t\t\t\t\tif (dbType === \"mysql\") {\n\t\t\t\t\t\t\tcol = col.defaultTo(sql`CURRENT_TIMESTAMP(3)`);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tcol = col.defaultTo(sql`CURRENT_TIMESTAMP`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn col;\n\t\t\t\t});\n\n\t\t\t\tif (field.index) {\n\t\t\t\t\tlet builder = db.schema\n\t\t\t\t\t\t.createIndex(\n\t\t\t\t\t\t\t`${table.table}_${fieldName}_${field.unique ? \"uidx\" : \"idx\"}`,\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.on(table.table)\n\t\t\t\t\t\t.columns([fieldName]);\n\t\t\t\t\ttoBeIndexed.push(field.unique ? builder.unique() : builder);\n\t\t\t\t}\n\t\t\t}\n\t\t\tmigrations.push(dbT);\n\t\t}\n\t}\n\n\t// instead of adding the index straight to `migrations`,\n\t// we do this at the end so that indexes are created after the table is created\n\tif (toBeIndexed.length) {\n\t\tfor (const index of toBeIndexed) {\n\t\t\tmigrations.push(index);\n\t\t}\n\t}\n\n\tasync function runMigrations() {\n\t\tfor (const migration of migrations) {\n\t\t\tawait migration.execute();\n\t\t}\n\t}\n\tasync function compileMigrations() {\n\t\tconst compiled = migrations.map((m) => m.compile().sql);\n\t\treturn compiled.join(\";\\n\\n\") + \";\";\n\t}\n\treturn { toBeCreated, toBeAdded, runMigrations, compileMigrations };\n}\n"],"mappings":"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"}