@strapi/database 4.3.4 → 4.3.7

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 (57) hide show
  1. package/jest.config.js +1 -1
  2. package/lib/__tests__/lifecycles.test.js +1 -1
  3. package/lib/connection.js +4 -4
  4. package/lib/dialects/dialect.js +12 -2
  5. package/lib/dialects/index.js +2 -2
  6. package/lib/dialects/mysql/index.js +2 -2
  7. package/lib/dialects/mysql/schema-inspector.js +12 -16
  8. package/lib/dialects/postgresql/index.js +2 -2
  9. package/lib/dialects/postgresql/schema-inspector.js +30 -25
  10. package/lib/dialects/sqlite/index.js +9 -1
  11. package/lib/dialects/sqlite/schema-inspector.js +5 -5
  12. package/lib/entity-manager.js +46 -72
  13. package/lib/entity-repository.js +1 -1
  14. package/lib/errors/database.js +12 -0
  15. package/lib/errors/index.js +15 -0
  16. package/lib/errors/invalid-date.js +14 -0
  17. package/lib/errors/invalid-datetime.js +14 -0
  18. package/lib/errors/invalid-time.js +14 -0
  19. package/lib/errors/not-null.js +15 -0
  20. package/lib/fields/biginteger.js +17 -0
  21. package/lib/fields/boolean.js +39 -0
  22. package/lib/fields/date.js +16 -0
  23. package/lib/fields/datetime.js +19 -0
  24. package/lib/fields/field.js +17 -0
  25. package/lib/{fields.d.ts → fields/index.d.ts} +0 -0
  26. package/lib/fields/index.js +49 -0
  27. package/lib/fields/json.js +16 -0
  28. package/lib/fields/number.js +23 -0
  29. package/lib/fields/shared/parsers.js +69 -0
  30. package/lib/fields/string.js +17 -0
  31. package/lib/fields/time.js +17 -0
  32. package/lib/fields/timestamp.js +19 -0
  33. package/lib/index.js +1 -1
  34. package/lib/lifecycles/index.js +2 -2
  35. package/lib/lifecycles/subscribers/models-lifecycles.js +1 -1
  36. package/lib/lifecycles/subscribers/timestamps.js +2 -2
  37. package/lib/metadata/index.js +2 -2
  38. package/lib/metadata/relations.js +18 -15
  39. package/lib/migrations/index.js +5 -5
  40. package/lib/migrations/storage.js +4 -11
  41. package/lib/query/helpers/join.js +5 -5
  42. package/lib/query/helpers/order-by.js +1 -1
  43. package/lib/query/helpers/populate.js +43 -51
  44. package/lib/query/helpers/search.js +5 -5
  45. package/lib/query/helpers/transform.js +2 -2
  46. package/lib/query/helpers/where.js +17 -17
  47. package/lib/query/query-builder.js +11 -14
  48. package/lib/schema/builder.js +28 -17
  49. package/lib/schema/diff.js +15 -15
  50. package/lib/schema/index.js +1 -2
  51. package/lib/schema/schema.js +4 -4
  52. package/lib/schema/storage.js +3 -6
  53. package/lib/types/index.js +6 -6
  54. package/lib/utils/content-types.js +3 -3
  55. package/package.json +3 -3
  56. package/lib/errors.js +0 -56
  57. package/lib/fields.js +0 -231
@@ -3,7 +3,7 @@
3
3
  const { isNil, prop, omit, castArray } = require('lodash/fp');
4
4
  const debug = require('debug')('strapi::database');
5
5
 
6
- module.exports = db => {
6
+ module.exports = (db) => {
7
7
  const helpers = createHelpers(db);
8
8
 
9
9
  return {
@@ -20,7 +20,7 @@ module.exports = db => {
20
20
  * @param {Schema} schema - database schema
21
21
  */
22
22
  async createSchema(schema) {
23
- await db.connection.transaction(async trx => {
23
+ await db.connection.transaction(async (trx) => {
24
24
  await this.createTables(schema.tables, trx);
25
25
  });
26
26
  },
@@ -56,7 +56,7 @@ module.exports = db => {
56
56
  return;
57
57
  }
58
58
 
59
- await db.connection.transaction(async trx => {
59
+ await db.connection.transaction(async (trx) => {
60
60
  for (const table of schema.tables.reverse()) {
61
61
  const schemaBuilder = this.getSchemaBuilder(trx);
62
62
  await helpers.dropTable(schemaBuilder, table);
@@ -73,7 +73,7 @@ module.exports = db => {
73
73
  const { forceMigration } = db.config.settings;
74
74
 
75
75
  await db.dialect.startSchemaUpdate();
76
- await db.connection.transaction(async trx => {
76
+ await db.connection.transaction(async (trx) => {
77
77
  await this.createTables(schemaDiff.tables.added, trx);
78
78
 
79
79
  if (forceMigration) {
@@ -107,7 +107,7 @@ module.exports = db => {
107
107
  };
108
108
  };
109
109
 
110
- const createHelpers = db => {
110
+ const createHelpers = (db) => {
111
111
  /**
112
112
  * Creates a foreign key on a table
113
113
  * @param {Knex.TableBuilder} tableBuilder
@@ -243,23 +243,25 @@ const createHelpers = db => {
243
243
  * @param {Table} table
244
244
  */
245
245
  const createTable = async (schemaBuilder, table) => {
246
- await schemaBuilder.createTable(table.name, tableBuilder => {
246
+ await schemaBuilder.createTable(table.name, (tableBuilder) => {
247
247
  // columns
248
- (table.columns || []).forEach(column => createColumn(tableBuilder, column));
248
+ (table.columns || []).forEach((column) => createColumn(tableBuilder, column));
249
249
 
250
250
  // indexes
251
- (table.indexes || []).forEach(index => createIndex(tableBuilder, index));
251
+ (table.indexes || []).forEach((index) => createIndex(tableBuilder, index));
252
252
 
253
253
  // foreign keys
254
254
 
255
255
  if (!db.dialect.canAlterConstraints()) {
256
- (table.foreignKeys || []).forEach(foreignKey => createForeignKey(tableBuilder, foreignKey));
256
+ (table.foreignKeys || []).forEach((foreignKey) =>
257
+ createForeignKey(tableBuilder, foreignKey)
258
+ );
257
259
  }
258
260
  });
259
261
  };
260
262
 
261
263
  const alterTable = async (schemaBuilder, table) => {
262
- await schemaBuilder.alterTable(table.name, tableBuilder => {
264
+ await schemaBuilder.alterTable(table.name, (tableBuilder) => {
263
265
  // Delete indexes / fks / columns
264
266
 
265
267
  for (const removedIndex of table.indexes.removed) {
@@ -288,13 +290,16 @@ const createHelpers = db => {
288
290
  }
289
291
 
290
292
  // Update existing columns / foreign keys / indexes
291
-
292
293
  for (const updatedColumn of table.columns.updated) {
293
294
  debug(`Updating column ${updatedColumn.name}`);
294
295
 
295
296
  const { object } = updatedColumn;
296
297
 
297
- createColumn(tableBuilder, object).alter();
298
+ if (object.type === 'increments') {
299
+ createColumn(tableBuilder, { ...object, type: 'integer' }).alter();
300
+ } else {
301
+ createColumn(tableBuilder, object).alter();
302
+ }
298
303
  }
299
304
 
300
305
  for (const updatedForeignKey of table.foreignKeys.updated) {
@@ -309,7 +314,13 @@ const createHelpers = db => {
309
314
 
310
315
  for (const addedColumn of table.columns.added) {
311
316
  debug(`Creating column ${addedColumn.name}`);
312
- createColumn(tableBuilder, addedColumn);
317
+
318
+ if (addedColumn.type === 'increments' && !db.dialect.canAddIncrements()) {
319
+ tableBuilder.integer(addedColumn.name).unsigned().notNullable();
320
+ tableBuilder.primary(addedColumn.name);
321
+ } else {
322
+ createColumn(tableBuilder, addedColumn);
323
+ }
313
324
  }
314
325
 
315
326
  for (const addedForeignKey of table.foreignKeys.added) {
@@ -344,8 +355,8 @@ const createHelpers = db => {
344
355
  */
345
356
  const createTableForeignKeys = async (schemaBuilder, table) => {
346
357
  // foreign keys
347
- await schemaBuilder.table(table.name, tableBuilder => {
348
- (table.foreignKeys || []).forEach(foreignKey => createForeignKey(tableBuilder, foreignKey));
358
+ await schemaBuilder.table(table.name, (tableBuilder) => {
359
+ (table.foreignKeys || []).forEach((foreignKey) => createForeignKey(tableBuilder, foreignKey));
349
360
  });
350
361
  };
351
362
 
@@ -360,8 +371,8 @@ const createHelpers = db => {
360
371
  }
361
372
 
362
373
  // foreign keys
363
- await schemaBuilder.table(table.name, tableBuilder => {
364
- (table.foreignKeys || []).forEach(foreignKey => dropForeignKey(tableBuilder, foreignKey));
374
+ await schemaBuilder.table(table.name, (tableBuilder) => {
375
+ (table.foreignKeys || []).forEach((foreignKey) => dropForeignKey(tableBuilder, foreignKey));
365
376
  });
366
377
  };
367
378
 
@@ -14,36 +14,36 @@ const statuses = {
14
14
 
15
15
  const helpers = {
16
16
  hasTable(schema, tableName) {
17
- return schema.tables.findIndex(table => table.name === tableName) !== -1;
17
+ return schema.tables.findIndex((table) => table.name === tableName) !== -1;
18
18
  },
19
19
  findTable(schema, tableName) {
20
- return schema.tables.find(table => table.name === tableName);
20
+ return schema.tables.find((table) => table.name === tableName);
21
21
  },
22
22
 
23
23
  hasColumn(table, columnName) {
24
- return table.columns.findIndex(column => column.name === columnName) !== -1;
24
+ return table.columns.findIndex((column) => column.name === columnName) !== -1;
25
25
  },
26
26
  findColumn(table, columnName) {
27
- return table.columns.find(column => column.name === columnName);
27
+ return table.columns.find((column) => column.name === columnName);
28
28
  },
29
29
 
30
30
  hasIndex(table, columnName) {
31
- return table.indexes.findIndex(column => column.name === columnName) !== -1;
31
+ return table.indexes.findIndex((column) => column.name === columnName) !== -1;
32
32
  },
33
33
  findIndex(table, columnName) {
34
- return table.indexes.find(column => column.name === columnName);
34
+ return table.indexes.find((column) => column.name === columnName);
35
35
  },
36
36
 
37
37
  hasForeignKey(table, columnName) {
38
- return table.foreignKeys.findIndex(column => column.name === columnName) !== -1;
38
+ return table.foreignKeys.findIndex((column) => column.name === columnName) !== -1;
39
39
  },
40
40
  findForeignKey(table, columnName) {
41
- return table.foreignKeys.find(column => column.name === columnName);
41
+ return table.foreignKeys.find((column) => column.name === columnName);
42
42
  },
43
43
  };
44
44
 
45
- module.exports = db => {
46
- const hasChangedStatus = diff => diff.status === statuses.CHANGED;
45
+ module.exports = (db) => {
46
+ const hasChangedStatus = (diff) => diff.status === statuses.CHANGED;
47
47
 
48
48
  /**
49
49
  * Compares two indexes info
@@ -117,7 +117,7 @@ module.exports = db => {
117
117
 
118
118
  const diffDefault = (oldColumn, column) => {
119
119
  const oldDefaultTo = oldColumn.defaultTo;
120
- const defaultTo = column.defaultTo;
120
+ const { defaultTo } = column;
121
121
 
122
122
  if (oldDefaultTo === null || _.toLower(oldDefaultTo) === 'null') {
123
123
  return _.isNil(defaultTo) || _.toLower(defaultTo) === 'null';
@@ -197,7 +197,7 @@ module.exports = db => {
197
197
  }
198
198
  }
199
199
 
200
- const hasChanged = [addedColumns, updatedColumns, removedColumns].some(arr => arr.length > 0);
200
+ const hasChanged = [addedColumns, updatedColumns, removedColumns].some((arr) => arr.length > 0);
201
201
 
202
202
  return {
203
203
  status: hasChanged ? statuses.CHANGED : statuses.UNCHANGED,
@@ -237,7 +237,7 @@ module.exports = db => {
237
237
  }
238
238
  }
239
239
 
240
- const hasChanged = [addedIndexes, updatedIndexes, removedIndexes].some(arr => arr.length > 0);
240
+ const hasChanged = [addedIndexes, updatedIndexes, removedIndexes].some((arr) => arr.length > 0);
241
241
 
242
242
  return {
243
243
  status: hasChanged ? statuses.CHANGED : statuses.UNCHANGED,
@@ -290,7 +290,7 @@ module.exports = db => {
290
290
  }
291
291
 
292
292
  const hasChanged = [addedForeignKeys, updatedForeignKeys, removedForeignKeys].some(
293
- arr => arr.length > 0
293
+ (arr) => arr.length > 0
294
294
  );
295
295
 
296
296
  return {
@@ -353,7 +353,7 @@ module.exports = db => {
353
353
  }
354
354
  }
355
355
 
356
- const hasChanged = [addedTables, updatedTables, removedTables].some(arr => arr.length > 0);
356
+ const hasChanged = [addedTables, updatedTables, removedTables].some((arr) => arr.length > 0);
357
357
 
358
358
  return {
359
359
  status: hasChanged ? statuses.CHANGED : statuses.UNCHANGED,
@@ -10,7 +10,7 @@ const { metadataToSchema } = require('./schema');
10
10
  /**
11
11
  * @type {import('.').default}
12
12
  */
13
- const createSchemaProvider = db => {
13
+ const createSchemaProvider = (db) => {
14
14
  const schema = metadataToSchema(db.metadata);
15
15
 
16
16
  return {
@@ -87,7 +87,6 @@ const createSchemaProvider = db => {
87
87
  }
88
88
 
89
89
  debug('Schema unchanged');
90
- return;
91
90
  },
92
91
  };
93
92
  };
@@ -17,7 +17,7 @@ const createColumn = (name, attribute) => {
17
17
  };
18
18
  };
19
19
 
20
- const createTable = meta => {
20
+ const createTable = (meta) => {
21
21
  const table = {
22
22
  name: meta.tableName,
23
23
  indexes: meta.indexes || [],
@@ -96,7 +96,7 @@ const createTable = meta => {
96
96
  return table;
97
97
  };
98
98
 
99
- const getColumnType = attribute => {
99
+ const getColumnType = (attribute) => {
100
100
  if (attribute.columnType) {
101
101
  return attribute.columnType;
102
102
  }
@@ -182,7 +182,7 @@ const getColumnType = attribute => {
182
182
  }
183
183
  };
184
184
 
185
- const metadataToSchema = metadata => {
185
+ const metadataToSchema = (metadata) => {
186
186
  const schema = {
187
187
  tables: [],
188
188
  addTable(table) {
@@ -191,7 +191,7 @@ const metadataToSchema = metadata => {
191
191
  },
192
192
  };
193
193
 
194
- metadata.forEach(metadata => {
194
+ metadata.forEach((metadata) => {
195
195
  schema.addTable(createTable(metadata));
196
196
  });
197
197
 
@@ -4,11 +4,11 @@ const crypto = require('crypto');
4
4
 
5
5
  const TABLE_NAME = 'strapi_database_schema';
6
6
 
7
- module.exports = db => {
7
+ module.exports = (db) => {
8
8
  const hasSchemaTable = () => db.getSchemaConnection().hasTable(TABLE_NAME);
9
9
 
10
10
  const createSchemaTable = () => {
11
- return db.getSchemaConnection().createTable(TABLE_NAME, t => {
11
+ return db.getSchemaConnection().createTable(TABLE_NAME, (t) => {
12
12
  t.increments('id');
13
13
  t.json('schema');
14
14
  t.datetime('time', { useTz: false });
@@ -46,10 +46,7 @@ module.exports = db => {
46
46
  },
47
47
 
48
48
  hashSchema(schema) {
49
- return crypto
50
- .createHash('md5')
51
- .update(JSON.stringify(schema))
52
- .digest('hex');
49
+ return crypto.createHash('md5').update(JSON.stringify(schema)).digest('hex');
53
50
  },
54
51
 
55
52
  async add(schema) {
@@ -25,10 +25,10 @@ const STRING_TYPES = ['string', 'text', 'uid', 'email', 'enumeration', 'richtext
25
25
  const NUMBER_TYPES = ['biginteger', 'integer', 'decimal', 'float'];
26
26
 
27
27
  module.exports = {
28
- isString: type => STRING_TYPES.includes(type),
29
- isNumber: type => NUMBER_TYPES.includes(type),
30
- isScalar: type => SCALAR_TYPES.includes(type),
31
- isComponent: type => type === 'component',
32
- isDynamicZone: type => type === 'dynamiczone',
33
- isRelation: type => type === 'relation',
28
+ isString: (type) => STRING_TYPES.includes(type),
29
+ isNumber: (type) => NUMBER_TYPES.includes(type),
30
+ isScalar: (type) => SCALAR_TYPES.includes(type),
31
+ isComponent: (type) => type === 'component',
32
+ isDynamicZone: (type) => type === 'dynamiczone',
33
+ isRelation: (type) => type === 'relation',
34
34
  };
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const transformAttribute = attribute => {
3
+ const transformAttribute = (attribute) => {
4
4
  switch (attribute.type) {
5
5
  case 'media': {
6
6
  return {
@@ -17,8 +17,8 @@ const transformAttribute = attribute => {
17
17
  };
18
18
 
19
19
  // TODO: model logic outside DB
20
- const transformContentTypes = contentTypes => {
21
- return contentTypes.map(contentType => {
20
+ const transformContentTypes = (contentTypes) => {
21
+ return contentTypes.map((contentType) => {
22
22
  const model = {
23
23
  ...contentType,
24
24
  // reuse new model def
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@strapi/database",
3
- "version": "4.3.4",
3
+ "version": "4.3.7",
4
4
  "description": "Strapi's database layer",
5
5
  "homepage": "https://strapi.io",
6
6
  "bugs": {
@@ -31,7 +31,7 @@
31
31
  "test:unit": "jest --verbose"
32
32
  },
33
33
  "dependencies": {
34
- "date-fns": "2.28.0",
34
+ "date-fns": "2.29.2",
35
35
  "debug": "4.3.1",
36
36
  "fs-extra": "10.0.0",
37
37
  "knex": "1.0.7",
@@ -42,5 +42,5 @@
42
42
  "node": ">=14.19.1 <=16.x.x",
43
43
  "npm": ">=6.0.0"
44
44
  },
45
- "gitHead": "28a2a00db8234ffcf644661c4c8092aa82f8c119"
45
+ "gitHead": "73f523b98322cea8992c72977b94a73a624d2e79"
46
46
  }
package/lib/errors.js DELETED
@@ -1,56 +0,0 @@
1
- 'use strict';
2
-
3
- /* DatabaseError */
4
- class DatabaseError extends Error {
5
- constructor(message, details = {}) {
6
- super();
7
- this.name = 'DatabaseError';
8
- this.message = message || 'A database error occured';
9
- this.details = details;
10
- }
11
- }
12
-
13
- class NotNullConstraint extends DatabaseError {
14
- constructor({ column = '' } = {}) {
15
- super();
16
- this.name = 'NotNullConstraint';
17
- this.message = `Not null constraint violation${column ? ` on column ${column}` : ''}.`;
18
- this.details = { column };
19
- this.stack = '';
20
- }
21
- }
22
-
23
- class InvalidTimeError extends DatabaseError {
24
- constructor(message) {
25
- super();
26
- this.name = 'InvalidTimeFormat';
27
- this.message = message || 'Invalid time format, expected HH:mm:ss.SSS';
28
- this.details = {};
29
- }
30
- }
31
-
32
- class InvalidDateError extends DatabaseError {
33
- constructor(message) {
34
- super();
35
- this.name = 'InvalidTimeFormat';
36
- this.message = message || 'Invalid date format, expected YYYY-MM-DD';
37
- this.details = {};
38
- }
39
- }
40
-
41
- class InvalidDateTimeError extends DatabaseError {
42
- constructor(message) {
43
- super();
44
- this.name = 'InvalidTimeFormat';
45
- this.message = message || 'Invalid datetime format, expected a timestamp or an ISO date';
46
- this.details = {};
47
- }
48
- }
49
-
50
- module.exports = {
51
- DatabaseError,
52
- NotNullConstraint,
53
- InvalidTimeError,
54
- InvalidDateError,
55
- InvalidDateTimeError,
56
- };
package/lib/fields.js DELETED
@@ -1,231 +0,0 @@
1
- 'use strict';
2
-
3
- const _ = require('lodash/fp');
4
- const dateFns = require('date-fns');
5
- const { InvalidTimeError, InvalidDateError, InvalidDateTimeError } = require('./errors');
6
-
7
- class Field {
8
- constructor(config) {
9
- this.config = config;
10
- }
11
-
12
- toDB(value) {
13
- return value;
14
- }
15
-
16
- fromDB(value) {
17
- return value;
18
- }
19
- }
20
-
21
- class StringField extends Field {
22
- toDB(value) {
23
- return _.toString(value);
24
- }
25
-
26
- fromDB(value) {
27
- return _.toString(value);
28
- }
29
- }
30
-
31
- class JSONField extends Field {
32
- toDB(value) {
33
- return JSON.stringify(value);
34
- }
35
-
36
- fromDB(value) {
37
- if (typeof value === 'string') return JSON.parse(value);
38
- return value;
39
- }
40
- }
41
-
42
- class BooleanField extends Field {
43
- toDB(value) {
44
- if (typeof value === 'boolean') return value;
45
-
46
- if (['true', 't', '1', 1].includes(value)) {
47
- return true;
48
- }
49
-
50
- if (['false', 'f', '0', 0].includes(value)) {
51
- return false;
52
- }
53
-
54
- return Boolean(value);
55
- }
56
-
57
- fromDB(value) {
58
- if (typeof value === 'boolean') {
59
- return value;
60
- }
61
-
62
- const strVal = _.toString(value);
63
-
64
- if (strVal === '1') {
65
- return true;
66
- } else if (strVal === '0') {
67
- return false;
68
- } else {
69
- return null;
70
- }
71
- }
72
- }
73
-
74
- class NumberField extends Field {
75
- toDB(value) {
76
- const numberValue = _.toNumber(value);
77
-
78
- if (Number.isNaN(numberValue)) {
79
- throw new Error(`Expected a valid Number, got ${value}`);
80
- }
81
-
82
- return numberValue;
83
- }
84
-
85
- fromDB(value) {
86
- return _.toNumber(value);
87
- }
88
- }
89
-
90
- class BigIntegerField extends NumberField {
91
- toDB(value) {
92
- return _.toString(value);
93
- }
94
-
95
- fromDB(value) {
96
- return _.toString(value);
97
- }
98
- }
99
-
100
- const timeRegex = new RegExp('^(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(.[0-9]{1,3})?$');
101
- const dateRegex = /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/;
102
- const partialDateRegex = /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])/g;
103
-
104
- const parseTime = value => {
105
- if (dateFns.isDate(value)) return dateFns.format(value, 'HH:mm:ss.SSS');
106
-
107
- if (typeof value !== 'string') {
108
- throw new InvalidTimeError(`Expected a string, got a ${typeof value}`);
109
- }
110
- const result = value.match(timeRegex);
111
-
112
- if (result === null) {
113
- throw new InvalidTimeError('Invalid time format, expected HH:mm:ss.SSS');
114
- }
115
-
116
- const [, hours, minutes, seconds, fraction = '.000'] = result;
117
- const fractionPart = _.padCharsEnd('0', 3, fraction.slice(1));
118
-
119
- return `${hours}:${minutes}:${seconds}.${fractionPart}`;
120
- };
121
-
122
- const parseDate = value => {
123
- const found = _.isString(value) ? value.match(partialDateRegex) || [] : [];
124
- const extractedValue = found[0];
125
-
126
- if (extractedValue && !dateRegex.test(value)) {
127
- // TODO V5: throw an error when format yyyy-MM-dd is not respected
128
- // throw new InvalidDateError(`Invalid format, expected yyyy-MM-dd`);
129
- process.emitWarning(
130
- `[deprecated] Using a date format other than YYYY-MM-DD will be removed in future versions. Date received: ${value}. Date stored: ${extractedValue}.`
131
- );
132
- }
133
-
134
- let date = dateFns.parseISO(extractedValue);
135
- if (!dateFns.isValid(date)) {
136
- throw new InvalidDateError(`Invalid date`);
137
- }
138
-
139
- return extractedValue;
140
- };
141
-
142
- const parseDateTimeOrTimestamp = value => {
143
- if (dateFns.isDate(value)) return value;
144
- try {
145
- const date = dateFns.parseISO(value);
146
- if (dateFns.isValid(date)) return date;
147
-
148
- const milliUnixDate = dateFns.parse(value, 'T', new Date());
149
- if (dateFns.isValid(milliUnixDate)) return milliUnixDate;
150
-
151
- throw new InvalidDateTimeError(`Invalid format, expected a timestamp or an ISO date`);
152
- } catch (error) {
153
- throw new InvalidDateTimeError(`Invalid format, expected a timestamp or an ISO date`);
154
- }
155
- };
156
-
157
- class DateField extends Field {
158
- toDB(value) {
159
- return parseDate(value);
160
- }
161
-
162
- fromDB(value) {
163
- return value;
164
- }
165
- }
166
- class DatetimeField extends Field {
167
- toDB(value) {
168
- return parseDateTimeOrTimestamp(value);
169
- }
170
-
171
- fromDB(value) {
172
- const cast = new Date(value);
173
- return dateFns.isValid(cast) ? cast.toISOString() : null;
174
- }
175
- }
176
-
177
- class TimeField extends Field {
178
- toDB(value) {
179
- return parseTime(value);
180
- }
181
-
182
- fromDB(value) {
183
- // make sure that's a string with valid format ?
184
- return value;
185
- }
186
- }
187
- class TimestampField extends Field {
188
- toDB(value) {
189
- return parseDateTimeOrTimestamp(value);
190
- }
191
-
192
- fromDB(value) {
193
- const cast = new Date(value);
194
- return dateFns.isValid(cast) ? dateFns.format(cast, 'T') : null;
195
- }
196
- }
197
-
198
- const typeToFieldMap = {
199
- increments: Field,
200
- password: StringField,
201
- email: StringField,
202
- string: StringField,
203
- uid: StringField,
204
- richtext: StringField,
205
- text: StringField,
206
- enumeration: StringField,
207
- json: JSONField,
208
- biginteger: BigIntegerField,
209
- integer: NumberField,
210
- float: NumberField,
211
- decimal: NumberField,
212
- date: DateField,
213
- time: TimeField,
214
- datetime: DatetimeField,
215
- timestamp: TimestampField,
216
- boolean: BooleanField,
217
- };
218
-
219
- const createField = attribute => {
220
- const { type } = attribute;
221
-
222
- if (_.has(type, typeToFieldMap)) {
223
- return new typeToFieldMap[type]({});
224
- }
225
-
226
- throw new Error(`Undefined field for type ${type}`);
227
- };
228
-
229
- module.exports = {
230
- createField,
231
- };