@strapi/database 4.0.0-beta.0
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/LICENSE +22 -0
- package/examples/connections.js +36 -0
- package/examples/data.sqlite +0 -0
- package/examples/docker-compose.yml +29 -0
- package/examples/index.js +73 -0
- package/examples/models.js +341 -0
- package/examples/typings.ts +17 -0
- package/lib/dialects/dialect.js +45 -0
- package/lib/dialects/index.js +28 -0
- package/lib/dialects/mysql/index.js +51 -0
- package/lib/dialects/mysql/schema-inspector.js +203 -0
- package/lib/dialects/postgresql/index.js +49 -0
- package/lib/dialects/postgresql/schema-inspector.js +229 -0
- package/lib/dialects/sqlite/index.js +74 -0
- package/lib/dialects/sqlite/schema-inspector.js +151 -0
- package/lib/entity-manager.js +886 -0
- package/lib/entity-repository.js +110 -0
- package/lib/errors.js +14 -0
- package/lib/fields.d.ts +9 -0
- package/lib/fields.js +232 -0
- package/lib/index.d.ts +146 -0
- package/lib/index.js +60 -0
- package/lib/lifecycles/index.d.ts +50 -0
- package/lib/lifecycles/index.js +66 -0
- package/lib/lifecycles/subscribers/index.d.ts +9 -0
- package/lib/lifecycles/subscribers/models-lifecycles.js +19 -0
- package/lib/lifecycles/subscribers/timestamps.js +65 -0
- package/lib/metadata/index.js +219 -0
- package/lib/metadata/relations.js +488 -0
- package/lib/migrations/index.d.ts +9 -0
- package/lib/migrations/index.js +69 -0
- package/lib/migrations/storage.js +49 -0
- package/lib/query/helpers/index.js +10 -0
- package/lib/query/helpers/join.js +95 -0
- package/lib/query/helpers/order-by.js +70 -0
- package/lib/query/helpers/populate.js +652 -0
- package/lib/query/helpers/search.js +84 -0
- package/lib/query/helpers/transform.js +84 -0
- package/lib/query/helpers/where.js +322 -0
- package/lib/query/index.js +7 -0
- package/lib/query/query-builder.js +348 -0
- package/lib/schema/__tests__/schema-diff.test.js +181 -0
- package/lib/schema/builder.js +352 -0
- package/lib/schema/diff.js +376 -0
- package/lib/schema/index.d.ts +49 -0
- package/lib/schema/index.js +95 -0
- package/lib/schema/schema.js +209 -0
- package/lib/schema/storage.js +75 -0
- package/lib/types/index.d.ts +6 -0
- package/lib/types/index.js +34 -0
- package/lib/utils/content-types.js +41 -0
- package/package.json +39 -0
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { isNil, prop, omit, castArray } = require('lodash/fp');
|
|
4
|
+
const debug = require('debug')('strapi::database');
|
|
5
|
+
|
|
6
|
+
module.exports = db => {
|
|
7
|
+
const helpers = createHelpers(db);
|
|
8
|
+
|
|
9
|
+
return {
|
|
10
|
+
/**
|
|
11
|
+
* Returns a knex schema builder instance
|
|
12
|
+
* @param {string} table - table name
|
|
13
|
+
*/
|
|
14
|
+
getSchemaBuilder(table, trx = db.connection) {
|
|
15
|
+
return table.schema ? trx.schema.withSchema(table.schema) : trx.schema;
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Creates schema in DB
|
|
20
|
+
* @param {Schema} schema - database schema
|
|
21
|
+
*/
|
|
22
|
+
async createSchema(schema) {
|
|
23
|
+
// TODO: ensure database exists;
|
|
24
|
+
|
|
25
|
+
await db.connection.transaction(async trx => {
|
|
26
|
+
// create tables without FKs first do avoid ordering issues
|
|
27
|
+
await this.createTables(schema.tables, trx);
|
|
28
|
+
});
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Creates a list of tables in a schema
|
|
33
|
+
* @param {KnexInstance} trx
|
|
34
|
+
* @param {Table[]} tables
|
|
35
|
+
*/
|
|
36
|
+
async createTables(tables, trx) {
|
|
37
|
+
for (const table of tables) {
|
|
38
|
+
debug(`Creating table: ${table.name}`);
|
|
39
|
+
const schemaBuilder = this.getSchemaBuilder(table, trx);
|
|
40
|
+
await helpers.createTable(schemaBuilder, table);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// create FKs once all the tables exist
|
|
44
|
+
for (const table of tables) {
|
|
45
|
+
debug(`Creating table foreign keys: ${table.name}`);
|
|
46
|
+
const schemaBuilder = this.getSchemaBuilder(table, trx);
|
|
47
|
+
await helpers.createTableForeignKeys(schemaBuilder, table);
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
/**
|
|
51
|
+
* Drops schema from DB
|
|
52
|
+
* @param {Schema} schema - database schema
|
|
53
|
+
* @param {object} opts
|
|
54
|
+
* @param {boolean} opts.dropDatabase - weather to drop the entire database or simply drop the tables
|
|
55
|
+
*/
|
|
56
|
+
async dropSchema(schema, { dropDatabase = false } = {}) {
|
|
57
|
+
if (dropDatabase) {
|
|
58
|
+
// TODO: drop database & return as it will drop everything
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
await db.connection.transaction(async trx => {
|
|
63
|
+
for (const table of schema.tables.reverse()) {
|
|
64
|
+
const schemaBuilder = this.getSchemaBuilder(table, trx);
|
|
65
|
+
await helpers.dropTable(schemaBuilder, table);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Applies a schema diff update in the DB
|
|
72
|
+
* @param {*} schemaDiff
|
|
73
|
+
*/
|
|
74
|
+
// TODO: implement force option to disable removal in DB
|
|
75
|
+
async updateSchema(schemaDiff) {
|
|
76
|
+
await db.dialect.startSchemaUpdate();
|
|
77
|
+
await db.connection.transaction(async trx => {
|
|
78
|
+
await this.createTables(schemaDiff.tables.added, trx);
|
|
79
|
+
|
|
80
|
+
// drop all delete table foreign keys then delete the tables
|
|
81
|
+
for (const table of schemaDiff.tables.removed) {
|
|
82
|
+
debug(`Removing table foreign keys: ${table.name}`);
|
|
83
|
+
|
|
84
|
+
const schemaBuilder = this.getSchemaBuilder(table, trx);
|
|
85
|
+
await helpers.dropTableForeignKeys(schemaBuilder, table);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
for (const table of schemaDiff.tables.removed) {
|
|
89
|
+
debug(`Removing table: ${table.name}`);
|
|
90
|
+
|
|
91
|
+
const schemaBuilder = this.getSchemaBuilder(table, trx);
|
|
92
|
+
await helpers.dropTable(schemaBuilder, table);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
for (const table of schemaDiff.tables.updated) {
|
|
96
|
+
debug(`Updating table: ${table.name}`);
|
|
97
|
+
// alter table
|
|
98
|
+
const schemaBuilder = this.getSchemaBuilder(table, trx);
|
|
99
|
+
|
|
100
|
+
await helpers.alterTable(schemaBuilder, table);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
await db.dialect.endSchemaUpdate();
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const createHelpers = db => {
|
|
110
|
+
/**
|
|
111
|
+
* Creates a foreign key on a table
|
|
112
|
+
* @param {Knex.TableBuilder} tableBuilder
|
|
113
|
+
* @param {ForeignKey} foreignKey
|
|
114
|
+
*/
|
|
115
|
+
const createForeignKey = (tableBuilder, foreignKey) => {
|
|
116
|
+
const { name, columns, referencedColumns, referencedTable, onDelete, onUpdate } = foreignKey;
|
|
117
|
+
|
|
118
|
+
const constraint = tableBuilder
|
|
119
|
+
.foreign(columns, name)
|
|
120
|
+
.references(referencedColumns)
|
|
121
|
+
.inTable(referencedTable);
|
|
122
|
+
|
|
123
|
+
if (onDelete) {
|
|
124
|
+
constraint.onDelete(onDelete);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (onUpdate) {
|
|
128
|
+
constraint.onUpdate(onUpdate);
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Drops a foreign key from a table
|
|
134
|
+
* @param {Knex.TableBuilder} tableBuilder
|
|
135
|
+
* @param {ForeignKey} foreignKey
|
|
136
|
+
*/
|
|
137
|
+
const dropForeignKey = (tableBuilder, foreignKey) => {
|
|
138
|
+
const { name, columns } = foreignKey;
|
|
139
|
+
|
|
140
|
+
tableBuilder.dropForeign(columns, name);
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Creates an index on a table
|
|
145
|
+
* @param {Knex.TableBuilder} tableBuilder
|
|
146
|
+
* @param {Index} index
|
|
147
|
+
*/
|
|
148
|
+
const createIndex = (tableBuilder, index) => {
|
|
149
|
+
const { type, columns, name } = index;
|
|
150
|
+
|
|
151
|
+
switch (type) {
|
|
152
|
+
case 'primary': {
|
|
153
|
+
return tableBuilder.primary(columns, name);
|
|
154
|
+
}
|
|
155
|
+
case 'unique': {
|
|
156
|
+
return tableBuilder.unique(columns, name);
|
|
157
|
+
}
|
|
158
|
+
default: {
|
|
159
|
+
return tableBuilder.index(columns, name, type);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Drops an index from table
|
|
166
|
+
* @param {Knex.TableBuilder} tableBuilder
|
|
167
|
+
* @param {Index} index
|
|
168
|
+
*/
|
|
169
|
+
const dropIndex = (tableBuilder, index) => {
|
|
170
|
+
const { type, columns, name } = index;
|
|
171
|
+
|
|
172
|
+
switch (type) {
|
|
173
|
+
case 'primary': {
|
|
174
|
+
return tableBuilder.dropPrimary(name);
|
|
175
|
+
}
|
|
176
|
+
case 'unique': {
|
|
177
|
+
return tableBuilder.dropUnique(columns, name);
|
|
178
|
+
}
|
|
179
|
+
default: {
|
|
180
|
+
return tableBuilder.dropIndex(columns, name);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Creates a column in a table
|
|
187
|
+
* @param {Knex.TableBuilder} tableBuilder
|
|
188
|
+
* @param {Column} column
|
|
189
|
+
*/
|
|
190
|
+
const createColumn = (tableBuilder, column) => {
|
|
191
|
+
const { type, name, args = [], defaultTo, unsigned, notNullable } = column;
|
|
192
|
+
|
|
193
|
+
const col = tableBuilder[type](name, ...args);
|
|
194
|
+
|
|
195
|
+
if (unsigned === true) {
|
|
196
|
+
col.unsigned();
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (!isNil(defaultTo)) {
|
|
200
|
+
const [value, opts] = castArray(defaultTo);
|
|
201
|
+
|
|
202
|
+
if (prop('isRaw', opts)) {
|
|
203
|
+
col.defaultTo(db.connection.raw(value), omit('isRaw', opts));
|
|
204
|
+
} else {
|
|
205
|
+
col.defaultTo(value, opts);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (notNullable === true) {
|
|
210
|
+
col.notNullable();
|
|
211
|
+
} else {
|
|
212
|
+
col.nullable();
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return col;
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Drops a column from a table
|
|
220
|
+
* @param {Knex.TableBuilder} tableBuilder
|
|
221
|
+
* @param {Column} column
|
|
222
|
+
*/
|
|
223
|
+
const dropColumn = (tableBuilder, column) => {
|
|
224
|
+
tableBuilder.dropColumn(column.name);
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Creates a table in a database
|
|
229
|
+
* @param {SchemaBuilder} schemaBuilder
|
|
230
|
+
* @param {Table} table
|
|
231
|
+
*/
|
|
232
|
+
const createTable = async (schemaBuilder, table) => {
|
|
233
|
+
await schemaBuilder.createTable(table.name, tableBuilder => {
|
|
234
|
+
// columns
|
|
235
|
+
(table.columns || []).forEach(column => createColumn(tableBuilder, column));
|
|
236
|
+
|
|
237
|
+
// indexes
|
|
238
|
+
(table.indexes || []).forEach(index => createIndex(tableBuilder, index));
|
|
239
|
+
|
|
240
|
+
// foreign keys
|
|
241
|
+
|
|
242
|
+
if (!db.dialect.canAlterConstraints()) {
|
|
243
|
+
(table.foreignKeys || []).forEach(foreignKey => createForeignKey(tableBuilder, foreignKey));
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
const alterTable = async (schemaBuilder, table) => {
|
|
249
|
+
await schemaBuilder.alterTable(table.name, tableBuilder => {
|
|
250
|
+
// Delete indexes / fks / columns
|
|
251
|
+
|
|
252
|
+
for (const removedIndex of table.indexes.removed) {
|
|
253
|
+
debug(`Dropping index ${removedIndex.name}`);
|
|
254
|
+
dropIndex(tableBuilder, removedIndex);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
for (const updateddIndex of table.indexes.updated) {
|
|
258
|
+
debug(`Dropping updated index ${updateddIndex.name}`);
|
|
259
|
+
dropIndex(tableBuilder, updateddIndex.object);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
for (const removedForeignKey of table.foreignKeys.removed) {
|
|
263
|
+
debug(`Dropping foreign key ${removedForeignKey.name}`);
|
|
264
|
+
dropForeignKey(tableBuilder, removedForeignKey);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
for (const updatedForeignKey of table.foreignKeys.updated) {
|
|
268
|
+
debug(`Dropping updated foreign key ${updatedForeignKey.name}`);
|
|
269
|
+
dropForeignKey(tableBuilder, updatedForeignKey.object);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
for (const removedColumn of table.columns.removed) {
|
|
273
|
+
debug(`Dropping column ${removedColumn.name}`);
|
|
274
|
+
dropColumn(tableBuilder, removedColumn);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Update existing columns / foreign keys / indexes
|
|
278
|
+
|
|
279
|
+
for (const updatedColumn of table.columns.updated) {
|
|
280
|
+
debug(`Updating column ${updatedColumn.name}`);
|
|
281
|
+
|
|
282
|
+
const { object } = updatedColumn;
|
|
283
|
+
|
|
284
|
+
createColumn(tableBuilder, object).alter();
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
for (const updatedForeignKey of table.foreignKeys.updated) {
|
|
288
|
+
debug(`Recreating updated foreign key ${updatedForeignKey.name}`);
|
|
289
|
+
createForeignKey(tableBuilder, updatedForeignKey.object);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
for (const updatedIndex of table.indexes.updated) {
|
|
293
|
+
debug(`Recreating updated index ${updatedIndex.name}`);
|
|
294
|
+
createIndex(tableBuilder, updatedIndex.object);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
for (const addedColumn of table.columns.added) {
|
|
298
|
+
debug(`Creating column ${addedColumn.name}`);
|
|
299
|
+
createColumn(tableBuilder, addedColumn);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
for (const addedForeignKey of table.foreignKeys.added) {
|
|
303
|
+
debug(`Creating foreign keys ${addedForeignKey.name}`);
|
|
304
|
+
createForeignKey(tableBuilder, addedForeignKey);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
for (const addedIndex of table.indexes.added) {
|
|
308
|
+
debug(`Creating index ${addedIndex.name}`);
|
|
309
|
+
createIndex(tableBuilder, addedIndex);
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Drops a table from a database
|
|
316
|
+
* @param {Knex.SchemaBuilder} schemaBuilder
|
|
317
|
+
* @param {Table} table
|
|
318
|
+
*/
|
|
319
|
+
const dropTable = (schemaBuilder, table) => schemaBuilder.dropTableIfExists(table.name);
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Creates a table foreign keys constraints
|
|
323
|
+
* @param {SchemaBuilder} schemaBuilder
|
|
324
|
+
* @param {Table} table
|
|
325
|
+
*/
|
|
326
|
+
const createTableForeignKeys = async (schemaBuilder, table) => {
|
|
327
|
+
// foreign keys
|
|
328
|
+
await schemaBuilder.table(table.name, tableBuilder => {
|
|
329
|
+
(table.foreignKeys || []).forEach(foreignKey => createForeignKey(tableBuilder, foreignKey));
|
|
330
|
+
});
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Drops a table foreign keys constraints
|
|
335
|
+
* @param {SchemaBuilder} schemaBuilder
|
|
336
|
+
* @param {Table} table
|
|
337
|
+
*/
|
|
338
|
+
const dropTableForeignKeys = async (schemaBuilder, table) => {
|
|
339
|
+
// foreign keys
|
|
340
|
+
await schemaBuilder.table(table.name, tableBuilder => {
|
|
341
|
+
(table.foreignKeys || []).forEach(foreignKey => dropForeignKey(tableBuilder, foreignKey));
|
|
342
|
+
});
|
|
343
|
+
};
|
|
344
|
+
|
|
345
|
+
return {
|
|
346
|
+
createTable,
|
|
347
|
+
alterTable,
|
|
348
|
+
dropTable,
|
|
349
|
+
createTableForeignKeys,
|
|
350
|
+
dropTableForeignKeys,
|
|
351
|
+
};
|
|
352
|
+
};
|