Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PG] Add Support For Domains and Check Constraints On Columns #4040

Open
wants to merge 26 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
2fd421f
Initial check-in for adding pg domain support
anthonyalayo Jan 28, 2025
71c7934
undo unrelated lint
anthonyalayo Jan 28, 2025
d5e26ef
continue developing domain support
anthonyalayo Jan 28, 2025
d57d187
Continued development
anthonyalayo Jan 28, 2025
8c9a01f
iterating on initial test code
anthonyalayo Jan 28, 2025
f86d609
adding support for PgSchema V7 and V8
anthonyalayo Jan 29, 2025
f999914
adding fix to pg serializer for v8
anthonyalayo Jan 29, 2025
961506e
fixing existing tests
anthonyalayo Jan 29, 2025
d29268e
adding proper serialization support for domains
anthonyalayo Jan 29, 2025
36de943
getting a new suite of tests passing
anthonyalayo Jan 30, 2025
782b3a0
linting
anthonyalayo Jan 30, 2025
2146303
using global snapshot version
anthonyalayo Jan 30, 2025
161cdce
cleaning up converters
anthonyalayo Jan 30, 2025
aca687b
log and logic clean up
anthonyalayo Jan 30, 2025
c65ca7e
cleaning up snapshots differ
anthonyalayo Jan 30, 2025
c4dde09
Update snapshotsDiffer.ts
anthonyalayo Jan 30, 2025
f0b7d9a
Merge branch 'main' into pg-domain-support
anthonyalayo Jan 30, 2025
4a3d29c
updating all code to use pre-existing check class
anthonyalayo Jan 31, 2025
270bfae
Update domain.ts
anthonyalayo Jan 31, 2025
9d513ff
adding support for check constraints on columns
anthonyalayo Jan 31, 2025
b1e026b
Add drizzle-kit test for using domain column in table
anthonyalayo Feb 1, 2025
6cc2f4d
adding more table tests and fixing bug
anthonyalayo Feb 1, 2025
a5322f5
more fixes for drizzle-zod generation
anthonyalayo Feb 1, 2025
5a167ee
fixing the constraint parser to handle more cases
anthonyalayo Feb 1, 2025
82aa92e
Update pg.test.ts
anthonyalayo Feb 2, 2025
702acb1
making names for check constraints optional
anthonyalayo Feb 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
node_modules
.vscode
.idea
dist
dist.new
*.tsbuildinfo
Expand All @@ -12,4 +13,4 @@ dist-dts
rollup.config-*.mjs
*.log
.DS_Store
drizzle-seed/src/dev
drizzle-seed/src/dev
4 changes: 4 additions & 0 deletions drizzle-kit/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { PgDatabase } from 'drizzle-orm/pg-core';
import { SingleStoreDriverDatabase } from 'drizzle-orm/singlestore';
import {
columnsResolver,
domainsResolver,
enumsResolver,
indPolicyResolver,
mySqlViewsResolver,
Expand Down Expand Up @@ -57,6 +58,7 @@ export const generateDrizzleJson = (

const snapshot = generatePgSnapshot(
prepared.tables,
prepared.domains,
prepared.enums,
prepared.schemas,
prepared.sequences,
Expand Down Expand Up @@ -91,6 +93,7 @@ export const generateMigration = async (
squashedPrev,
squashedCur,
schemasResolver,
domainsResolver,
enumsResolver,
sequencesResolver,
policyResolver,
Expand Down Expand Up @@ -144,6 +147,7 @@ export const pushSchema = async (
squashedPrev,
squashedCur,
schemasResolver,
domainsResolver,
enumsResolver,
sequencesResolver,
policyResolver,
Expand Down
4 changes: 3 additions & 1 deletion drizzle-kit/src/cli/commands/introspect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import type { SqliteCredentials } from '../validations/sqlite';
import { IntrospectProgress } from '../views';
import {
columnsResolver,
domainsResolver,
enumsResolver,
indPolicyResolver,
mySqlViewsResolver,
Expand Down Expand Up @@ -121,6 +122,7 @@ export const introspectPostgres = async (
squashPgScheme(dryPg),
squashPgScheme(schema),
schemasResolver,
domainsResolver,
enumsResolver,
sequencesResolver,
policyResolver,
Expand Down Expand Up @@ -485,7 +487,7 @@ export const introspectSqlite = async (
chalk.green(
'✓',
)
}] You relations file is ready ➜ ${
}] Your relations file is ready ➜ ${
chalk.bold.underline.blue(
relationsFile,
)
Expand Down
28 changes: 27 additions & 1 deletion drizzle-kit/src/cli/commands/migrate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
Column,
ColumnsResolverInput,
ColumnsResolverOutput,
Domain,
Enum,
PolicyResolverInput,
PolicyResolverOutput,
Expand Down Expand Up @@ -260,6 +261,28 @@ export const indPolicyResolver = async (
};
};

export const domainsResolver = async (
input: ResolverInput<Domain>,
): Promise<ResolverOutputWithMoved<Domain>> => {
try {
const { created, deleted, moved, renamed } = await promptNamedWithSchemasConflict(
input.created,
input.deleted,
'domain',
);

return {
created: created,
deleted: deleted,
moved: moved,
renamed: renamed,
};
} catch (e) {
console.error(e);
throw e;
}
};

export const enumsResolver = async (
input: ResolverInput<Enum>,
): Promise<ResolverOutputWithMoved<Enum>> => {
Expand Down Expand Up @@ -342,6 +365,7 @@ export const prepareAndMigratePg = async (config: GenerateConfig) => {
squashedPrev,
squashedCur,
schemasResolver,
domainsResolver,
enumsResolver,
sequencesResolver,
policyResolver,
Expand Down Expand Up @@ -388,6 +412,7 @@ export const prepareAndExportPg = async (config: ExportConfig) => {
squashedPrev,
squashedCur,
schemasResolver,
domainsResolver,
enumsResolver,
sequencesResolver,
policyResolver,
Expand Down Expand Up @@ -420,6 +445,7 @@ export const preparePgPush = async (
squashedPrev,
squashedCur,
schemasResolver,
domainsResolver,
enumsResolver,
sequencesResolver,
policyResolver,
Expand Down Expand Up @@ -1205,7 +1231,7 @@ export const promptNamedConflict = async <T extends Named>(
export const promptNamedWithSchemasConflict = async <T extends NamedWithSchema>(
newItems: T[],
missingItems: T[],
entity: 'table' | 'enum' | 'sequence' | 'view',
entity: 'table' | 'domain' | 'enum' | 'sequence' | 'view',
): Promise<{
created: T[];
renamed: { from: T; to: T }[];
Expand Down
42 changes: 40 additions & 2 deletions drizzle-kit/src/cli/commands/pgUp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
pgSchemaV5,
PgSchemaV6,
pgSchemaV6,
PgSchemaV7,
Table,
TableV5,
} from '../../serializer/pgSchema';
Expand Down Expand Up @@ -72,8 +73,7 @@ export const updateUpToV6 = (json: Record<string, any>): PgSchemaV6 => {
};
};

// Changed index format stored in snapshot for PostgreSQL in 0.22.0
export const updateUpToV7 = (json: Record<string, any>): PgSchema => {
export const updateUpToV7 = (json: Record<string, any>): PgSchemaV7 => {
const schema = pgSchemaV6.parse(json);
const tables = Object.fromEntries(
Object.entries(schema.tables).map((it) => {
Expand Down Expand Up @@ -109,6 +109,44 @@ export const updateUpToV7 = (json: Record<string, any>): PgSchema => {
};
};

// Changed index format stored in snapshot for PostgreSQL in 0.22.0
export const updateUpToV8 = (json: Record<string, any>): PgSchema => {
const schema = pgSchemaV6.parse(json);
const tables = Object.fromEntries(
Object.entries(schema.tables).map((it) => {
const table = it[1];
const mappedIndexes = Object.fromEntries(
Object.entries(table.indexes).map((idx) => {
const { columns, ...rest } = idx[1];
const mappedColumns = columns.map<Index['columns'][number]>((it) => {
return {
expression: it,
isExpression: false,
asc: true,
nulls: 'last',
opClass: undefined,
};
});
return [idx[0], { columns: mappedColumns, with: {}, ...rest }];
}),
);
return [it[0], { ...table, indexes: mappedIndexes, policies: {}, isRLSEnabled: false, checkConstraints: {} }];
}),
);

return {
...schema,
version: '8',
dialect: 'postgresql',
domains: {},
sequences: {},
tables: tables,
policies: {},
views: {},
roles: {},
};
};

// major migration with of folder structure, etc...
export const upPgHandlerV4toV5 = (obj: PgSchemaV4): PgSchemaV5 => {
const mappedTables: Record<string, TableV5> = {};
Expand Down
2 changes: 1 addition & 1 deletion drizzle-kit/src/cli/views.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ export class ResolveSelect<T extends NamedWithSchema> extends Prompt<
constructor(
private readonly base: T,
data: (RenamePropmtItem<T> | T)[],
private readonly entityType: 'table' | 'enum' | 'sequence' | 'view' | 'role',
private readonly entityType: 'table' | 'domain' | 'enum' | 'sequence' | 'view' | 'role',
) {
super();
this.on('attach', (terminal) => terminal.toggleCursor('hide'));
Expand Down
2 changes: 1 addition & 1 deletion drizzle-kit/src/global.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export const originUUID = '00000000-0000-0000-0000-000000000000';
export const snapshotVersion = '7';
export const snapshotVersion = '8';

export function assertUnreachable(x: never | undefined): never {
throw new Error("Didn't expect to get here");
Expand Down
12 changes: 12 additions & 0 deletions drizzle-kit/src/jsonDiffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ export function applyJsonDiff(json1, json2) {
const difference = JSON.parse(JSON.stringify(rawDiff || {}));
difference.schemas = difference.schemas || {};
difference.tables = difference.tables || {};
difference.domains = difference.domains || {};
difference.enums = difference.enums || {};
difference.sequences = difference.sequences || {};
difference.roles = difference.roles || {};
Expand Down Expand Up @@ -271,6 +272,16 @@ export function applyJsonDiff(json1, json2) {
}
}

const domainsEntries = Object.entries(difference.domains);
const alteredDomains = domainsEntries
.filter((it) => !(it[0].includes('__added') || it[0].includes('__deleted')))
.map((it) => {
const domainEntry = json1.domains[it[0]];
if (!domainEntry) return;
const { name, schema, baseType, notNull, defaultValue, checkConstraints } = domainEntry;
return { name, schema, baseType, notNull, defaultValue, checkConstraints };
}).filter(Boolean);

const enumsEntries = Object.entries(difference.enums);
const alteredEnums = enumsEntries
.filter((it) => !(it[0].includes('__added') || it[0].includes('__deleted')))
Expand Down Expand Up @@ -402,6 +413,7 @@ export function applyJsonDiff(json1, json2) {

return {
alteredTablesWithColumns,
alteredDomains,
alteredEnums,
alteredSequences,
alteredRoles,
Expand Down
85 changes: 83 additions & 2 deletions drizzle-kit/src/jsonStatements.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { warning } from './cli/views';
import { CommonSquashedSchema } from './schemaValidator';
import { MySqlKitInternals, MySqlSchema, MySqlSquasher, View as MySqlView } from './serializer/mysqlSchema';
import {
CheckConstraint,
Index,
MatViewWithOption,
PgSchema,
Expand All @@ -21,7 +22,7 @@ import {
SQLiteSquasher,
View as SqliteView,
} from './serializer/sqliteSchema';
import { AlteredColumn, Column, Sequence, Table } from './snapshotsDiffer';
import { AlteredColumn, Column, Domain, Sequence, Table } from './snapshotsDiffer';

export interface JsonSqliteCreateTableStatement {
type: 'sqlite_create_table';
Expand Down Expand Up @@ -96,6 +97,43 @@ export interface JsonRenameTableStatement {
tableNameTo: string;
}

// Types for Domain-related JSON statements
export type JsonDomainStatement =
| JsonCreateDomainStatement
| JsonDropDomainStatement
| JsonAlterDomainStatement;

export interface JsonCreateDomainStatement {
type: 'create_domain';
name: string;
schema: string;
notNull?: boolean;
defaultValue?: string;
baseType: string;
checkConstraints?: string[];
}

export interface JsonDropDomainStatement {
type: 'drop_domain';
name: string;
schema: string;
}

export interface JsonAlterDomainStatement {
type: 'alter_domain';
action:
| 'add_constraint'
| 'drop_constraint'
| 'set_not_null'
| 'drop_not_null'
| 'set_default'
| 'drop_default';
name: string;
schema: string;
defaultValue?: string;
checkConstraints?: string[];
}

export interface JsonCreateEnumStatement {
type: 'create_type_enum';
name: string;
Expand Down Expand Up @@ -866,7 +904,10 @@ export type JsonStatement =
| JsonIndRenamePolicyStatement
| JsonDropIndPolicyStatement
| JsonCreateIndPolicyStatement
| JsonAlterIndPolicyStatement;
| JsonAlterIndPolicyStatement
| JsonCreateDomainStatement
| JsonDropDomainStatement
| JsonAlterDomainStatement;

export const preparePgCreateTableJson = (
table: Table,
Expand Down Expand Up @@ -1006,6 +1047,46 @@ export const prepareRenameTableJson = (
};
};

// Helper function to create domain statements
export const prepareDomainJson = (
domain: Domain,
type: 'create' | 'alter' | 'drop',
action?: JsonAlterDomainStatement['action'],
): JsonDomainStatement => {
let checkConstraints;
if (domain.checkConstraints) {
checkConstraints = Object.values(domain.checkConstraints);
}

if (type === 'create') {
return {
type: 'create_domain',
name: domain.name,
schema: domain.schema,
notNull: domain.notNull,
defaultValue: domain.defaultValue,
baseType: domain.baseType,
checkConstraints,
};
} else if (type === 'drop') {
return {
type: 'drop_domain',
name: domain.name,
schema: domain.schema,
};
}

// For alter actions
return {
type: 'alter_domain',
action: action!,
name: domain.name,
schema: domain.schema,
defaultValue: domain.defaultValue,
checkConstraints,
};
};

export const prepareCreateEnumJson = (
name: string,
schema: string,
Expand Down
16 changes: 14 additions & 2 deletions drizzle-kit/src/serializer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,23 @@ export const serializePg = async (
const { prepareFromPgImports } = await import('./pgImports');
const { generatePgSnapshot } = await import('./pgSerializer');

const { tables, enums, schemas, sequences, views, matViews, roles, policies } = await prepareFromPgImports(
const { tables, domains, enums, schemas, sequences, views, matViews, roles, policies } = await prepareFromPgImports(
filenames,
);

return generatePgSnapshot(tables, enums, schemas, sequences, roles, policies, views, matViews, casing, schemaFilter);
return generatePgSnapshot(
tables,
domains,
enums,
schemas,
sequences,
roles,
policies,
views,
matViews,
casing,
schemaFilter,
);
};

export const serializeSQLite = async (
Expand Down
Loading