@strapi/database 4.0.0-next.8 → 4.0.2

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 (46) hide show
  1. package/jest.config.js +10 -0
  2. package/lib/dialects/dialect.js +45 -0
  3. package/lib/dialects/index.js +6 -112
  4. package/lib/dialects/mysql/index.js +51 -0
  5. package/lib/dialects/mysql/schema-inspector.js +199 -0
  6. package/lib/dialects/postgresql/index.js +49 -0
  7. package/lib/dialects/postgresql/schema-inspector.js +232 -0
  8. package/lib/dialects/sqlite/index.js +73 -0
  9. package/lib/dialects/sqlite/schema-inspector.js +151 -0
  10. package/lib/entity-manager.js +18 -14
  11. package/lib/entity-repository.js +2 -3
  12. package/lib/errors.js +44 -2
  13. package/lib/fields.d.ts +2 -3
  14. package/lib/fields.js +7 -16
  15. package/lib/index.d.ts +67 -22
  16. package/lib/index.js +44 -27
  17. package/lib/lifecycles/index.d.ts +50 -0
  18. package/lib/{lifecycles.js → lifecycles/index.js} +25 -14
  19. package/lib/lifecycles/subscribers/index.d.ts +9 -0
  20. package/lib/lifecycles/subscribers/models-lifecycles.js +19 -0
  21. package/lib/lifecycles/subscribers/timestamps.js +65 -0
  22. package/lib/metadata/index.js +84 -95
  23. package/lib/metadata/relations.js +16 -0
  24. package/lib/migrations/index.d.ts +9 -0
  25. package/lib/migrations/index.js +69 -0
  26. package/lib/migrations/storage.js +51 -0
  27. package/lib/query/helpers/join.js +3 -5
  28. package/lib/query/helpers/order-by.js +21 -11
  29. package/lib/query/helpers/populate.js +35 -10
  30. package/lib/query/helpers/search.js +26 -12
  31. package/lib/query/helpers/transform.js +42 -14
  32. package/lib/query/helpers/where.js +92 -57
  33. package/lib/query/query-builder.js +116 -34
  34. package/lib/schema/__tests__/schema-diff.test.js +14 -1
  35. package/lib/schema/builder.js +315 -284
  36. package/lib/schema/diff.js +374 -0
  37. package/lib/schema/index.d.ts +49 -0
  38. package/lib/schema/index.js +47 -50
  39. package/lib/schema/schema.js +21 -26
  40. package/lib/schema/storage.js +79 -0
  41. package/lib/utils/content-types.js +0 -1
  42. package/package.json +26 -21
  43. package/examples/data.sqlite +0 -0
  44. package/lib/configuration.js +0 -49
  45. package/lib/schema/schema-diff.js +0 -337
  46. package/lib/schema/schema-storage.js +0 -44
@@ -5,12 +5,12 @@ const _ = require('lodash/fp');
5
5
  const types = require('../../types');
6
6
  const { createField } = require('../../fields');
7
7
 
8
- const fromRow = (metadata, row) => {
8
+ const fromRow = (meta, row) => {
9
9
  if (Array.isArray(row)) {
10
- return row.map(singleRow => fromRow(metadata, singleRow));
10
+ return row.map(singleRow => fromRow(meta, singleRow));
11
11
  }
12
12
 
13
- const { attributes } = metadata;
13
+ const { attributes } = meta;
14
14
 
15
15
  if (_.isNil(row)) {
16
16
  return null;
@@ -19,25 +19,16 @@ const fromRow = (metadata, row) => {
19
19
  const obj = {};
20
20
 
21
21
  for (const column in row) {
22
- // to field Name
23
- const attributeName = column;
24
-
25
- if (!attributes[attributeName]) {
26
- // ignore value that are not related to an attribute (join columns ...)
22
+ if (!_.has(column, meta.columnToAttribute)) {
27
23
  continue;
28
24
  }
29
25
 
26
+ const attributeName = meta.columnToAttribute[column];
30
27
  const attribute = attributes[attributeName];
31
28
 
32
29
  if (types.isScalar(attribute.type)) {
33
- // TODO: we convert to column name
34
- // TODO: handle default value too
35
- // TODO: format data & use dialect to know which type they support (json particularly)
36
-
37
30
  const field = createField(attribute);
38
31
 
39
- // TODO: validate data on creation
40
- // field.validate(data[attributeName]);
41
32
  const val = row[column] === null ? null : field.fromDB(row[column]);
42
33
 
43
34
  obj[attributeName] = val;
@@ -51,6 +42,43 @@ const fromRow = (metadata, row) => {
51
42
  return obj;
52
43
  };
53
44
 
45
+ const toRow = (meta, data = {}) => {
46
+ if (_.isNil(data)) {
47
+ return data;
48
+ }
49
+
50
+ if (_.isArray(data)) {
51
+ return data.map(datum => toRow(meta, datum));
52
+ }
53
+
54
+ const { attributes } = meta;
55
+
56
+ for (const key in data) {
57
+ const attribute = attributes[key];
58
+
59
+ if (!attribute || attribute.columnName === key) {
60
+ continue;
61
+ }
62
+
63
+ data[attribute.columnName] = data[key];
64
+ delete data[key];
65
+ }
66
+
67
+ return data;
68
+ };
69
+
70
+ const toColumnName = (meta, name) => {
71
+ const attribute = meta.attributes[name];
72
+
73
+ if (!attribute) {
74
+ return name;
75
+ }
76
+
77
+ return attribute.columnName || name;
78
+ };
79
+
54
80
  module.exports = {
81
+ toRow,
55
82
  fromRow,
83
+ toColumnName,
56
84
  };
@@ -3,7 +3,9 @@
3
3
  const _ = require('lodash/fp');
4
4
 
5
5
  const types = require('../../types');
6
+ const { createField } = require('../../fields');
6
7
  const { createJoin } = require('./join');
8
+ const { toColumnName } = require('./transform');
7
9
 
8
10
  const GROUP_OPERATORS = ['$and', '$or'];
9
11
  const OPERATORS = [
@@ -19,8 +21,6 @@ const OPERATORS = [
19
21
  '$null',
20
22
  '$notNull',
21
23
  '$between',
22
- // '$like',
23
- // '$regexp',
24
24
  '$startsWith',
25
25
  '$endsWith',
26
26
  '$contains',
@@ -29,10 +29,65 @@ const OPERATORS = [
29
29
  '$notContainsi',
30
30
  ];
31
31
 
32
+ const CAST_OPERATORS = [
33
+ '$not',
34
+ '$in',
35
+ '$notIn',
36
+ '$eq',
37
+ '$ne',
38
+ '$gt',
39
+ '$gte',
40
+ '$lt',
41
+ '$lte',
42
+ '$between',
43
+ ];
44
+
32
45
  const ARRAY_OPERATORS = ['$in', '$notIn', '$between'];
33
46
 
34
47
  const isOperator = key => OPERATORS.includes(key);
35
48
 
49
+ const castValue = (value, attribute) => {
50
+ if (!attribute) {
51
+ return value;
52
+ }
53
+
54
+ if (types.isScalar(attribute.type)) {
55
+ const field = createField(attribute);
56
+
57
+ return value === null ? null : field.toDB(value);
58
+ }
59
+
60
+ return value;
61
+ };
62
+
63
+ const processAttributeWhere = (attribute, where, operator = '$eq') => {
64
+ if (_.isArray(where)) {
65
+ return where.map(sub => processAttributeWhere(attribute, sub, operator));
66
+ }
67
+
68
+ if (!_.isPlainObject(where)) {
69
+ if (CAST_OPERATORS.includes(operator)) {
70
+ return castValue(where, attribute);
71
+ }
72
+
73
+ return where;
74
+ }
75
+
76
+ const filters = {};
77
+
78
+ for (const key in where) {
79
+ const value = where[key];
80
+
81
+ if (!isOperator(key)) {
82
+ throw new Error(`Undefined attribute level operator ${key}`);
83
+ }
84
+
85
+ filters[key] = processAttributeWhere(attribute, value, key);
86
+ }
87
+
88
+ return filters;
89
+ };
90
+
36
91
  /**
37
92
  * Process where parameter
38
93
  * @param {Object} where
@@ -40,9 +95,13 @@ const isOperator = key => OPERATORS.includes(key);
40
95
  * @param {number} depth
41
96
  * @returns {Object}
42
97
  */
43
- const processWhere = (where, ctx, depth = 0) => {
44
- if (depth === 0 && !_.isPlainObject(where)) {
45
- throw new Error('Where must be an object');
98
+ const processWhere = (where, ctx) => {
99
+ if (!_.isArray(where) && !_.isPlainObject(where)) {
100
+ throw new Error('Where must be an array or an object');
101
+ }
102
+
103
+ if (_.isArray(where)) {
104
+ return where.map(sub => processWhere(sub, ctx));
46
105
  }
47
106
 
48
107
  const processNested = (where, ctx) => {
@@ -50,17 +109,17 @@ const processWhere = (where, ctx, depth = 0) => {
50
109
  return where;
51
110
  }
52
111
 
53
- return processWhere(where, ctx, depth + 1);
112
+ return processWhere(where, ctx);
54
113
  };
55
114
 
56
- const { db, uid, qb, alias = qb.alias } = ctx;
115
+ const { db, uid, qb, alias } = ctx;
116
+ const meta = db.metadata.get(uid);
57
117
 
58
118
  const filters = {};
59
119
 
60
120
  // for each key in where
61
121
  for (const key in where) {
62
122
  const value = where[key];
63
- const attribute = db.metadata.get(uid).attributes[key];
64
123
 
65
124
  // if operator $and $or then loop over them
66
125
  if (GROUP_OPERATORS.includes(key)) {
@@ -74,36 +133,24 @@ const processWhere = (where, ctx, depth = 0) => {
74
133
  }
75
134
 
76
135
  if (isOperator(key)) {
77
- if (depth == 0) {
78
- throw new Error(
79
- `Only $and, $or and $not can by used as root level operators. Found ${key}.`
80
- );
81
- }
82
-
83
- filters[key] = processNested(value, ctx);
84
- continue;
136
+ throw new Error(`Only $and, $or and $not can by used as root level operators. Found ${key}.`);
85
137
  }
86
138
 
87
- if (!attribute) {
88
- // TODO: if targeting a column name instead of an attribute
139
+ const attribute = meta.attributes[key];
89
140
 
90
- // if key as an alias don't add one
91
- if (key.indexOf('.') >= 0) {
92
- filters[key] = processNested(value, ctx);
93
- } else {
94
- filters[`${alias || qb.alias}.${key}`] = processNested(value, ctx);
95
- }
141
+ if (!attribute) {
142
+ filters[qb.aliasColumn(key, alias)] = processAttributeWhere(null, value);
96
143
  continue;
97
-
98
- // throw new Error(`Attribute ${key} not found on model ${uid}`);
99
144
  }
100
145
 
101
- // move to if else to check for scalar / relation / components & throw for other types
102
- if (attribute.type === 'relation') {
103
- // TODO: pass down some filters (e.g published at)
104
-
146
+ if (types.isRelation(attribute.type)) {
105
147
  // attribute
106
- const subAlias = createJoin(ctx, { alias, uid, attributeName: key, attribute });
148
+ const subAlias = createJoin(ctx, {
149
+ alias: alias || qb.alias,
150
+ uid,
151
+ attributeName: key,
152
+ attribute,
153
+ });
107
154
 
108
155
  let nestedWhere = processNested(value, {
109
156
  db,
@@ -113,7 +160,7 @@ const processWhere = (where, ctx, depth = 0) => {
113
160
  });
114
161
 
115
162
  if (!_.isPlainObject(nestedWhere) || isOperator(_.keys(nestedWhere)[0])) {
116
- nestedWhere = { [`${subAlias}.id`]: nestedWhere };
163
+ nestedWhere = { [qb.aliasColumn('id', subAlias)]: nestedWhere };
117
164
  }
118
165
 
119
166
  // TODO: use a better merge logic (push to $and when collisions)
@@ -123,9 +170,11 @@ const processWhere = (where, ctx, depth = 0) => {
123
170
  }
124
171
 
125
172
  if (types.isScalar(attribute.type)) {
126
- // TODO: convert attribute name to column name
127
- // TODO: cast to DB type
128
- filters[`${alias || qb.alias}.${key}`] = processNested(value, ctx);
173
+ const columnName = toColumnName(meta, key);
174
+ const aliasedColumnName = qb.aliasColumn(columnName, alias);
175
+
176
+ filters[aliasedColumnName] = processAttributeWhere(attribute, value);
177
+
129
178
  continue;
130
179
  }
131
180
 
@@ -135,6 +184,7 @@ const processWhere = (where, ctx, depth = 0) => {
135
184
  return filters;
136
185
  };
137
186
 
187
+ // TODO: add type casting per operator at some point
138
188
  const applyOperator = (qb, column, operator, value) => {
139
189
  if (Array.isArray(value) && !ARRAY_OPERATORS.includes(operator)) {
140
190
  return qb.where(subQB => {
@@ -197,7 +247,6 @@ const applyOperator = (qb, column, operator, value) => {
197
247
  break;
198
248
  }
199
249
  case '$null': {
200
- // TODO: make this better
201
250
  if (value) {
202
251
  qb.whereNull(column);
203
252
  }
@@ -207,26 +256,12 @@ const applyOperator = (qb, column, operator, value) => {
207
256
  if (value) {
208
257
  qb.whereNotNull(column);
209
258
  }
210
-
211
259
  break;
212
260
  }
213
261
  case '$between': {
214
262
  qb.whereBetween(column, value);
215
263
  break;
216
264
  }
217
- // case '$regexp': {
218
- // // TODO:
219
- //
220
- // break;
221
- // }
222
- // // string
223
- // // TODO: use $case to make it case insensitive
224
- // case '$like': {
225
- // qb.where(column, 'like', value);
226
- // break;
227
- // }
228
-
229
- // TODO: add casting logic
230
265
  case '$startsWith': {
231
266
  qb.where(column, 'like', `${value}%`);
232
267
  break;
@@ -260,7 +295,7 @@ const applyOperator = (qb, column, operator, value) => {
260
295
  // TODO: relational operators every/some/exists/size ...
261
296
 
262
297
  default: {
263
- throw new Error(`Undefined operator ${operator}`);
298
+ throw new Error(`Undefined attribute level operator ${operator}`);
264
299
  }
265
300
  }
266
301
  };
@@ -274,7 +309,6 @@ const applyWhereToColumn = (qb, column, columnWhere) => {
274
309
  return qb.where(column, columnWhere);
275
310
  }
276
311
 
277
- // TODO: handle casing
278
312
  Object.keys(columnWhere).forEach(operator => {
279
313
  const value = columnWhere[operator];
280
314
 
@@ -283,12 +317,12 @@ const applyWhereToColumn = (qb, column, columnWhere) => {
283
317
  };
284
318
 
285
319
  const applyWhere = (qb, where) => {
286
- if (Array.isArray(where)) {
287
- return qb.where(subQB => where.forEach(subWhere => applyWhere(subQB, subWhere)));
320
+ if (!_.isArray(where) && !_.isPlainObject(where)) {
321
+ throw new Error('Where must be an array or an object');
288
322
  }
289
323
 
290
- if (!_.isPlainObject(where)) {
291
- throw new Error('Where must be an object');
324
+ if (_.isArray(where)) {
325
+ return qb.where(subQB => where.forEach(subWhere => applyWhere(subQB, subWhere)));
292
326
  }
293
327
 
294
328
  Object.keys(where).forEach(key => {
@@ -316,9 +350,10 @@ const applyWhere = (qb, where) => {
316
350
 
317
351
  const fieldLowerFn = qb => {
318
352
  // Postgres requires string to be passed
319
- if (qb.client.config.client === 'pg') {
353
+ if (qb.client.config.client === 'postgres') {
320
354
  return 'LOWER(CAST(?? AS VARCHAR))';
321
355
  }
356
+
322
357
  return 'LOWER(??)';
323
358
  };
324
359
 
@@ -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',