@strapi/database 4.0.0-next.6 → 4.0.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.
Files changed (44) hide show
  1. package/lib/dialects/dialect.js +45 -0
  2. package/lib/dialects/index.js +6 -112
  3. package/lib/dialects/mysql/index.js +51 -0
  4. package/lib/dialects/mysql/schema-inspector.js +199 -0
  5. package/lib/dialects/postgresql/index.js +49 -0
  6. package/lib/dialects/postgresql/schema-inspector.js +232 -0
  7. package/lib/dialects/sqlite/index.js +74 -0
  8. package/lib/dialects/sqlite/schema-inspector.js +151 -0
  9. package/lib/entity-manager.js +18 -14
  10. package/lib/entity-repository.js +2 -3
  11. package/lib/errors.js +45 -3
  12. package/lib/fields.d.ts +2 -3
  13. package/lib/fields.js +7 -16
  14. package/lib/index.d.ts +67 -22
  15. package/lib/index.js +44 -27
  16. package/lib/lifecycles/index.d.ts +50 -0
  17. package/lib/{lifecycles.js → lifecycles/index.js} +25 -14
  18. package/lib/lifecycles/subscribers/index.d.ts +9 -0
  19. package/lib/lifecycles/subscribers/models-lifecycles.js +19 -0
  20. package/lib/lifecycles/subscribers/timestamps.js +65 -0
  21. package/lib/metadata/index.js +84 -95
  22. package/lib/metadata/relations.js +16 -0
  23. package/lib/migrations/index.d.ts +9 -0
  24. package/lib/migrations/index.js +69 -0
  25. package/lib/migrations/storage.js +51 -0
  26. package/lib/query/helpers/join.js +3 -5
  27. package/lib/query/helpers/order-by.js +21 -11
  28. package/lib/query/helpers/populate.js +35 -10
  29. package/lib/query/helpers/search.js +26 -12
  30. package/lib/query/helpers/transform.js +42 -14
  31. package/lib/query/helpers/where.js +92 -57
  32. package/lib/query/query-builder.js +116 -34
  33. package/lib/schema/__tests__/schema-diff.test.js +14 -1
  34. package/lib/schema/builder.js +315 -284
  35. package/lib/schema/diff.js +376 -0
  36. package/lib/schema/index.d.ts +49 -0
  37. package/lib/schema/index.js +47 -50
  38. package/lib/schema/schema.js +21 -18
  39. package/lib/schema/storage.js +79 -0
  40. package/lib/utils/content-types.js +1 -2
  41. package/package.json +26 -21
  42. package/lib/configuration.js +0 -49
  43. package/lib/schema/schema-diff.js +0 -337
  44. package/lib/schema/schema-storage.js +0 -44
@@ -29,22 +29,17 @@ const createQueryBuilder = (uid, db) => {
29
29
  return {
30
30
  alias: getAlias(),
31
31
  getAlias,
32
+ state,
32
33
 
33
34
  select(args) {
34
35
  state.type = 'select';
35
- state.select = _.uniq(_.castArray(args)).map(col => this.aliasColumn(col));
36
+ state.select = _.uniq(_.castArray(args));
36
37
 
37
38
  return this;
38
39
  },
39
40
 
40
41
  addSelect(args) {
41
- _.uniq(_.castArray(args))
42
- .map(col => this.aliasColumn(col))
43
- .forEach(toSelect => {
44
- if (!state.select.includes(toSelect)) {
45
- state.select.push(toSelect);
46
- }
47
- });
42
+ state.select = _.uniq([...state.select, ..._.castArray(args)]);
48
43
 
49
44
  return this;
50
45
  },
@@ -62,6 +57,10 @@ const createQueryBuilder = (uid, db) => {
62
57
  return this;
63
58
  },
64
59
 
60
+ ref(name) {
61
+ return db.connection.ref(helpers.toColumnName(meta, name));
62
+ },
63
+
65
64
  update(data) {
66
65
  state.type = 'update';
67
66
  state.data = data;
@@ -77,9 +76,11 @@ const createQueryBuilder = (uid, db) => {
77
76
  },
78
77
 
79
78
  where(where = {}) {
80
- const processedWhere = helpers.processWhere(where, { qb: this, uid, db });
79
+ if (!_.isPlainObject(where)) {
80
+ throw new Error('Where must be an object');
81
+ }
81
82
 
82
- state.where.push(processedWhere);
83
+ state.where.push(where);
83
84
 
84
85
  return this;
85
86
  },
@@ -95,7 +96,7 @@ const createQueryBuilder = (uid, db) => {
95
96
  },
96
97
 
97
98
  orderBy(orderBy) {
98
- state.orderBy = helpers.processOrderBy(orderBy, { qb: this, uid, db });
99
+ state.orderBy = orderBy;
99
100
  return this;
100
101
  },
101
102
 
@@ -105,7 +106,7 @@ const createQueryBuilder = (uid, db) => {
105
106
  },
106
107
 
107
108
  populate(populate) {
108
- state.populate = helpers.processPopulate(populate, { qb: this, uid, db });
109
+ state.populate = populate;
109
110
  return this;
110
111
  },
111
112
 
@@ -115,7 +116,7 @@ const createQueryBuilder = (uid, db) => {
115
116
  },
116
117
 
117
118
  init(params = {}) {
118
- const { _q, where, select, limit, offset, orderBy, groupBy, populate } = params;
119
+ const { _q, filters, where, select, limit, offset, orderBy, groupBy, populate } = params;
119
120
 
120
121
  if (!_.isNil(where)) {
121
122
  this.where(where);
@@ -151,9 +152,17 @@ const createQueryBuilder = (uid, db) => {
151
152
  this.populate(populate);
152
153
  }
153
154
 
155
+ if (!_.isNil(filters)) {
156
+ this.filters(filters);
157
+ }
158
+
154
159
  return this;
155
160
  },
156
161
 
162
+ filters(filters) {
163
+ state.filters = filters;
164
+ },
165
+
157
166
  first() {
158
167
  state.first = true;
159
168
  return this;
@@ -164,43 +173,111 @@ const createQueryBuilder = (uid, db) => {
164
173
  return this;
165
174
  },
166
175
 
167
- aliasColumn(columnName) {
168
- if (typeof columnName !== 'string') {
169
- return columnName;
176
+ mustUseAlias() {
177
+ return ['select', 'count'].includes(state.type);
178
+ },
179
+
180
+ aliasColumn(key, alias) {
181
+ if (typeof key !== 'string') {
182
+ return key;
183
+ }
184
+
185
+ if (key.indexOf('.') >= 0) {
186
+ return key;
187
+ }
188
+
189
+ if (!_.isNil(alias)) {
190
+ return `${alias}.${key}`;
170
191
  }
171
192
 
172
- if (columnName.indexOf('.') >= 0) return columnName;
173
- return this.alias + '.' + columnName;
193
+ return this.mustUseAlias() ? `${this.alias}.${key}` : key;
174
194
  },
175
195
 
176
196
  raw(...args) {
177
197
  return db.connection.raw(...args);
178
198
  },
179
199
 
180
- getKnexQuery() {
181
- const aliasedTableName = state.type === 'insert' ? tableName : { [this.alias]: tableName };
200
+ shouldUseSubQuery() {
201
+ return ['delete', 'update'].includes(state.type) && state.joins.length > 0;
202
+ },
203
+
204
+ runSubQuery() {
205
+ this.select('id');
206
+ const subQB = this.getKnexQuery();
182
207
 
183
- const qb = db.connection(aliasedTableName);
208
+ const nestedSubQuery = db
209
+ .getConnection()
210
+ .select('id')
211
+ .from(subQB.as('subQuery'));
184
212
 
213
+ return db
214
+ .getConnection(tableName)
215
+ [state.type]()
216
+ .whereIn('id', nestedSubQuery);
217
+ },
218
+
219
+ processState() {
220
+ state.orderBy = helpers.processOrderBy(state.orderBy, { qb: this, uid, db });
221
+
222
+ if (!_.isNil(state.filters)) {
223
+ if (_.isFunction(state.filters)) {
224
+ const filters = state.filters({ qb: this, uid, meta, db });
225
+
226
+ if (!_.isNil(filters)) {
227
+ state.where.push(filters);
228
+ }
229
+ } else {
230
+ state.where.push(state.filters);
231
+ }
232
+ }
233
+
234
+ state.where = helpers.processWhere(state.where, { qb: this, uid, db });
235
+ state.populate = helpers.processPopulate(state.populate, { qb: this, uid, db });
236
+ state.data = helpers.toRow(meta, state.data);
237
+
238
+ this.processSelect();
239
+ },
240
+
241
+ shouldUseDistinct() {
242
+ return state.joins.length > 0 && _.isEmpty(state.groupBy);
243
+ },
244
+
245
+ processSelect() {
246
+ state.select = state.select.map(field => helpers.toColumnName(meta, field));
247
+
248
+ if (this.shouldUseDistinct()) {
249
+ const joinsOrderByColumns = state.joins.flatMap(join => {
250
+ return _.keys(join.orderBy).map(key => this.aliasColumn(key, join.alias));
251
+ });
252
+ const orderByColumns = state.orderBy.map(({ column }) => column);
253
+
254
+ state.select = _.uniq([...joinsOrderByColumns, ...orderByColumns, ...state.select]);
255
+ }
256
+ },
257
+
258
+ getKnexQuery() {
185
259
  if (!state.type) {
186
260
  this.select('*');
187
261
  }
188
262
 
263
+ const aliasedTableName = this.mustUseAlias() ? `${tableName} as ${this.alias}` : tableName;
264
+
265
+ const qb = db.getConnection(aliasedTableName);
266
+
267
+ if (this.shouldUseSubQuery()) {
268
+ return this.runSubQuery();
269
+ }
270
+
271
+ this.processState();
272
+
189
273
  switch (state.type) {
190
274
  case 'select': {
191
- if (state.select.length === 0) {
192
- state.select = [this.aliasColumn('*')];
193
- }
275
+ qb.select(state.select.map(column => this.aliasColumn(column)));
194
276
 
195
- if (state.joins.length > 0 && !state.groupBy) {
196
- // add a discting when making joins and if we don't have a groupBy
197
- // TODO: make sure we return the right data
198
- qb.distinct(`${this.alias}.id`);
199
- // TODO: add column if they aren't there already
200
- state.select.unshift(...state.orderBy.map(({ column }) => column));
277
+ if (this.shouldUseDistinct()) {
278
+ qb.distinct();
201
279
  }
202
280
 
203
- qb.select(state.select);
204
281
  break;
205
282
  }
206
283
  case 'count': {
@@ -218,14 +295,17 @@ const createQueryBuilder = (uid, db) => {
218
295
  }
219
296
  case 'update': {
220
297
  qb.update(state.data);
221
-
222
298
  break;
223
299
  }
224
300
  case 'delete': {
225
- qb.del();
301
+ qb.delete();
226
302
 
227
303
  break;
228
304
  }
305
+ case 'truncate': {
306
+ db.truncate();
307
+ break;
308
+ }
229
309
  }
230
310
 
231
311
  if (state.limit) {
@@ -248,13 +328,15 @@ const createQueryBuilder = (uid, db) => {
248
328
  qb.groupBy(state.groupBy);
249
329
  }
250
330
 
331
+ // if there are joins and it is a delete or update use a sub query
251
332
  if (state.where) {
252
333
  helpers.applyWhere(qb, state.where);
253
334
  }
254
335
 
336
+ // if there are joins and it is a delete or update use a sub query
255
337
  if (state.search) {
256
338
  qb.where(subQb => {
257
- helpers.applySearch(subQb, state.search, { alias: this.alias, db, uid });
339
+ helpers.applySearch(subQb, state.search, { qb: this, db, uid });
258
340
  });
259
341
  }
260
342
 
@@ -1,8 +1,21 @@
1
1
  'use strict';
2
2
 
3
- const { diffSchemas } = require('../schema-diff');
3
+ const createSchemaDiff = require('../diff');
4
4
 
5
+ let diffSchemas;
5
6
  describe('diffSchemas', () => {
7
+ beforeEach(() => {
8
+ const schemaDiff = createSchemaDiff({
9
+ dialect: {
10
+ usesForeignKeys() {
11
+ return true;
12
+ },
13
+ },
14
+ });
15
+
16
+ diffSchemas = schemaDiff.diff.bind(schemaDiff);
17
+ });
18
+
6
19
  test('New Table', () => {
7
20
  const testTable = {
8
21
  name: 'my_table',