@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.
- package/jest.config.js +1 -1
- package/lib/__tests__/lifecycles.test.js +1 -1
- package/lib/connection.js +4 -4
- package/lib/dialects/dialect.js +12 -2
- package/lib/dialects/index.js +2 -2
- package/lib/dialects/mysql/index.js +2 -2
- package/lib/dialects/mysql/schema-inspector.js +12 -16
- package/lib/dialects/postgresql/index.js +2 -2
- package/lib/dialects/postgresql/schema-inspector.js +30 -25
- package/lib/dialects/sqlite/index.js +9 -1
- package/lib/dialects/sqlite/schema-inspector.js +5 -5
- package/lib/entity-manager.js +46 -72
- package/lib/entity-repository.js +1 -1
- package/lib/errors/database.js +12 -0
- package/lib/errors/index.js +15 -0
- package/lib/errors/invalid-date.js +14 -0
- package/lib/errors/invalid-datetime.js +14 -0
- package/lib/errors/invalid-time.js +14 -0
- package/lib/errors/not-null.js +15 -0
- package/lib/fields/biginteger.js +17 -0
- package/lib/fields/boolean.js +39 -0
- package/lib/fields/date.js +16 -0
- package/lib/fields/datetime.js +19 -0
- package/lib/fields/field.js +17 -0
- package/lib/{fields.d.ts → fields/index.d.ts} +0 -0
- package/lib/fields/index.js +49 -0
- package/lib/fields/json.js +16 -0
- package/lib/fields/number.js +23 -0
- package/lib/fields/shared/parsers.js +69 -0
- package/lib/fields/string.js +17 -0
- package/lib/fields/time.js +17 -0
- package/lib/fields/timestamp.js +19 -0
- package/lib/index.js +1 -1
- package/lib/lifecycles/index.js +2 -2
- package/lib/lifecycles/subscribers/models-lifecycles.js +1 -1
- package/lib/lifecycles/subscribers/timestamps.js +2 -2
- package/lib/metadata/index.js +2 -2
- package/lib/metadata/relations.js +18 -15
- package/lib/migrations/index.js +5 -5
- package/lib/migrations/storage.js +4 -11
- package/lib/query/helpers/join.js +5 -5
- package/lib/query/helpers/order-by.js +1 -1
- package/lib/query/helpers/populate.js +43 -51
- package/lib/query/helpers/search.js +5 -5
- package/lib/query/helpers/transform.js +2 -2
- package/lib/query/helpers/where.js +17 -17
- package/lib/query/query-builder.js +11 -14
- package/lib/schema/builder.js +28 -17
- package/lib/schema/diff.js +15 -15
- package/lib/schema/index.js +1 -2
- package/lib/schema/schema.js +4 -4
- package/lib/schema/storage.js +3 -6
- package/lib/types/index.js +6 -6
- package/lib/utils/content-types.js +3 -3
- package/package.json +3 -3
- package/lib/errors.js +0 -56
- package/lib/fields.js +0 -231
package/lib/schema/builder.js
CHANGED
|
@@ -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 =>
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
package/lib/schema/diff.js
CHANGED
|
@@ -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
|
|
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,
|
package/lib/schema/index.js
CHANGED
|
@@ -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
|
};
|
package/lib/schema/schema.js
CHANGED
|
@@ -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
|
|
package/lib/schema/storage.js
CHANGED
|
@@ -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) {
|
package/lib/types/index.js
CHANGED
|
@@ -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.
|
|
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.
|
|
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": "
|
|
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
|
-
};
|