drizzle-orm 0.9.16 → 0.9.17
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/package.json +1 -1
- package/serializer/serializer.d.ts +12 -0
- package/serializer/serializer.js +167 -0
package/package.json
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
|
+
import { DB } from '../db';
|
|
1
2
|
import { AbstractTable } from '../tables';
|
|
2
3
|
import Enum from '../types/type';
|
|
4
|
+
interface EnumsAsObject {
|
|
5
|
+
[name: string]: {
|
|
6
|
+
name: string;
|
|
7
|
+
values: string[];
|
|
8
|
+
};
|
|
9
|
+
}
|
|
3
10
|
interface ColumnAsObject {
|
|
4
11
|
[name: string]: {
|
|
5
12
|
name?: string;
|
|
@@ -37,5 +44,10 @@ export default class MigrationSerializer {
|
|
|
37
44
|
[key: string]: Enum<any>;
|
|
38
45
|
};
|
|
39
46
|
};
|
|
47
|
+
fromDatabase: (db: DB) => Promise<{
|
|
48
|
+
version: string;
|
|
49
|
+
tables: TableAsObject;
|
|
50
|
+
enums: EnumsAsObject;
|
|
51
|
+
}>;
|
|
40
52
|
}
|
|
41
53
|
export {};
|
package/serializer/serializer.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
/* eslint-disable max-classes-per-file */
|
|
2
3
|
/* eslint-disable import/no-named-as-default-member */
|
|
3
4
|
/* eslint-disable import/no-named-as-default */
|
|
4
5
|
/* eslint-disable no-param-reassign */
|
|
@@ -69,6 +70,172 @@ class MigrationSerializer {
|
|
|
69
70
|
}, {});
|
|
70
71
|
return { version: '1', tables: result, enums: enumsToReturn };
|
|
71
72
|
};
|
|
73
|
+
this.fromDatabase = async (db) => {
|
|
74
|
+
var _a;
|
|
75
|
+
const result = {};
|
|
76
|
+
const allTables = await db.session().execute('SELECT table_schema, table_name FROM information_schema.tables WHERE table_schema != \'pg_catalog\' and table_schema != \'information_schema\';');
|
|
77
|
+
for await (const row of allTables.rows) {
|
|
78
|
+
try {
|
|
79
|
+
// const tableSchema = row.table_schema;
|
|
80
|
+
const tableName = row.table_name;
|
|
81
|
+
const columnToReturn = {};
|
|
82
|
+
const indexToReturn = {};
|
|
83
|
+
const tableResponse = await db.session().execute(`SELECT a.attrelid::regclass::text, a.attname
|
|
84
|
+
, CASE WHEN a.atttypid = ANY ('{int,int8,int2}'::regtype[])
|
|
85
|
+
AND EXISTS (
|
|
86
|
+
SELECT FROM pg_attrdef ad
|
|
87
|
+
WHERE ad.adrelid = a.attrelid
|
|
88
|
+
AND ad.adnum = a.attnum
|
|
89
|
+
AND pg_get_expr(ad.adbin, ad.adrelid)
|
|
90
|
+
= 'nextval('''
|
|
91
|
+
|| (pg_get_serial_sequence (a.attrelid::regclass::text
|
|
92
|
+
, a.attname))::regclass
|
|
93
|
+
|| '''::regclass)'
|
|
94
|
+
)
|
|
95
|
+
THEN CASE a.atttypid
|
|
96
|
+
WHEN 'int'::regtype THEN 'serial'
|
|
97
|
+
WHEN 'int8'::regtype THEN 'bigserial'
|
|
98
|
+
WHEN 'int2'::regtype THEN 'smallserial'
|
|
99
|
+
END
|
|
100
|
+
ELSE format_type(a.atttypid, a.atttypmod)
|
|
101
|
+
END AS data_type, INFORMATION_SCHEMA.COLUMNS.table_name, INFORMATION_SCHEMA.COLUMNS.column_name, INFORMATION_SCHEMA.COLUMNS.column_default
|
|
102
|
+
FROM pg_attribute a
|
|
103
|
+
JOIN INFORMATION_SCHEMA.COLUMNS ON INFORMATION_SCHEMA.COLUMNS.column_name = a.attname
|
|
104
|
+
WHERE a.attrelid = '${tableName}'::regclass and INFORMATION_SCHEMA.COLUMNS.table_name = '${tableName}'
|
|
105
|
+
AND a.attnum > 0
|
|
106
|
+
AND NOT a.attisdropped
|
|
107
|
+
ORDER BY a.attnum;`);
|
|
108
|
+
const tableConstraints = await db.session().execute(`SELECT c.column_name, c.data_type, constraint_type, constraint_name
|
|
109
|
+
FROM information_schema.table_constraints tc
|
|
110
|
+
JOIN information_schema.constraint_column_usage AS ccu USING (constraint_schema, constraint_name)
|
|
111
|
+
JOIN information_schema.columns AS c ON c.table_schema = tc.constraint_schema
|
|
112
|
+
AND tc.table_name = c.table_name AND ccu.column_name = c.column_name
|
|
113
|
+
WHERE tc.table_name = '${tableName}';`);
|
|
114
|
+
const tableForeignKeys = await db.session().execute(`SELECT
|
|
115
|
+
tc.table_schema,
|
|
116
|
+
tc.constraint_name,
|
|
117
|
+
tc.table_name,
|
|
118
|
+
kcu.column_name,
|
|
119
|
+
ccu.table_schema AS foreign_table_schema,
|
|
120
|
+
ccu.table_name AS foreign_table_name,
|
|
121
|
+
ccu.column_name AS foreign_column_name,
|
|
122
|
+
rc.delete_rule, rc.update_rule
|
|
123
|
+
FROM
|
|
124
|
+
information_schema.table_constraints AS tc
|
|
125
|
+
JOIN information_schema.key_column_usage AS kcu
|
|
126
|
+
ON tc.constraint_name = kcu.constraint_name
|
|
127
|
+
AND tc.table_schema = kcu.table_schema
|
|
128
|
+
JOIN information_schema.constraint_column_usage AS ccu
|
|
129
|
+
ON ccu.constraint_name = tc.constraint_name
|
|
130
|
+
AND ccu.table_schema = tc.table_schema
|
|
131
|
+
JOIN information_schema.referential_constraints AS rc
|
|
132
|
+
ON ccu.constraint_name = rc.constraint_name
|
|
133
|
+
WHERE tc.constraint_type = 'FOREIGN KEY' AND tc.table_name='${tableName}';`);
|
|
134
|
+
const mappedRefernces = {};
|
|
135
|
+
for (const fk of tableForeignKeys.rows) {
|
|
136
|
+
// const tableFrom = fk.table_name;
|
|
137
|
+
const columnFrom = fk.column_name;
|
|
138
|
+
const tableTo = fk.foreign_table_name;
|
|
139
|
+
const columnTo = fk.foreign_column_name;
|
|
140
|
+
const foreignKeyName = fk.constraint_name;
|
|
141
|
+
const onUpdate = fk.update_rule;
|
|
142
|
+
const onDelete = fk.delete_rule;
|
|
143
|
+
mappedRefernces[columnFrom] = {
|
|
144
|
+
foreignKeyName,
|
|
145
|
+
table: tableTo,
|
|
146
|
+
column: columnTo,
|
|
147
|
+
onDelete: onUpdate ? `ON UPDATE ${onUpdate}` : undefined,
|
|
148
|
+
onUpdate: onDelete ? `ON DELETE ${onDelete}` : undefined,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
for (const columnResponse of tableResponse.rows) {
|
|
152
|
+
const columnName = columnResponse.attname;
|
|
153
|
+
const columnType = columnResponse.data_type;
|
|
154
|
+
const primaryKey = tableConstraints.rows.filter((mapRow) => columnName === mapRow.column_name && mapRow.constraint_type === 'PRIMARY KEY');
|
|
155
|
+
const uniqueKey = tableConstraints.rows.filter((mapRow) => columnName === mapRow.column_name && mapRow.constraint_type === 'UNIQUE');
|
|
156
|
+
const defaultValue = columnResponse.column_default === null
|
|
157
|
+
? undefined : columnResponse.column_default;
|
|
158
|
+
const isSerial = columnType === 'serial';
|
|
159
|
+
columnToReturn[columnName] = {
|
|
160
|
+
name: columnName,
|
|
161
|
+
type: columnType,
|
|
162
|
+
primaryKey: !!primaryKey[0],
|
|
163
|
+
unique: !!uniqueKey[0],
|
|
164
|
+
default: isSerial ? undefined : defaultValue,
|
|
165
|
+
notNull: !columnResponse.is_nullable,
|
|
166
|
+
references: (_a = mappedRefernces[columnName]) !== null && _a !== void 0 ? _a : undefined,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
const dbIndexes = await db.session().execute(`select
|
|
170
|
+
t.relname as table_name,
|
|
171
|
+
i.relname as index_name,
|
|
172
|
+
a.attname as column_name
|
|
173
|
+
from
|
|
174
|
+
pg_class t,
|
|
175
|
+
pg_class i,
|
|
176
|
+
pg_index ix,
|
|
177
|
+
pg_attribute a
|
|
178
|
+
where
|
|
179
|
+
t.oid = ix.indrelid
|
|
180
|
+
and i.oid = ix.indexrelid
|
|
181
|
+
and a.attrelid = t.oid
|
|
182
|
+
and a.attnum = ANY(ix.indkey)
|
|
183
|
+
and t.relkind = 'r'
|
|
184
|
+
and t.relname = '${tableName}'
|
|
185
|
+
order by
|
|
186
|
+
t.relname,
|
|
187
|
+
i.relname;`);
|
|
188
|
+
for (const dbIndex of dbIndexes.rows) {
|
|
189
|
+
const indexName = dbIndex.index_name;
|
|
190
|
+
const indexColumnName = dbIndex.column_name;
|
|
191
|
+
if (indexToReturn[indexName] !== undefined && indexToReturn[indexName] !== null) {
|
|
192
|
+
indexToReturn[indexName].columns[indexColumnName] = {
|
|
193
|
+
name: indexColumnName,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
indexToReturn[indexName] = {
|
|
198
|
+
name: indexName,
|
|
199
|
+
columns: {
|
|
200
|
+
[indexColumnName]: {
|
|
201
|
+
name: indexColumnName,
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
result[tableName] = {
|
|
208
|
+
name: tableName,
|
|
209
|
+
columns: columnToReturn,
|
|
210
|
+
indexes: indexToReturn,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
catch (e) {
|
|
214
|
+
console.log(e);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
const allEnums = await db.session().execute(`select n.nspname as enum_schema,
|
|
218
|
+
t.typname as enum_name,
|
|
219
|
+
e.enumlabel as enum_value
|
|
220
|
+
from pg_type t
|
|
221
|
+
join pg_enum e on t.oid = e.enumtypid
|
|
222
|
+
join pg_catalog.pg_namespace n ON n.oid = t.typnamespace;`);
|
|
223
|
+
const enumsToReturn = {};
|
|
224
|
+
for (const dbEnum of allEnums.rows) {
|
|
225
|
+
const enumName = dbEnum.enum_name;
|
|
226
|
+
const enumValue = dbEnum.enum_value;
|
|
227
|
+
if (enumsToReturn[enumName] !== undefined && enumsToReturn[enumName] !== null) {
|
|
228
|
+
enumsToReturn[enumName].values.push(enumValue);
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
enumsToReturn[enumName] = {
|
|
232
|
+
name: enumName,
|
|
233
|
+
values: [enumValue],
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return { version: '1', tables: result, enums: enumsToReturn };
|
|
238
|
+
};
|
|
72
239
|
}
|
|
73
240
|
}
|
|
74
241
|
exports.default = MigrationSerializer;
|