drizzle-kit 0.9.40 → 0.9.41
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.
- package/.eslintrc +21 -0
- package/LICENSE +674 -0
- package/package.json +17 -16
- package/pnpm-lock.yaml +2209 -0
- package/readme.rst +2 -0
- package/src/cli/commands/migrate.ts +79 -0
- package/src/cli/components-api/index.ts +287 -0
- package/src/cli/enq.ts +41 -0
- package/src/cli/index.ts +14 -0
- package/src/cli/machines/resolveColumnsMachine.ts +173 -0
- package/src/cli/machines/resolveTablesMachine.ts +167 -0
- package/src/cli/utils/formatDataForTable.ts +29 -0
- package/src/cli/utils/valuesForPrompts.ts +35 -0
- package/src/diff.ts +37 -0
- package/src/jsonDiffer.js +197 -115
- package/src/jsonStatements.ts +482 -0
- package/src/migrationPreparator.ts +44 -0
- package/src/serializer/factory.ts +415 -0
- package/src/serializer/index.ts +23 -0
- package/src/simulator.ts +155 -0
- package/src/snapshotsDiffer.ts +267 -0
- package/src/sqlgenerator.ts +323 -0
- package/src/tests/columnsMachine.test.ts +338 -0
- package/src/tests/tablesMachine.test.ts +339 -0
- package/tests/alters/index.test.ts +22 -0
- package/tests/alters/suite1/_patch.yaml +16 -0
- package/tests/alters/suite1/from.ts +16 -0
- package/tests/alters/suite1/to.ts +15 -0
- package/tsconfig.json +7 -0
- package/dev/data/column_rename/with_talbe_rename/new.js +0 -15
- package/dev/data/column_rename/with_talbe_rename/new.js.map +0 -1
- package/dev/data/column_rename/with_talbe_rename/prev.js +0 -15
- package/dev/data/column_rename/with_talbe_rename/prev.js.map +0 -1
- package/dev/data/column_rename/without_table_rename/v1/usersTable.js +0 -15
- package/dev/data/column_rename/without_table_rename/v1/usersTable.js.map +0 -1
- package/dev/data/column_rename/without_table_rename/v2/usersTable.js +0 -15
- package/dev/data/column_rename/without_table_rename/v2/usersTable.js.map +0 -1
- package/dev/data/jobs/from/from.js +0 -22
- package/dev/data/jobs/from/from.js.map +0 -1
- package/dev/data/jobs/to/to.js +0 -23
- package/dev/data/jobs/to/to.js.map +0 -1
- package/dev/data/leha/UsersTable.js +0 -36
- package/dev/data/leha/UsersTable.js.map +0 -1
- package/dev/data/leha/types.js +0 -13
- package/dev/data/leha/types.js.map +0 -1
- package/dev/data/v1/authOtpTable.js +0 -20
- package/dev/data/v1/authOtpTable.js.map +0 -1
- package/dev/data/v1/deletedTable.js +0 -14
- package/dev/data/v1/deletedTable.js.map +0 -1
- package/dev/data/v1/types.js +0 -9
- package/dev/data/v1/types.js.map +0 -1
- package/dev/data/v1/usersTable.js +0 -18
- package/dev/data/v1/usersTable.js.map +0 -1
- package/dev/data/v2/authOtpTable.js +0 -29
- package/dev/data/v2/authOtpTable.js.map +0 -1
- package/dev/data/v2/cityTable.js +0 -15
- package/dev/data/v2/cityTable.js.map +0 -1
- package/dev/data/v2/types.js +0 -13
- package/dev/data/v2/types.js.map +0 -1
- package/dev/data/v2/usersTable.js +0 -21
- package/dev/data/v2/usersTable.js.map +0 -1
- package/dev/data/v3/authOtpTable.js +0 -27
- package/dev/data/v3/authOtpTable.js.map +0 -1
- package/dev/data/v3/cityTable.js +0 -23
- package/dev/data/v3/cityTable.js.map +0 -1
- package/dev/data/v3/types.js +0 -13
- package/dev/data/v3/types.js.map +0 -1
- package/dev/data/v3/usersTable.js +0 -22
- package/dev/data/v3/usersTable.js.map +0 -1
- package/dev/data/v4/multi.js +0 -46
- package/dev/data/v4/multi.js.map +0 -1
- package/dev/diff.js +0 -28
- package/dev/diff.js.map +0 -1
- package/dev/factory.js +0 -78
- package/dev/factory.js.map +0 -1
- package/dev/fstest.js +0 -45
- package/dev/fstest.js.map +0 -1
- package/dev/index.js +0 -16
- package/dev/index.js.map +0 -1
- package/dev/prepare-snapshot.js +0 -19
- package/dev/prepare-snapshot.js.map +0 -1
- package/dev/quokka.js +0 -90
- package/dev/quokka.js.map +0 -1
- package/dev/serialiser.js +0 -30
- package/dev/serialiser.js.map +0 -1
- package/dev/simulate.js +0 -29
- package/dev/simulate.js.map +0 -1
- package/dev/test-build.js +0 -32
- package/dev/test-build.js.map +0 -1
- package/dev/testFactory.js +0 -42
- package/dev/testFactory.js.map +0 -1
- package/dev/testiko.js +0 -57
- package/dev/testiko.js.map +0 -1
- package/dev/yuup.js +0 -36
- package/dev/yuup.js.map +0 -1
- package/index.js +0 -168169
- package/index.js.map +0 -7
- package/jest.config.js +0 -7
- package/jest.config.js.map +0 -1
- package/src/cli/commands/migrate.js +0 -64
- package/src/cli/commands/migrate.js.map +0 -1
- package/src/cli/components-api/index.js +0 -205
- package/src/cli/components-api/index.js.map +0 -1
- package/src/cli/enq.js +0 -38
- package/src/cli/enq.js.map +0 -1
- package/src/cli/index.js +0 -15
- package/src/cli/index.js.map +0 -1
- package/src/cli/machines/resolveColumnsMachine.js +0 -116
- package/src/cli/machines/resolveColumnsMachine.js.map +0 -1
- package/src/cli/machines/resolveTablesMachine.js +0 -114
- package/src/cli/machines/resolveTablesMachine.js.map +0 -1
- package/src/cli/utils/formatDataForTable.js +0 -21
- package/src/cli/utils/formatDataForTable.js.map +0 -1
- package/src/cli/utils/valuesForPrompts.js +0 -38
- package/src/cli/utils/valuesForPrompts.js.map +0 -1
- package/src/diff.js +0 -28
- package/src/diff.js.map +0 -1
- package/src/jsonDiffer.js.map +0 -1
- package/src/jsonStatements.js +0 -197
- package/src/jsonStatements.js.map +0 -1
- package/src/migrationPreparator.js +0 -37
- package/src/migrationPreparator.js.map +0 -1
- package/src/serializer/factory.js +0 -113
- package/src/serializer/factory.js.map +0 -1
- package/src/serializer/index.js +0 -25
- package/src/serializer/index.js.map +0 -1
- package/src/simulator.js +0 -105
- package/src/simulator.js.map +0 -1
- package/src/snapshotsDiffer.js +0 -127
- package/src/snapshotsDiffer.js.map +0 -1
- package/src/sqlgenerator.js +0 -241
- package/src/sqlgenerator.js.map +0 -1
- package/src/tests/columnsMachine.test.js +0 -270
- package/src/tests/columnsMachine.test.js.map +0 -1
- package/src/tests/tablesMachine.test.js +0 -272
- package/src/tests/tablesMachine.test.js.map +0 -1
|
@@ -0,0 +1,267 @@
|
|
|
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
|
|
@@ -0,0 +1,323 @@
|
|
|
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
|
+
`
|