@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,19 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @typedef {import(".").Subscriber } Subscriber
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* For each model try to run it's lifecycles function if any is defined
|
|
9
|
+
* @type {Subscriber}
|
|
10
|
+
*/
|
|
11
|
+
const modelsLifecyclesSubscriber = async event => {
|
|
12
|
+
const { model } = event;
|
|
13
|
+
|
|
14
|
+
if (event.action in model.lifecycles) {
|
|
15
|
+
await model.lifecycles[event.action](event);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
module.exports = modelsLifecyclesSubscriber;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @typedef {import(".").Subscriber } Subscriber
|
|
7
|
+
* @typedef { import("../").Event } Event
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// NOTE: we could add onCreate & onUpdate on field level to do this instead
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @type {Subscriber}
|
|
14
|
+
*/
|
|
15
|
+
const timestampsLifecyclesSubscriber = {
|
|
16
|
+
/**
|
|
17
|
+
* Init createdAt & updatedAt before create
|
|
18
|
+
* @param {Event} event
|
|
19
|
+
*/
|
|
20
|
+
beforeCreate(event) {
|
|
21
|
+
const { data } = event.params;
|
|
22
|
+
|
|
23
|
+
const now = new Date();
|
|
24
|
+
_.defaults(data, { createdAt: now, updatedAt: now });
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Init createdAt & updatedAt before create
|
|
29
|
+
* @param {Event} event
|
|
30
|
+
*/
|
|
31
|
+
beforeCreateMany(event) {
|
|
32
|
+
const { data } = event.params;
|
|
33
|
+
|
|
34
|
+
const now = new Date();
|
|
35
|
+
if (_.isArray(data)) {
|
|
36
|
+
data.forEach(data => _.defaults(data, { createdAt: now, updatedAt: now }));
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Update updatedAt before update
|
|
42
|
+
* @param {Event} event
|
|
43
|
+
*/
|
|
44
|
+
beforeUpdate(event) {
|
|
45
|
+
const { data } = event.params;
|
|
46
|
+
|
|
47
|
+
const now = new Date();
|
|
48
|
+
_.assign(data, { updatedAt: now });
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Update updatedAt before update
|
|
53
|
+
* @param {Event} event
|
|
54
|
+
*/
|
|
55
|
+
beforeUpdateMany(event) {
|
|
56
|
+
const { data } = event.params;
|
|
57
|
+
|
|
58
|
+
const now = new Date();
|
|
59
|
+
if (_.isArray(data)) {
|
|
60
|
+
data.forEach(data => _.assign(data, { updatedAt: now }));
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
module.exports = timestampsLifecyclesSubscriber;
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash/fp');
|
|
4
|
+
|
|
5
|
+
const types = require('../types');
|
|
6
|
+
const { createRelation } = require('./relations');
|
|
7
|
+
|
|
8
|
+
class Metadata extends Map {
|
|
9
|
+
add(meta) {
|
|
10
|
+
return this.set(meta.uid, meta);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// TODO: check if there isn't an attribute with an id already
|
|
15
|
+
/**
|
|
16
|
+
* Create Metadata from models configurations
|
|
17
|
+
* @param {object[]} models
|
|
18
|
+
* @returns {Metadata}
|
|
19
|
+
*/
|
|
20
|
+
const createMetadata = (models = []) => {
|
|
21
|
+
const metadata = new Metadata();
|
|
22
|
+
|
|
23
|
+
// init pass
|
|
24
|
+
for (const model of _.cloneDeep(models)) {
|
|
25
|
+
metadata.add({
|
|
26
|
+
singularName: model.singularName,
|
|
27
|
+
uid: model.uid,
|
|
28
|
+
tableName: model.tableName,
|
|
29
|
+
attributes: {
|
|
30
|
+
id: {
|
|
31
|
+
type: 'increments',
|
|
32
|
+
},
|
|
33
|
+
...model.attributes,
|
|
34
|
+
},
|
|
35
|
+
lifecycles: model.lifecycles || {},
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// build compos / relations
|
|
40
|
+
for (const meta of metadata.values()) {
|
|
41
|
+
if (hasComponentsOrDz(meta)) {
|
|
42
|
+
const compoLinkModelMeta = createCompoLinkModelMeta(meta);
|
|
43
|
+
meta.componentLink = compoLinkModelMeta;
|
|
44
|
+
metadata.add(compoLinkModelMeta);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
for (const [attributeName, attribute] of Object.entries(meta.attributes)) {
|
|
48
|
+
try {
|
|
49
|
+
if (types.isComponent(attribute.type)) {
|
|
50
|
+
createComponent(attributeName, attribute, meta, metadata);
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (types.isDynamicZone(attribute.type)) {
|
|
55
|
+
createDynamicZone(attributeName, attribute, meta, metadata);
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (types.isRelation(attribute.type)) {
|
|
60
|
+
createRelation(attributeName, attribute, meta, metadata);
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
createAttribute(attributeName, attribute, meta, metadata);
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.log(error);
|
|
67
|
+
throw new Error(
|
|
68
|
+
`Error on attribute ${attributeName} in model ${meta.singularName}(${meta.uid}): ${error.message}`
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
for (const meta of metadata.values()) {
|
|
75
|
+
const columnToAttribute = Object.keys(meta.attributes).reduce((acc, key) => {
|
|
76
|
+
const attribute = meta.attributes[key];
|
|
77
|
+
return Object.assign(acc, { [attribute.columnName || key]: key });
|
|
78
|
+
}, {});
|
|
79
|
+
|
|
80
|
+
meta.columnToAttribute = columnToAttribute;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return metadata;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const hasComponentsOrDz = model => {
|
|
87
|
+
return Object.values(model.attributes).some(
|
|
88
|
+
({ type }) => types.isComponent(type) || types.isDynamicZone(type)
|
|
89
|
+
);
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
// NOTE: we might just move the compo logic outside this layer too at some point
|
|
93
|
+
const createCompoLinkModelMeta = baseModelMeta => {
|
|
94
|
+
return {
|
|
95
|
+
// TODO: make sure there can't be any conflicts with a prefix
|
|
96
|
+
// singularName: 'compo',
|
|
97
|
+
uid: `${baseModelMeta.tableName}_components`,
|
|
98
|
+
tableName: `${baseModelMeta.tableName}_components`,
|
|
99
|
+
attributes: {
|
|
100
|
+
id: {
|
|
101
|
+
type: 'increments',
|
|
102
|
+
},
|
|
103
|
+
entity_id: {
|
|
104
|
+
type: 'integer',
|
|
105
|
+
column: {
|
|
106
|
+
unsigned: true,
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
component_id: {
|
|
110
|
+
type: 'integer',
|
|
111
|
+
column: {
|
|
112
|
+
unsigned: true,
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
component_type: {
|
|
116
|
+
type: 'string',
|
|
117
|
+
},
|
|
118
|
+
field: {
|
|
119
|
+
type: 'string',
|
|
120
|
+
},
|
|
121
|
+
order: {
|
|
122
|
+
type: 'integer',
|
|
123
|
+
column: {
|
|
124
|
+
unsigned: true,
|
|
125
|
+
defaultTo: 0,
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
indexes: [
|
|
130
|
+
{
|
|
131
|
+
name: `${baseModelMeta.tableName}_field_index`,
|
|
132
|
+
columns: ['field'],
|
|
133
|
+
type: null,
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
name: `${baseModelMeta.tableName}_component_type_index`,
|
|
137
|
+
columns: ['component_type'],
|
|
138
|
+
type: null,
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
name: `${baseModelMeta.tableName}_entity_fk`,
|
|
142
|
+
columns: ['entity_id'],
|
|
143
|
+
},
|
|
144
|
+
],
|
|
145
|
+
foreignKeys: [
|
|
146
|
+
{
|
|
147
|
+
name: `${baseModelMeta.tableName}_entity_fk`,
|
|
148
|
+
columns: ['entity_id'],
|
|
149
|
+
referencedColumns: ['id'],
|
|
150
|
+
referencedTable: baseModelMeta.tableName,
|
|
151
|
+
onDelete: 'CASCADE',
|
|
152
|
+
},
|
|
153
|
+
],
|
|
154
|
+
};
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
const createDynamicZone = (attributeName, attribute, meta) => {
|
|
158
|
+
Object.assign(attribute, {
|
|
159
|
+
type: 'relation',
|
|
160
|
+
relation: 'morphToMany',
|
|
161
|
+
// TODO: handle restrictions at some point
|
|
162
|
+
// target: attribute.components,
|
|
163
|
+
joinTable: {
|
|
164
|
+
name: meta.componentLink.tableName,
|
|
165
|
+
joinColumn: {
|
|
166
|
+
name: 'entity_id',
|
|
167
|
+
referencedColumn: 'id',
|
|
168
|
+
},
|
|
169
|
+
morphColumn: {
|
|
170
|
+
idColumn: {
|
|
171
|
+
name: 'component_id',
|
|
172
|
+
referencedColumn: 'id',
|
|
173
|
+
},
|
|
174
|
+
typeColumn: {
|
|
175
|
+
name: 'component_type',
|
|
176
|
+
},
|
|
177
|
+
typeField: '__component',
|
|
178
|
+
},
|
|
179
|
+
on: {
|
|
180
|
+
field: attributeName,
|
|
181
|
+
},
|
|
182
|
+
orderBy: {
|
|
183
|
+
order: 'asc',
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
});
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
const createComponent = (attributeName, attribute, meta) => {
|
|
190
|
+
Object.assign(attribute, {
|
|
191
|
+
type: 'relation',
|
|
192
|
+
relation: attribute.repeatable === true ? 'oneToMany' : 'oneToOne',
|
|
193
|
+
target: attribute.component,
|
|
194
|
+
joinTable: {
|
|
195
|
+
name: meta.componentLink.tableName,
|
|
196
|
+
joinColumn: {
|
|
197
|
+
name: 'entity_id',
|
|
198
|
+
referencedColumn: 'id',
|
|
199
|
+
},
|
|
200
|
+
inverseJoinColumn: {
|
|
201
|
+
name: 'component_id',
|
|
202
|
+
referencedColumn: 'id',
|
|
203
|
+
},
|
|
204
|
+
on: {
|
|
205
|
+
field: attributeName,
|
|
206
|
+
},
|
|
207
|
+
orderBy: {
|
|
208
|
+
order: 'asc',
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
});
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
const createAttribute = (attributeName, attribute) => {
|
|
215
|
+
const columnName = _.snakeCase(attributeName);
|
|
216
|
+
Object.assign(attribute, { columnName });
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
module.exports = createMetadata;
|