drizzle-kit 0.9.41 → 0.9.42

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,267 +0,0 @@
1
- import { fromJson } from "./sqlgenerator";
2
- import { applyJsonDiff, diffForRenamedTables, diffForRenamedColumn } from "./jsonDiffer";
3
- import { object, string, boolean, mixed } from 'yup';
4
-
5
- import {
6
- JsonReferenceStatement,
7
- JsonRenameColumnStatement,
8
- prepareAddValuesToEnumJson,
9
- prepareAlterReferencesJson,
10
- prepareAlterTableColumnsJson,
11
- prepareCreateEnumJson,
12
- prepareCreateIndexesJson,
13
- prepareCreateReferencesJson,
14
- prepareCreateTableJson,
15
- prepareDropIndexesJson,
16
- prepareDropTableJson,
17
- prepareRenameColumns,
18
- prepareRenameTableJson
19
- } from "./jsonStatements";
20
-
21
- export interface Column {
22
- name: string;
23
- type: string;
24
- primaryKey?: boolean;
25
- unique?: boolean;
26
- defaultValue?: string;
27
- notNull?: boolean;
28
- references?: string;
29
- }
30
-
31
- const columnSchema = object({
32
- name: string().required(),
33
- type: string().required(),
34
- primaryKey: boolean().optional(),
35
- unique: boolean().optional(),
36
- defaultValue: mixed().optional(),
37
- notNull: boolean().optional(),
38
- references: string().optional()
39
- }).noUnknown()
40
-
41
- export interface Added<T> {
42
- type: 'added';
43
- value: T;
44
- }
45
-
46
- export interface Deleted<T> {
47
- type: 'deleted';
48
- value: T;
49
- }
50
-
51
- export interface Changed<T> {
52
- type: 'changed';
53
- old: T;
54
- new: T;
55
- }
56
-
57
- export type PatchedProperty<T> = Added<T> | Deleted<T> | Changed<T>;
58
-
59
- export interface AlteredColumn {
60
- name: string | Changed<string>
61
- type?: Changed<string>
62
- defaultValue?: PatchedProperty<string>,
63
- notNull?: PatchedProperty<boolean>
64
- references?: PatchedProperty<string>
65
- }
66
-
67
- export interface ColumnsObject {
68
- [name: string]: Column;
69
- }
70
-
71
- interface Enum {
72
- name: string;
73
- values: string[];
74
- }
75
-
76
- export interface Index {
77
- name: string;
78
- columns: string[];
79
- isUnique: boolean;
80
- }
81
-
82
- export interface Table {
83
- name: string;
84
- columns: ColumnsObject,
85
- indexes: Index[]
86
- }
87
-
88
- export interface AlteredTable {
89
- name: string;
90
- deleted: Column[];
91
- added: Column[],
92
- altered: AlteredColumn[],
93
- addedIndexes: Index[],
94
- deletedIndexes: Index[],
95
- }
96
-
97
- export type DiffResult = {
98
- addedTables: Table[]
99
- deletedTables: Table[]
100
- alteredTablesWithColumns: AlteredTable[]
101
- addedEnums: Enum[]
102
- deletedEnums: Enum[]
103
- alteredEnums: any[]
104
- }
105
-
106
- export interface TablesResolverInput<T extends { name: string }> {
107
- created: T[],
108
- deleted: T[]
109
- }
110
- export interface TablesResolverOutput<T extends { name: string }> {
111
- created: T[],
112
- renamed: { from: T, to: T }[],
113
- deleted: T[]
114
- }
115
-
116
- export interface ColumnsResolverInput<T extends { name: string }> {
117
- tableName: string,
118
- created: T[],
119
- deleted: T[]
120
- }
121
-
122
- export interface ColumnsResolverOutput<T extends { name: string }> {
123
- tableName: string,
124
- created: T[],
125
- renamed: { from: T, to: T }[],
126
- deleted: T[]
127
- }
128
-
129
- export const applySnapshotsDiff = async (
130
- json1: Object,
131
- json2: Object,
132
- tablesResolver: (input: TablesResolverInput<Table>) => Promise<TablesResolverOutput<Table>>,
133
- columnsResolver: (input: ColumnsResolverInput<Column>) => Promise<ColumnsResolverOutput<Column>>
134
- ) => {
135
- const diffResult = applyJsonDiff(json1, json2)
136
- const typedResult: DiffResult = diffResult
137
-
138
- typedResult.addedTables.forEach(t => {
139
- Object.values(t.columns).forEach(column => {
140
- columnSchema.validateSync(column, { strict: true })
141
- })
142
- })
143
-
144
- typedResult.deletedTables.forEach(t => {
145
- Object.values(t.columns).forEach(column => {
146
- columnSchema.validateSync(column, { strict: true })
147
- })
148
- })
149
-
150
- typedResult.alteredTablesWithColumns.forEach(t => {
151
- t.added.forEach(column => {
152
- columnSchema.validateSync(column, { strict: true })
153
- })
154
- t.deleted.forEach(column => {
155
- columnSchema.validateSync(column, { strict: true })
156
- })
157
- })
158
-
159
-
160
- const { created, deleted, renamed } = await tablesResolver({ created: typedResult.addedTables, deleted: typedResult.deletedTables })
161
-
162
- const jsonStatements: any[] = []
163
- const jsonCreateTables = created.map(it => {
164
- return prepareCreateTableJson(it)
165
- })
166
-
167
- const jsonCreateIndexesForCreatedTables = created.map(it => {
168
- return prepareCreateIndexesJson(it.name, it.indexes)
169
- }).flat()
170
-
171
- const jsonDropTables = deleted.map(it => {
172
- return prepareDropTableJson(it)
173
- })
174
-
175
- const jsonRenameTables = renamed.map(it => {
176
- return prepareRenameTableJson(it.from, it.to)
177
- })
178
-
179
- const renamedWithAlternations: AlteredTable[] = diffForRenamedTables(renamed)
180
- const allAltered = typedResult.alteredTablesWithColumns.concat(renamedWithAlternations)
181
-
182
- const jsonRenameColumnsStatements: JsonRenameColumnStatement[] = []
183
-
184
- const allAlteredResolved: AlteredTable[] = []
185
- for (const table of allAltered) {
186
- const result = await columnsResolver({ tableName: table.name, created: table.added, deleted: table.deleted });
187
- // prepare oldTable and newTable
188
-
189
- jsonRenameColumnsStatements.push(...prepareRenameColumns(table.name, result.renamed))
190
-
191
- const renamedColumnsAltered: AlteredColumn[] = result.renamed.map(it => diffForRenamedColumn(it.from, it.to))
192
- const allAltered = table.altered.concat(renamedColumnsAltered)
193
-
194
- const resolved: AlteredTable = {
195
- name: table.name,
196
- deleted: result.deleted,
197
- added: result.created,
198
- altered: allAltered,
199
- addedIndexes: table.addedIndexes,
200
- deletedIndexes: table.deletedIndexes
201
- }
202
-
203
- allAlteredResolved.push(resolved)
204
- }
205
-
206
- const jsonAlterTables = allAlteredResolved.map(it => {
207
- return prepareAlterTableColumnsJson(it.name, it.deleted, it.added, it.altered)
208
- }).flat()
209
-
210
- const jsonCreateIndexesForAllAlteredTables = allAltered.map(it => {
211
- return prepareCreateIndexesJson(it.name, it.addedIndexes || {})
212
- }).flat()
213
-
214
- const jsonDropIndexesForAllAlteredTables = allAltered.map(it => {
215
- return prepareDropIndexesJson(it.name, it.deletedIndexes || {})
216
- }).flat()
217
-
218
- const jsonReferencesForCreatedTables: JsonReferenceStatement[] = created.map(it => {
219
- return prepareCreateReferencesJson(it.name, Object.values(it.columns))
220
- }).flat()
221
-
222
- const jsonReferencesForAllAlteredTables: JsonReferenceStatement[] = allAltered.map(it => {
223
- const forAdded = prepareCreateReferencesJson(it.name, it.added)
224
- const forAltered = prepareAlterReferencesJson(it.name, it.altered)
225
- return [...forAdded, ...forAltered]
226
- }).flat()
227
-
228
- const jsonCreateReferences: JsonReferenceStatement[] = jsonReferencesForCreatedTables.concat(jsonReferencesForAllAlteredTables)
229
-
230
- // // Enums:
231
- // // - создание енама ✅
232
- // // - переименование енама (пока не делаю)⏳
233
- // // - добавление вэлью к енаму ✅
234
- // // - ренейм вейлью у енама (пока не делаю, это надо запрашивать опять же через слай)⏳
235
- // // - удаление енама -> чекать не используется ли где-то енам и сначала ранить миграции и в самом конце удаление енама⏳
236
- // // - удаление вэлью из енама -> блок ❌
237
- // const enums = result.addedEnums.map(it => {
238
- // return prepareCreateEnum(it.name, it.values)
239
- // })
240
-
241
- const createEnums = diffResult.addedEnums.map(it => {
242
- return prepareCreateEnumJson(it.name, it.values)
243
- })
244
-
245
- //todo: block enum rename, enum value rename and enun deletion for now
246
- const jsonAlterEnumsWithAddedValues = diffResult.alteredEnums.map(it => {
247
- return prepareAddValuesToEnumJson(it.name, it.addedValues)
248
- }).flat()
249
-
250
- jsonStatements.push(...createEnums)
251
- jsonStatements.push(...jsonAlterEnumsWithAddedValues)
252
- jsonStatements.push(...jsonCreateTables)
253
- jsonStatements.push(...jsonDropTables)
254
- jsonStatements.push(...jsonRenameTables)
255
- jsonStatements.push(...jsonRenameColumnsStatements)
256
- jsonStatements.push(...jsonAlterTables)
257
- jsonStatements.push(...jsonCreateReferences)
258
- jsonStatements.push(...jsonCreateIndexesForCreatedTables)
259
- jsonStatements.push(...jsonCreateIndexesForAllAlteredTables)
260
- jsonStatements.push(...jsonDropIndexesForAllAlteredTables)
261
-
262
- const sqlStatements = fromJson(jsonStatements)
263
- return sqlStatements.join('\n')
264
- }
265
-
266
- // explicitely ask if tables were renamed, if yes - add those to altered tables, otherwise - deleted
267
- // double check if user wants to delete particular table and warn him on data loss
@@ -1,323 +0,0 @@
1
- import { JsonAddColumnStatement, JsonAddValueToEnumStatement, JsonAlterColumnDropDefaultStatement, JsonAlterColumnDropNotNullStatement, JsonAlterColumnSetDefaultStatement, JsonAlterColumnSetNotNullStatement, JsonAlterColumnTypeStatement, JsonAlterReferenceStatement, JsonCreateEnumStatement, JsonCreateIndexStatement, JsonCreateReferenceStatement, JsonCreateTableStatement, JsonDeleteReferenceStatement, JsonDropColumnStatement, JsonDropIndexStatement, JsonDropTableStatement, JsonRenameColumnStatement, JsonRenameTableStatement, JsonStatement } from "./jsonStatements";
2
-
3
- abstract class Convertor {
4
- abstract can(statement: JsonStatement): boolean
5
- abstract convert(statement: JsonStatement): string
6
- }
7
-
8
- class CreateTableConvertor extends Convertor {
9
- can(statement: JsonStatement): boolean {
10
- return statement.type === 'create_table'
11
- }
12
-
13
- convert(st: JsonCreateTableStatement) {
14
- const { tableName, columns } = st
15
-
16
- let statement = ''
17
-
18
- statement += `CREATE TABLE IF NOT EXISTS ${tableName} (\n`
19
- for (let i = 0; i < columns.length; i++) {
20
- const column = columns[i]
21
-
22
- const primaryKeyStatement = column.primaryKey ? "PRIMARY KEY" : ''
23
- const notNullStatement = column.notNull ? "NOT NULL" : "";
24
- const defaultStatement = column.defaultValue !== undefined ? `DEFAULT ${column.defaultValue}` : "";
25
-
26
- statement += '\t' + `"${column.name}" ${column.type} ${primaryKeyStatement} ${defaultStatement} ${notNullStatement}`.replace(/ +/g, ' ').trim();
27
- statement += (i === columns.length - 1 ? '' : ',') + '\n'
28
- }
29
- statement += `);`
30
- statement += `\n`
31
- return statement;
32
- }
33
- }
34
-
35
- class CreateTypeEnumConvertor extends Convertor {
36
- can(statement: JsonStatement): boolean {
37
- return statement.type === 'create_type_enum'
38
- }
39
-
40
-
41
- convert(st: JsonCreateEnumStatement) {
42
- const { name, values } = st
43
- let valuesStatement = '('
44
- valuesStatement += values.map(it => `'${it}'`).join(', ')
45
- valuesStatement += ')'
46
-
47
- let statement = "DO $$ BEGIN"
48
- statement += "\n"
49
- statement += ` CREATE TYPE ${name} AS ENUM${valuesStatement};`
50
- statement += "\n"
51
- statement += "EXCEPTION"
52
- statement += "\n"
53
- statement += " WHEN duplicate_object THEN null;"
54
- statement += "\n"
55
- statement += "END $$;"
56
- statement += '\n'
57
- return statement
58
- }
59
- }
60
-
61
- class AlterTypeAddValueConvertor extends Convertor {
62
- can(statement: JsonStatement): boolean {
63
- return statement.type === 'alter_type_add_value'
64
- }
65
-
66
- convert(st: JsonAddValueToEnumStatement) {
67
- const { name, value } = st
68
- return `ALTER TYPE ${name} ADD VALUE '${value}';`
69
- }
70
- }
71
-
72
- class DropTableConvertor extends Convertor {
73
- can(statement: JsonStatement): boolean {
74
- return statement.type === 'drop_table'
75
- }
76
-
77
- convert(statement: JsonDropTableStatement) {
78
- const { tableName } = statement
79
- return `DROP TABLE ${tableName};`
80
- }
81
- }
82
-
83
- class RenameTableConvertor extends Convertor {
84
- can(statement: JsonStatement): boolean {
85
- return statement.type === 'rename_table'
86
- }
87
-
88
- convert(statement: JsonRenameTableStatement) {
89
- const { tableNameFrom, tableNameTo } = statement
90
- return `ALTER TABLE ${tableNameFrom} RENAME TO ${tableNameTo};`
91
- }
92
- }
93
-
94
- class AlterTableRenameColumnConvertor extends Convertor {
95
- can(statement: JsonStatement): boolean {
96
- return statement.type === 'alter_table_rename_column'
97
- }
98
-
99
- convert(statement: JsonRenameColumnStatement) {
100
- const { tableName, oldColumnName, newColumnName } = statement
101
- return `ALTER TABLE ${tableName} RENAME COLUMN "${oldColumnName}" TO "${newColumnName}";`
102
- }
103
- }
104
-
105
- class AlterTableDropColumnConvertor extends Convertor {
106
- can(statement: JsonStatement): boolean {
107
- return statement.type === 'alter_table_drop_column'
108
- }
109
-
110
- convert(statement: JsonDropColumnStatement) {
111
- const { tableName, columnName } = statement
112
- return `ALTER TABLE ${tableName} DROP COLUMN IF EXISTS "${columnName}";`
113
- }
114
- }
115
-
116
- class AlterTableAddColumnConvertor extends Convertor {
117
- can(statement: JsonStatement): boolean {
118
- return statement.type === 'alter_table_add_column'
119
- }
120
-
121
- convert(statement: JsonAddColumnStatement) {
122
- const { tableName, column } = statement
123
- const { name, type, notNull } = column;
124
- const defaultValue = column.defaultValue
125
-
126
- const defaultStatement = `${defaultValue !== undefined ? `DEFAULT ${defaultValue}` : ''}`
127
- const notNullStatement = `${notNull ? 'NOT NULL' : ''}`
128
- return `ALTER TABLE ${tableName} ADD COLUMN "${name}" ${type} ${defaultStatement} ${notNullStatement}`.replace(/ +/g, ' ').trim() + ';'
129
- }
130
- }
131
-
132
- class AlterTableAlterColumnSetTypeConvertor extends Convertor {
133
- can(statement: JsonStatement): boolean {
134
- return statement.type === 'alter_table_alter_column_set_type'
135
- }
136
-
137
- convert(statement: JsonAlterColumnTypeStatement) {
138
- const { tableName, columnName, newDataType } = statement
139
- return `ALTER TABLE ${tableName} ALTER COLUMN "${columnName}" SET DATA TYPE ${newDataType};`
140
- }
141
- }
142
-
143
- class AlterTableAlterColumnSetDefaultConvertor extends Convertor {
144
- can(statement: JsonStatement): boolean {
145
- return statement.type === 'alter_table_alter_column_set_default'
146
- }
147
-
148
- convert(statement: JsonAlterColumnSetDefaultStatement) {
149
- const { tableName, columnName } = statement
150
- return `ALTER TABLE ${tableName} ALTER COLUMN "${columnName}" SET DEFAULT ${statement.newDefaultValue};`
151
- }
152
- }
153
-
154
- class AlterTableAlterColumnDropDefaultConvertor extends Convertor {
155
- can(statement: JsonStatement): boolean {
156
- return statement.type === 'alter_table_alter_column_drop_default'
157
- }
158
-
159
- convert(statement: JsonAlterColumnDropDefaultStatement) {
160
- const { tableName, columnName } = statement
161
- return `ALTER TABLE ${tableName} ALTER COLUMN "${columnName}" DROP DEFAULT;`
162
- }
163
- }
164
-
165
- class AlterTableAlterColumnSetNotNullConvertor extends Convertor {
166
- can(statement: JsonStatement): boolean {
167
- return statement.type === 'alter_table_alter_column_set_notnull'
168
- }
169
-
170
- convert(statement: JsonAlterColumnSetNotNullStatement) {
171
- const { tableName, columnName } = statement
172
- return `ALTER TABLE ${tableName} ALTER COLUMN "${columnName}" SET NOT NULL;`
173
- }
174
- }
175
-
176
- class AlterTableAlterColumnDropNotNullConvertor extends Convertor {
177
- can(statement: JsonStatement): boolean {
178
- return statement.type === 'alter_table_alter_column_drop_notnull'
179
- }
180
-
181
- convert(statement: JsonAlterColumnDropNotNullStatement) {
182
- const { tableName, columnName } = statement
183
- return `ALTER TABLE ${tableName} ALTER COLUMN "${columnName}" DROP NOT NULL;`
184
- }
185
- }
186
-
187
- class CreateForeignKeyConvertor extends Convertor {
188
- can(statement: JsonStatement): boolean {
189
- return statement.type === 'create_reference'
190
- }
191
-
192
- convert(statement: JsonCreateReferenceStatement) {
193
- const { fromTable, toTable, fromColumn, toColumn, foreignKeyName, onDelete, onUpdate } = statement
194
- const onDeleteStatement = onDelete || ""
195
- const onUpdateStatement = onUpdate || ""
196
- const alterStatement = `ALTER TABLE ${fromTable} ADD CONSTRAINT ${foreignKeyName} FOREIGN KEY ("${fromColumn}") REFERENCES ${toTable}(${toColumn}) ${onDeleteStatement} ${onUpdateStatement}`.replace(/ +/g, ' ').trim();
197
-
198
- let sql = "DO $$ BEGIN\n"
199
- sql += ' ' + alterStatement + ';\n'
200
- sql += "EXCEPTION\n"
201
- sql += " WHEN duplicate_object THEN null;\n"
202
- sql += "END $$;\n"
203
- return sql
204
- }
205
- }
206
-
207
- class AlterForeignKeyConvertor extends Convertor {
208
- can(statement: JsonStatement): boolean {
209
- return statement.type === 'alter_reference'
210
- }
211
-
212
- convert(statement: JsonAlterReferenceStatement) {
213
- const { fromTable, toTable, fromColumn, toColumn, foreignKeyName, onDelete, onUpdate, oldFkey } = statement
214
- const onDeleteStatement = onDelete || ""
215
- const onUpdateStatement = onUpdate || ""
216
- const alterStatement = `ALTER TABLE ${fromTable} ADD CONSTRAINT ${foreignKeyName} FOREIGN KEY ("${fromColumn}") REFERENCES ${toTable}(${toColumn}) ${onDeleteStatement} ${onUpdateStatement}`.replace(/ +/g, ' ').trim();
217
- let sql = `ALTER TABLE ${fromTable} DROP CONSTRAINT ${oldFkey};\n`
218
- sql += "DO $$ BEGIN\n"
219
- sql += ' ' + alterStatement + ';\n'
220
- sql += "EXCEPTION\n"
221
- sql += " WHEN duplicate_object THEN null;\n"
222
- sql += "END $$;\n"
223
- return sql
224
- }
225
- }
226
-
227
- class DeleteForeignKeyConvertor extends Convertor {
228
- can(statement: JsonStatement): boolean {
229
- return statement.type === 'delete_reference'
230
- }
231
-
232
- convert(statement: JsonDeleteReferenceStatement) {
233
- const { fromTable, foreignKeyName } = statement
234
- return `ALTER TABLE ${fromTable} DROP CONSTRAINT ${foreignKeyName};\n`
235
- }
236
- }
237
-
238
- class CreateIndexConvertor extends Convertor {
239
- can(statement: JsonStatement): boolean {
240
- return statement.type === 'create_index'
241
- }
242
-
243
- convert(statement: JsonCreateIndexStatement) {
244
- const { tableName, indexName, value } = statement
245
- // since postgresql 9.5
246
- const indexPart = statement.isUnique ? 'UNIQUE INDEX' : 'INDEX'
247
- return `CREATE ${indexPart} IF NOT EXISTS ${indexName} ON ${tableName} (${value});`
248
- }
249
- }
250
-
251
- class DropIndexConvertor extends Convertor {
252
- can(statement: JsonStatement): boolean {
253
- return statement.type === 'drop_index'
254
- }
255
-
256
- convert(statement: JsonDropIndexStatement) {
257
- const { indexName } = statement
258
- return `DROP INDEX IF EXISTS ${indexName};`
259
- }
260
- }
261
-
262
- const convertors: Convertor[] = []
263
- convertors.push(new CreateTableConvertor())
264
- convertors.push(new CreateTypeEnumConvertor())
265
- convertors.push(new DropTableConvertor())
266
- convertors.push(new RenameTableConvertor())
267
- convertors.push(new AlterTableRenameColumnConvertor())
268
- convertors.push(new AlterTableDropColumnConvertor())
269
- convertors.push(new AlterTableAddColumnConvertor())
270
- convertors.push(new AlterTableAlterColumnSetTypeConvertor())
271
- convertors.push(new CreateIndexConvertor())
272
- convertors.push(new DropIndexConvertor())
273
- convertors.push(new AlterTypeAddValueConvertor())
274
- convertors.push(new AlterTableAlterColumnSetNotNullConvertor())
275
- convertors.push(new AlterTableAlterColumnDropNotNullConvertor())
276
- convertors.push(new AlterTableAlterColumnSetDefaultConvertor())
277
- convertors.push(new AlterTableAlterColumnDropDefaultConvertor())
278
- convertors.push(new CreateForeignKeyConvertor())
279
- convertors.push(new AlterForeignKeyConvertor())
280
- convertors.push(new DeleteForeignKeyConvertor())
281
-
282
- export const fromJson = (statements: JsonStatement[]) => {
283
- const result = statements.map(statement => {
284
- const filtered = convertors.filter(it => {
285
- return it.can(statement)
286
- })
287
- const convertor = filtered.length === 1 ? filtered[0] : undefined
288
-
289
- if (!convertor) {
290
- console.log('no convertor:', statement.type)
291
- return 'dry run'
292
- }
293
-
294
- return convertor.convert(statement)
295
- })
296
- return result;
297
- }
298
-
299
- https://blog.yo1.dog/updating-enum-values-in-postgresql-the-safe-and-easy-way/
300
- // test case for enum altering
301
- `
302
- create table users (
303
- id int,
304
- name character varying(128)
305
- );
306
-
307
- create type venum as enum('one', 'two', 'three');
308
- alter table users add column typed venum;
309
-
310
- insert into users(id, name, typed) values (1, 'name1', 'one');
311
- insert into users(id, name, typed) values (2, 'name2', 'two');
312
- insert into users(id, name, typed) values (3, 'name3', 'three');
313
-
314
- alter type venum rename to __venum;
315
- create type venum as enum ('one', 'two', 'three', 'four', 'five');
316
-
317
- ALTER TABLE users ALTER COLUMN typed TYPE venum USING typed::text::venum;
318
-
319
- insert into users(id, name, typed) values (4, 'name4', 'four');
320
- insert into users(id, name, typed) values (5, 'name5', 'five');
321
-
322
- drop type __venum;
323
- `