From dc3d78c43ab7b64fb8ce07650c17086d9f6896eb Mon Sep 17 00:00:00 2001 From: prodrigues Date: Wed, 13 Nov 2024 00:22:54 +0000 Subject: [PATCH] remain fix of non singlestore files and common files --- drizzle-kit/src/cli/commands/introspect.ts | 1 + drizzle-kit/src/cli/commands/migrate.ts | 13 +- drizzle-kit/src/cli/commands/push.ts | 28 ++-- drizzle-kit/src/cli/commands/utils.ts | 10 +- drizzle-kit/src/cli/schema.ts | 4 +- drizzle-kit/src/cli/validations/outputs.ts | 2 +- drizzle-kit/src/cli/views.ts | 11 +- drizzle-kit/src/jsonStatements.ts | 22 +-- drizzle-kit/src/snapshotsDiffer.ts | 60 ++++--- drizzle-kit/src/sqlgenerator.ts | 147 ++++++++---------- drizzle-kit/src/utils.ts | 1 - .../tests/introspect/singlestore.test.ts | 2 +- drizzle-kit/tests/push/singlestore.test.ts | 10 +- drizzle-kit/tests/push/sqlite.test.ts | 77 +++++++++ drizzle-kit/tests/schemaDiffer.ts | 2 +- .../src/singlestore-core/columns/timestamp.ts | 2 +- 16 files changed, 226 insertions(+), 166 deletions(-) diff --git a/drizzle-kit/src/cli/commands/introspect.ts b/drizzle-kit/src/cli/commands/introspect.ts index 149d2048b..7f13b99ff 100644 --- a/drizzle-kit/src/cli/commands/introspect.ts +++ b/drizzle-kit/src/cli/commands/introspect.ts @@ -223,6 +223,7 @@ export const introspectMysql = async ( const schema = { id: originUUID, prevId: '', ...res } as MySqlSchema; const ts = mysqlSchemaToTypeScript(schema, casing); const relationsTs = relationsToTypeScript(schema, casing); + const { internal, ...schemaWithoutInternals } = schema; const schemaFile = join(out, 'schema.ts'); writeFileSync(schemaFile, ts.file); diff --git a/drizzle-kit/src/cli/commands/migrate.ts b/drizzle-kit/src/cli/commands/migrate.ts index 21a7bb440..00c472e9e 100644 --- a/drizzle-kit/src/cli/commands/migrate.ts +++ b/drizzle-kit/src/cli/commands/migrate.ts @@ -374,18 +374,9 @@ export const prepareAndMigratePg = async (config: GenerateConfig) => { }; export const preparePgPush = async ( - schemaPath: string | string[], - snapshot: PgSchema, - schemaFilter: string[], - casing: CasingType | undefined, + cur: PgSchema, + prev: PgSchema, ) => { - const { prev, cur } = await preparePgDbPushSnapshot( - snapshot, - schemaPath, - casing, - schemaFilter, - ); - const validatedPrev = pgSchema.parse(prev); const validatedCur = pgSchema.parse(cur); diff --git a/drizzle-kit/src/cli/commands/push.ts b/drizzle-kit/src/cli/commands/push.ts index b147c2854..0c82fe026 100644 --- a/drizzle-kit/src/cli/commands/push.ts +++ b/drizzle-kit/src/cli/commands/push.ts @@ -1,5 +1,7 @@ import chalk from 'chalk'; +import { randomUUID } from 'crypto'; import { render } from 'hanji'; +import { serializePg } from 'src/serializer'; import { fromJson } from '../../sqlgenerator'; import { Select } from '../selector-ui'; import { Entities } from '../validations/cli'; @@ -320,20 +322,15 @@ export const pgPush = async ( const { pgPushIntrospect } = await import('./pgIntrospect'); const db = await preparePostgresDB(credentials); - const { schema } = await pgPushIntrospect( - db, - tablesFilter, - schemasFilter, - entities, - ); + const serialized = await serializePg(schemaPath, casing, schemasFilter); + + const { schema } = await pgPushIntrospect(db, tablesFilter, schemasFilter, entities, serialized); const { preparePgPush } = await import('./migrate'); const statements = await preparePgPush( - schemaPath, + { id: randomUUID(), prevId: schema.id, ...serialized }, schema, - schemasFilter, - casing, ); try { @@ -405,9 +402,7 @@ export const pgPush = async ( }${ matViewsToRemove.length > 0 ? ` remove ${matViewsToRemove.length} ${ - matViewsToRemove.length > 1 - ? 'materialized views' - : 'materialize view' + matViewsToRemove.length > 1 ? 'materialized views' : 'materialize view' },` : ' ' }` @@ -464,6 +459,7 @@ export const sqlitePush = async ( tablesToRemove, tablesToTruncate, infoToPrint, + schemasToRemove, } = await sqliteSuggestions( db, statements.statements, @@ -537,15 +533,15 @@ export const sqlitePush = async ( render(`\n[${chalk.blue('i')}] No changes detected`); } else { if (!('driver' in credentials)) { - await db.query('begin'); + await db.run('begin'); try { for (const dStmnt of statementsToExecute) { - await db.query(dStmnt); + await db.run(dStmnt); } - await db.query('commit'); + await db.run('commit'); } catch (e) { console.error(e); - await db.query('rollback'); + await db.run('rollback'); process.exit(1); } } diff --git a/drizzle-kit/src/cli/commands/utils.ts b/drizzle-kit/src/cli/commands/utils.ts index 35a7b5a77..88476c56e 100644 --- a/drizzle-kit/src/cli/commands/utils.ts +++ b/drizzle-kit/src/cli/commands/utils.ts @@ -42,7 +42,7 @@ import { sqliteCredentials, } from '../validations/sqlite'; import { studioCliParams, studioConfig } from '../validations/studio'; -import { error } from '../views'; +import { error, grey } from '../views'; // NextJs default config is target: es5, which esbuild-register can't consume const assertES5 = async (unregister: () => void) => { @@ -769,12 +769,8 @@ export const drizzleConfigFromFile = async ( ): Promise => { const prefix = process.env.TEST_CONFIG_PATH_PREFIX || ''; - const defaultTsConfigExists = existsSync( - resolve(join(prefix, 'drizzle.config.ts')), - ); - const defaultJsConfigExists = existsSync( - resolve(join(prefix, 'drizzle.config.js')), - ); + const defaultTsConfigExists = existsSync(resolve(join(prefix, 'drizzle.config.ts'))); + const defaultJsConfigExists = existsSync(resolve(join(prefix, 'drizzle.config.js'))); const defaultJsonConfigExists = existsSync( join(resolve('drizzle.config.json')), ); diff --git a/drizzle-kit/src/cli/schema.ts b/drizzle-kit/src/cli/schema.ts index e952a8627..12153ee74 100644 --- a/drizzle-kit/src/cli/schema.ts +++ b/drizzle-kit/src/cli/schema.ts @@ -44,9 +44,7 @@ const optionDriver = string() .enum(...drivers) .desc('Database driver'); -const optionCasing = string() - .enum('camelCase', 'snake_case') - .desc('Casing for serialization'); +const optionCasing = string().enum('camelCase', 'snake_case').desc('Casing for serialization'); export const generate = command({ name: 'generate', diff --git a/drizzle-kit/src/cli/validations/outputs.ts b/drizzle-kit/src/cli/validations/outputs.ts index ad0423b97..6e9d520dd 100644 --- a/drizzle-kit/src/cli/validations/outputs.ts +++ b/drizzle-kit/src/cli/validations/outputs.ts @@ -26,7 +26,7 @@ export const outputs = { ), noDialect: () => withStyle.error( - `Please specify 'dialect' param in config, either of 'pg', 'mysql', 'sqlite' or singlestore`, + `Please specify 'dialect' param in config, either of 'postgresql', 'mysql', 'sqlite', turso or singlestore`, ), }, common: { diff --git a/drizzle-kit/src/cli/views.ts b/drizzle-kit/src/cli/views.ts index e79d585ee..9106d31cd 100644 --- a/drizzle-kit/src/cli/views.ts +++ b/drizzle-kit/src/cli/views.ts @@ -32,11 +32,16 @@ export const schema = (schema: CommonSchema): string => { .map((t) => { const columnsCount = Object.values(t.columns).length; const indexesCount = Object.values(t.indexes).length; - // should we have fks? - // const foreignKeys = Object.values(t.foreignKeys).length; + let foreignKeys: number = 0; + // Singlestore doesn't have foreign keys + if (schema.dialect !== 'singlestore') { + // @ts-expect-error + foreignKeys = Object.values(t.foreignKeys).length; + } + return `${chalk.bold.blue(t.name)} ${ chalk.gray( - `${columnsCount} columns ${indexesCount} indexes`, + `${columnsCount} columns ${indexesCount} indexes ${foreignKeys} fks`, ) }`; }) diff --git a/drizzle-kit/src/jsonStatements.ts b/drizzle-kit/src/jsonStatements.ts index 81bbc2610..4fd9726d6 100644 --- a/drizzle-kit/src/jsonStatements.ts +++ b/drizzle-kit/src/jsonStatements.ts @@ -3116,9 +3116,7 @@ export const prepareAddCompositePrimaryKeyPg = ( tableName, data: it, schema, - constraintName: json2.tables[`${schema || 'public'}.${tableName}`].compositePrimaryKeys[ - unsquashed.name - ].name, + constraintName: PgSquasher.unsquashPK(it).name, } as JsonCreateCompositePK; }); }; @@ -3136,9 +3134,7 @@ export const prepareDeleteCompositePrimaryKeyPg = ( tableName, data: it, schema, - constraintName: json1.tables[`${schema || 'public'}.${tableName}`].compositePrimaryKeys[ - PgSquasher.unsquashPK(it).name - ].name, + constraintName: PgSquasher.unsquashPK(it).name, } as JsonDeleteCompositePK; }); }; @@ -3158,12 +3154,8 @@ export const prepareAlterCompositePrimaryKeyPg = ( old: it.__old, new: it.__new, schema, - oldConstraintName: json1.tables[`${schema || 'public'}.${tableName}`].compositePrimaryKeys[ - PgSquasher.unsquashPK(it.__old).name - ].name, - newConstraintName: json2.tables[`${schema || 'public'}.${tableName}`].compositePrimaryKeys[ - PgSquasher.unsquashPK(it.__new).name - ].name, + oldConstraintName: PgSquasher.unsquashPK(it.__old).name, + newConstraintName: PgSquasher.unsquashPK(it.__new).name, } as JsonAlterCompositePK; }); }; @@ -3276,7 +3268,7 @@ export const prepareAddCompositePrimaryKeyMySql = ( type: 'create_composite_pk', tableName, data: it, - constraintName: json2.tables[tableName].compositePrimaryKeys[unsquashed.name].name, + constraintName: unsquashed.name, } as JsonCreateCompositePK); } return res; @@ -3289,13 +3281,11 @@ export const prepareDeleteCompositePrimaryKeyMySql = ( json1: MySqlSchema, ): JsonDeleteCompositePK[] => { return Object.values(pks).map((it) => { + const unsquashed = MySqlSquasher.unsquashPK(it); return { type: 'delete_composite_pk', tableName, data: it, - constraintName: json1.tables[tableName].compositePrimaryKeys[ - MySqlSquasher.unsquashPK(it).name - ].name, } as JsonDeleteCompositePK; }); }; diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index 48520dc68..5e5d8fb19 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -1003,8 +1003,10 @@ export const applyPgSnapshotsDiff = async ( const { renamed, created, deleted } = await policyResolver({ tableName: entry.name, schema: entry.schema, - deleted: entry.policies.deleted.map(PgSquasher.unsquashPolicy), - created: entry.policies.added.map(PgSquasher.unsquashPolicy), + deleted: entry.policies.deleted.map( + action === 'push' ? PgSquasher.unsquashPolicyPush : PgSquasher.unsquashPolicy, + ), + created: entry.policies.added.map(action === 'push' ? PgSquasher.unsquashPolicyPush : PgSquasher.unsquashPolicy), }); if (created.length > 0) { @@ -1058,7 +1060,9 @@ export const applyPgSnapshotsDiff = async ( ] || []; const newName = columnChangeFor(policyKey, rens); - const unsquashedPolicy = PgSquasher.unsquashPolicy(policy); + const unsquashedPolicy = action === 'push' + ? PgSquasher.unsquashPolicyPush(policy) + : PgSquasher.unsquashPolicy(policy); unsquashedPolicy.name = newName; policy = PgSquasher.squashPolicy(unsquashedPolicy); return newName; @@ -1083,8 +1087,12 @@ export const applyPgSnapshotsDiff = async ( }[]; const { renamed: indPolicyRenames, created, deleted } = await indPolicyResolver({ - deleted: indPolicyRes.deleted.map((t) => PgSquasher.unsquashPolicy(t.values)), - created: indPolicyRes.added.map((t) => PgSquasher.unsquashPolicy(t.values)), + deleted: indPolicyRes.deleted.map((t) => + action === 'push' ? PgSquasher.unsquashPolicyPush(t.values) : PgSquasher.unsquashPolicy(t.values) + ), + created: indPolicyRes.added.map((t) => + action === 'push' ? PgSquasher.unsquashPolicyPush(t.values) : PgSquasher.unsquashPolicy(t.values) + ), }); if (created.length > 0) { @@ -1250,22 +1258,22 @@ export const applyPgSnapshotsDiff = async ( // This part is needed to make sure that same columns in a table are not triggered for change // there is a case where orm and kit are responsible for pk name generation and one of them is not sorting name // We double-check that pk with same set of columns are both in added and deleted diffs - let addedColumns: string[] = []; + let addedColumns: { name: string; columns: string[] } | undefined; for (const addedPkName of Object.keys(it.addedCompositePKs)) { const addedPkColumns = it.addedCompositePKs[addedPkName]; - addedColumns = SQLiteSquasher.unsquashPK(addedPkColumns); + addedColumns = PgSquasher.unsquashPK(addedPkColumns); } - let deletedColumns: string[] = []; + let deletedColumns: { name: string; columns: string[] } | undefined; for (const deletedPkName of Object.keys(it.deletedCompositePKs)) { const deletedPkColumns = it.deletedCompositePKs[deletedPkName]; - deletedColumns = SQLiteSquasher.unsquashPK(deletedPkColumns); + deletedColumns = PgSquasher.unsquashPK(deletedPkColumns); } // Don't need to sort, but need to add tests for it // addedColumns.sort(); // deletedColumns.sort(); - const doPerformDeleteAndCreate = JSON.stringify(addedColumns) !== JSON.stringify(deletedColumns); + const doPerformDeleteAndCreate = JSON.stringify(addedColumns ?? {}) !== JSON.stringify(deletedColumns ?? {}); let addedCompositePKs: JsonCreateCompositePK[] = []; let deletedCompositePKs: JsonDeleteCompositePK[] = []; @@ -1436,10 +1444,14 @@ export const applyPgSnapshotsDiff = async ( typedResult.alteredPolicies.forEach(({ values }) => { // return prepareAlterIndPolicyJson(json1.policies[it.name], json2.policies[it.name]); - const policy = PgSquasher.unsquashPolicy(values); + const policy = action === 'push' ? PgSquasher.unsquashPolicyPush(values) : PgSquasher.unsquashPolicy(values); - const newPolicy = PgSquasher.unsquashPolicy(json2.policies[policy.name].values); - const oldPolicy = PgSquasher.unsquashPolicy(json1.policies[policy.name].values); + const newPolicy = action === 'push' + ? PgSquasher.unsquashPolicyPush(json2.policies[policy.name].values) + : PgSquasher.unsquashPolicy(json2.policies[policy.name].values); + const oldPolicy = action === 'push' + ? PgSquasher.unsquashPolicyPush(json2.policies[policy.name].values) + : PgSquasher.unsquashPolicy(json1.policies[policy.name].values); if (newPolicy.as !== oldPolicy.as) { jsonDropIndPoliciesStatements.push( @@ -1509,8 +1521,12 @@ export const applyPgSnapshotsDiff = async ( alteredTables.forEach((it) => { // handle policies Object.keys(it.alteredPolicies).forEach((policyName: string) => { - const newPolicy = PgSquasher.unsquashPolicy(it.alteredPolicies[policyName].__new); - const oldPolicy = PgSquasher.unsquashPolicy(it.alteredPolicies[policyName].__old); + const newPolicy = action === 'push' + ? PgSquasher.unsquashPolicyPush(it.alteredPolicies[policyName].__new) + : PgSquasher.unsquashPolicy(it.alteredPolicies[policyName].__new); + const oldPolicy = action === 'push' + ? PgSquasher.unsquashPolicyPush(it.alteredPolicies[policyName].__old) + : PgSquasher.unsquashPolicy(it.alteredPolicies[policyName].__old); if (newPolicy.as !== oldPolicy.as) { jsonDropPoliciesStatements.push( @@ -1584,7 +1600,8 @@ export const applyPgSnapshotsDiff = async ( } // handle table.isRLSEnabled - if (table.isRLSEnabled !== tableInPreviousState.isRLSEnabled) { + const wasRlsEnabled = tableInPreviousState ? tableInPreviousState.isRLSEnabled : false; + if (table.isRLSEnabled !== wasRlsEnabled) { if (table.isRLSEnabled) { // was force enabled jsonEnableRLSStatements.push({ type: 'enable_rls', tableName: table.name, schema: table.schema }); @@ -1777,7 +1794,11 @@ export const applyPgSnapshotsDiff = async ( jsonCreatePoliciesStatements.push(...([] as JsonCreatePolicyStatement[]).concat( ...(createdTables.map((it) => - prepareCreatePolicyJsons(it.name, it.schema, Object.values(it.policies).map(PgSquasher.unsquashPolicy)) + prepareCreatePolicyJsons( + it.name, + it.schema, + Object.values(it.policies).map(action === 'push' ? PgSquasher.unsquashPolicyPush : PgSquasher.unsquashPolicy), + ) )), )); const createViews: JsonCreatePgViewStatement[] = []; @@ -2052,7 +2073,7 @@ export const applyPgSnapshotsDiff = async ( return true; }); - const sqlStatements = fromJson(filteredEnumsJsonStatements, 'postgresql'); + const sqlStatements = fromJson(filteredEnumsJsonStatements, 'postgresql', action); const uniqueSqlStatements: string[] = []; sqlStatements.forEach((ss) => { @@ -2628,12 +2649,11 @@ export const applyMysqlSnapshotsDiff = async ( jsonStatements.push(...jsonDeletedCompositePKs); jsonStatements.push(...jsonTableAlternations); jsonStatements.push(...jsonAddedCompositePKs); + jsonStatements.push(...jsonAddColumnsStatemets); jsonStatements.push(...jsonAddedUniqueConstraints); jsonStatements.push(...jsonDeletedUniqueConstraints); - jsonStatements.push(...jsonAddColumnsStatemets); - jsonStatements.push(...jsonCreateReferencesForCreatedTables); jsonStatements.push(...jsonCreateIndexesForCreatedTables); jsonStatements.push(...jsonCreatedCheckConstraints); diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index 81f04f10e..1dd72a338 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -88,74 +88,59 @@ import { PgSquasher, policy } from './serializer/pgSchema'; import { SingleStoreSquasher } from './serializer/singlestoreSchema'; import { SQLiteSchemaSquashed, SQLiteSquasher } from './serializer/sqliteSchema'; -export const pgNativeTypes = new Set([ - 'uuid', - 'smallint', - 'integer', - 'bigint', - 'boolean', - 'text', - 'varchar', - 'serial', - 'bigserial', - 'decimal', - 'numeric', - 'real', - 'json', - 'jsonb', - 'time', - 'time with time zone', - 'time without time zone', - 'time', - 'timestamp', - 'timestamp with time zone', - 'timestamp without time zone', - 'date', - 'interval', - 'bigint', - 'bigserial', - 'double precision', - 'interval year', - 'interval month', - 'interval day', - 'interval hour', - 'interval minute', - 'interval second', - 'interval year to month', - 'interval day to hour', - 'interval day to minute', - 'interval day to second', - 'interval hour to minute', - 'interval hour to second', - 'interval minute to second', -]); - -const isPgNativeType = (it: string) => { - if (pgNativeTypes.has(it)) return true; - const toCheck = it.replace(/ /g, ''); - return ( - toCheck.startsWith('varchar(') - || toCheck.startsWith('char(') - || toCheck.startsWith('numeric(') - || toCheck.startsWith('timestamp(') - || toCheck.startsWith('doubleprecision[') - || toCheck.startsWith('intervalyear(') - || toCheck.startsWith('intervalmonth(') - || toCheck.startsWith('intervalday(') - || toCheck.startsWith('intervalhour(') - || toCheck.startsWith('intervalminute(') - || toCheck.startsWith('intervalsecond(') - || toCheck.startsWith('intervalyeartomonth(') - || toCheck.startsWith('intervaldaytohour(') - || toCheck.startsWith('intervaldaytominute(') - || toCheck.startsWith('intervaldaytosecond(') - || toCheck.startsWith('intervalhourtominute(') - || toCheck.startsWith('intervalhourtosecond(') - || toCheck.startsWith('intervalminutetosecond(') - || toCheck.startsWith('vector(') - || toCheck.startsWith('geometry(') - || /^(\w+)(\[\d*])+$/.test(it) - ); +import { escapeSingleQuotes } from './utils'; + +const parseType = (schemaPrefix: string, type: string) => { + const pgNativeTypes = [ + 'uuid', + 'smallint', + 'integer', + 'bigint', + 'boolean', + 'text', + 'varchar', + 'serial', + 'bigserial', + 'decimal', + 'numeric', + 'real', + 'json', + 'jsonb', + 'time', + 'time with time zone', + 'time without time zone', + 'time', + 'timestamp', + 'timestamp with time zone', + 'timestamp without time zone', + 'date', + 'interval', + 'bigint', + 'bigserial', + 'double precision', + 'interval year', + 'interval month', + 'interval day', + 'interval hour', + 'interval minute', + 'interval second', + 'interval year to month', + 'interval day to hour', + 'interval day to minute', + 'interval day to second', + 'interval hour to minute', + 'interval hour to second', + 'interval minute to second', + 'char', + 'vector', + 'geometry', + ]; + const arrayDefinitionRegex = /\[\d*(?:\[\d*\])*\]/g; + const arrayDefinition = (type.match(arrayDefinitionRegex) ?? []).join(''); + const withoutArrayDefinition = type.replace(arrayDefinitionRegex, ''); + return pgNativeTypes.some((it) => type.startsWith(it)) + ? `${withoutArrayDefinition}${arrayDefinition}` + : `${schemaPrefix}"${withoutArrayDefinition}"${arrayDefinition}`; }; abstract class Convertor { @@ -271,9 +256,13 @@ class PgAlterPolicyConvertor extends Convertor { override can(statement: JsonStatement, dialect: Dialect): boolean { return statement.type === 'alter_policy' && dialect === 'postgresql'; } - override convert(statement: JsonAlterPolicyStatement): string | string[] { - const newPolicy = PgSquasher.unsquashPolicy(statement.newData); - const oldPolicy = PgSquasher.unsquashPolicy(statement.oldData); + override convert(statement: JsonAlterPolicyStatement, _dialect: any, action?: string): string | string[] { + const newPolicy = action === 'push' + ? PgSquasher.unsquashPolicyPush(statement.newData) + : PgSquasher.unsquashPolicy(statement.newData); + const oldPolicy = action === 'push' + ? PgSquasher.unsquashPolicyPush(statement.oldData) + : PgSquasher.unsquashPolicy(statement.oldData); const tableNameWithSchema = statement.schema ? `"${statement.schema}"."${statement.tableName}"` @@ -416,9 +405,7 @@ class PgCreateTableConvertor extends Convertor { ? `"${column.typeSchema}".` : ''; - const type = isPgNativeType(column.type) - ? column.type - : `${schemaPrefix}"${column.type}"`; + const type = parseType(schemaPrefix, column.type); const generated = column.generated; const generatedStatement = generated ? ` GENERATED ALWAYS AS (${generated?.as}) STORED` : ''; @@ -1391,7 +1378,7 @@ class CreateTypeEnumConvertor extends Convertor { const enumNameWithSchema = schema ? `"${schema}"."${name}"` : `"${name}"`; let valuesStatement = '('; - valuesStatement += values.map((it) => `'${it}'`).join(', '); + valuesStatement += values.map((it) => `'${escapeSingleQuotes(it)}'`).join(', '); valuesStatement += ')'; // TODO do we need this? @@ -1507,7 +1494,7 @@ class PgDropTableConvertor extends Convertor { return statement.type === 'drop_table' && dialect === 'postgresql'; } - convert(statement: JsonDropTableStatement) { + convert(statement: JsonDropTableStatement, _d: any, action?: string) { const { tableName, schema, policies } = statement; const tableNameWithSchema = schema @@ -1519,7 +1506,9 @@ class PgDropTableConvertor extends Convertor { return dropPolicyConvertor.convert({ type: 'drop_policy', tableName, - data: PgSquasher.unsquashPolicy(p), + data: action === 'push' + ? PgSquasher.unsquashPolicyPush(p) + : PgSquasher.unsquashPolicy(p), schema, }) as string; }) ?? []; @@ -1743,9 +1732,7 @@ class PgAlterTableAddColumnConvertor extends Convertor { ? `"${column.typeSchema}".` : ''; - const fixedType = isPgNativeType(column.type) - ? column.type - : `${schemaPrefix}"${column.type}"`; + const fixedType = parseType(schemaPrefix, column.type); const notNullStatement = `${notNull ? ' NOT NULL' : ''}`; diff --git a/drizzle-kit/src/utils.ts b/drizzle-kit/src/utils.ts index 559153c38..2638ca4ef 100644 --- a/drizzle-kit/src/utils.ts +++ b/drizzle-kit/src/utils.ts @@ -1,4 +1,3 @@ - import type { RunResult } from 'better-sqlite3'; import chalk from 'chalk'; import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'fs'; diff --git a/drizzle-kit/tests/introspect/singlestore.test.ts b/drizzle-kit/tests/introspect/singlestore.test.ts index ed1db094b..9a7e3af5a 100644 --- a/drizzle-kit/tests/introspect/singlestore.test.ts +++ b/drizzle-kit/tests/introspect/singlestore.test.ts @@ -14,7 +14,7 @@ import { smallint, text, tinyint, - varchar + varchar, } from 'drizzle-orm/singlestore-core'; import * as fs from 'fs'; import getPort from 'get-port'; diff --git a/drizzle-kit/tests/push/singlestore.test.ts b/drizzle-kit/tests/push/singlestore.test.ts index 13ef08cfa..82a901b16 100644 --- a/drizzle-kit/tests/push/singlestore.test.ts +++ b/drizzle-kit/tests/push/singlestore.test.ts @@ -1,4 +1,5 @@ import Docker from 'dockerode'; +import { sql } from 'drizzle-orm'; import { bigint, binary, @@ -27,7 +28,6 @@ import { diffTestSchemasPushSingleStore, diffTestSchemasSingleStore } from 'test import { v4 as uuid } from 'uuid'; import { expect } from 'vitest'; import { DialectSuite, run } from './common'; -import { sql } from 'drizzle-orm'; async function createDockerDB(context: any): Promise { const docker = new Docker(); @@ -206,10 +206,10 @@ const singlestoreSuite: DialectSuite = { }), allTimestamps: singlestoreTable('all_timestamps', { - columnDateNow: timestamp("column_date_now", { - fsp: 0, - mode: "string", - }).default(sql`CURRENT_TIMESTAMP`), + columnDateNow: timestamp('column_date_now', { + fsp: 0, + mode: 'string', + }).default(sql`CURRENT_TIMESTAMP`), columnAll: timestamp('column_all', { mode: 'string' }) .default('2023-03-01 14:05:29') .notNull(), diff --git a/drizzle-kit/tests/push/sqlite.test.ts b/drizzle-kit/tests/push/sqlite.test.ts index 5ac6f996c..dd1d88fe3 100644 --- a/drizzle-kit/tests/push/sqlite.test.ts +++ b/drizzle-kit/tests/push/sqlite.test.ts @@ -9,6 +9,7 @@ import { int, integer, numeric, + primaryKey, real, sqliteTable, sqliteView, @@ -1534,3 +1535,79 @@ test('alter view ".as"', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); }); + +test('create composite primary key', async (t) => { + const client = new Database(':memory:'); + + const schema1 = {}; + + const schema2 = { + table: sqliteTable('table', { + col1: integer('col1').notNull(), + col2: integer('col2').notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.col1, t.col2], + }), + })), + }; + + const { + statements, + sqlStatements, + } = await diffTestSchemasPushSqlite( + client, + schema1, + schema2, + [], + ); + + expect(statements).toStrictEqual([{ + type: 'sqlite_create_table', + tableName: 'table', + compositePKs: [['col1', 'col2']], + uniqueConstraints: [], + referenceData: [], + checkConstraints: [], + columns: [ + { name: 'col1', type: 'integer', primaryKey: false, notNull: true, autoincrement: false }, + { name: 'col2', type: 'integer', primaryKey: false, notNull: true, autoincrement: false }, + ], + }]); + expect(sqlStatements).toStrictEqual([ + 'CREATE TABLE `table` (\n\t`col1` integer NOT NULL,\n\t`col2` integer NOT NULL,\n\tPRIMARY KEY(`col1`, `col2`)\n);\n', + ]); +}); + +test('rename table with composite primary key', async () => { + const client = new Database(':memory:'); + + const productsCategoriesTable = (tableName: string) => { + return sqliteTable(tableName, { + productId: text('product_id').notNull(), + categoryId: text('category_id').notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.productId, t.categoryId], + }), + })); + }; + + const schema1 = { + table: productsCategoriesTable('products_categories'), + }; + const schema2 = { + test: productsCategoriesTable('products_to_categories'), + }; + + const { sqlStatements } = await diffTestSchemasPushSqlite( + client, + schema1, + schema2, + ['public.products_categories->public.products_to_categories'], + false, + ); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `products_categories` RENAME TO `products_to_categories`;', + ]); +}); diff --git a/drizzle-kit/tests/schemaDiffer.ts b/drizzle-kit/tests/schemaDiffer.ts index 62109c60a..a383ab717 100644 --- a/drizzle-kit/tests/schemaDiffer.ts +++ b/drizzle-kit/tests/schemaDiffer.ts @@ -59,7 +59,7 @@ import { generateSingleStoreSnapshot, } from 'src/serializer/singlestoreSerializer'; import { prepareFromSqliteImports } from 'src/serializer/sqliteImports'; -import { sqliteSchema, View as SqliteView, squashSqliteScheme } from 'src/serializer/sqliteSchema'; +import { sqliteSchema, squashSqliteScheme, View as SqliteView } from 'src/serializer/sqliteSchema'; import { fromDatabase as fromSqliteDatabase, generateSqliteSnapshot } from 'src/serializer/sqliteSerializer'; import { applyLibSQLSnapshotsDiff, diff --git a/drizzle-orm/src/singlestore-core/columns/timestamp.ts b/drizzle-orm/src/singlestore-core/columns/timestamp.ts index 3dbe1f9da..f269dad0f 100644 --- a/drizzle-orm/src/singlestore-core/columns/timestamp.ts +++ b/drizzle-orm/src/singlestore-core/columns/timestamp.ts @@ -2,9 +2,9 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { sql } from '~/sql/sql.ts'; import { type Equal, getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreDateBaseColumn, SingleStoreDateColumnBaseBuilder } from './date.common.ts'; -import { sql } from '~/sql/sql.ts'; export type SingleStoreTimestampBuilderInitial = SingleStoreTimestampBuilder<{ name: TName;