@live-change/relations-plugin 0.1.8 → 0.1.12
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/index.js +3 -1
- package/itemOf.js +235 -0
- package/package.json +2 -2
- package/propertyOf.js +109 -126
- package/utils.js +114 -0
package/index.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
const propertyOf = require('./propertyOf.js')
|
|
2
|
+
const itemOf = require('./itemOf.js')
|
|
2
3
|
|
|
3
4
|
module.exports = function(app, services) {
|
|
4
5
|
|
|
5
6
|
app.defaultProcessors.push(propertyOf)
|
|
7
|
+
app.defaultProcessors.push(itemOf)
|
|
6
8
|
}
|
|
7
9
|
|
|
8
|
-
module.exports.processors = [ propertyOf ]
|
|
10
|
+
module.exports.processors = [ propertyOf, itemOf ]
|
package/itemOf.js
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
const App = require("@live-change/framework")
|
|
2
|
+
const { PropertyDefinition, ViewDefinition, IndexDefinition, ActionDefinition, EventDefinition } = App
|
|
3
|
+
|
|
4
|
+
const {
|
|
5
|
+
extractIdParts, extractRange, extractIdentifiers, extractObjectData, defineProperties, defineIndex,
|
|
6
|
+
processModelsAnnotation
|
|
7
|
+
} = require('./utils.js')
|
|
8
|
+
|
|
9
|
+
function defineView(config, context) {
|
|
10
|
+
const { service, modelRuntime, otherPropertyNames, joinedOthersPropertyName, joinedOthersClassName,
|
|
11
|
+
modelName, others, model } = context
|
|
12
|
+
const indexName = 'by'+context.joinedOthersClassName
|
|
13
|
+
const viewProperties = {}
|
|
14
|
+
for (let i = 0; i < others.length; i++) {
|
|
15
|
+
viewProperties[otherPropertyNames[i]] = new PropertyDefinition({
|
|
16
|
+
type: others[i],
|
|
17
|
+
validation: ['nonEmpty']
|
|
18
|
+
})
|
|
19
|
+
}
|
|
20
|
+
const viewName = joinedOthersPropertyName + 'Owned' + modelName + 's'
|
|
21
|
+
service.views[viewName] = new ViewDefinition({
|
|
22
|
+
name: viewName,
|
|
23
|
+
properties: {
|
|
24
|
+
...viewProperties,
|
|
25
|
+
...App.utils.rangeProperties
|
|
26
|
+
},
|
|
27
|
+
returns: {
|
|
28
|
+
type: Array,
|
|
29
|
+
of: {
|
|
30
|
+
type: model
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
access: config.readAccess,
|
|
34
|
+
daoPath(properties, { client, context }) {
|
|
35
|
+
const idParts = extractIdParts(otherPropertyNames, properties)
|
|
36
|
+
const range = extractRange(properties)
|
|
37
|
+
const path = modelRuntime().sortedIndexRangePath(indexName, idParts, range)
|
|
38
|
+
return path
|
|
39
|
+
}
|
|
40
|
+
})
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function defineCreatedEvent(config, context) {
|
|
44
|
+
const {
|
|
45
|
+
service, modelRuntime, joinedOthersPropertyName, modelName, modelPropertyName
|
|
46
|
+
} = context
|
|
47
|
+
const eventName = joinedOthersPropertyName + 'Owned' + modelName + 'Created'
|
|
48
|
+
service.events[eventName] = new EventDefinition({
|
|
49
|
+
name: eventName,
|
|
50
|
+
execute(properties) {
|
|
51
|
+
const id = properties[modelPropertyName]
|
|
52
|
+
return modelRuntime().create({ ...properties.data, ...properties.identifiers, id })
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function defineCreateAction(config, context) {
|
|
58
|
+
const {
|
|
59
|
+
service, app, model, defaults, modelPropertyName, modelRuntime,
|
|
60
|
+
otherPropertyNames, joinedOthersPropertyName, modelName, writeableProperties, joinedOthersClassName
|
|
61
|
+
} = context
|
|
62
|
+
const eventName = joinedOthersPropertyName + 'Owned' + modelName + 'Created'
|
|
63
|
+
const actionName = 'set' + joinedOthersClassName + 'Owned' + modelName
|
|
64
|
+
service.actions[actionName] = new ActionDefinition({
|
|
65
|
+
name: actionName,
|
|
66
|
+
properties: {
|
|
67
|
+
...(model.properties)
|
|
68
|
+
},
|
|
69
|
+
access: config.createAccess || config.writeAccess,
|
|
70
|
+
skipValidation: true,
|
|
71
|
+
//queuedBy: otherPropertyNames,
|
|
72
|
+
waitForEvents: true,
|
|
73
|
+
async execute(properties, { client, service }, emit) {
|
|
74
|
+
const id = properties[modelPropertyName] || app.generateUid()
|
|
75
|
+
const entity = await modelRuntime().get(id)
|
|
76
|
+
if(entity) throw 'exists'
|
|
77
|
+
const identifiers = extractIdentifiers(otherPropertyNames, properties)
|
|
78
|
+
const data = extractObjectData(writeableProperties, properties, defaults)
|
|
79
|
+
await App.validation.validate(data, validators, { source: action, action, service, app, client })
|
|
80
|
+
emit({
|
|
81
|
+
type: eventName,
|
|
82
|
+
[modelPropertyName]: id,
|
|
83
|
+
identifiers, data
|
|
84
|
+
})
|
|
85
|
+
}
|
|
86
|
+
})
|
|
87
|
+
const action = service.actions[actionName]
|
|
88
|
+
const validators = App.validation.getValidators(action, service, action)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async function defineUpdatedEvent(config, context) {
|
|
92
|
+
const {
|
|
93
|
+
service, modelRuntime, joinedOthersPropertyName, modelName, modelPropertyName
|
|
94
|
+
} = context
|
|
95
|
+
const eventName = joinedOthersPropertyName + 'Owned' + modelName + 'Updated'
|
|
96
|
+
service.events[eventName] = new EventDefinition({
|
|
97
|
+
name: eventName,
|
|
98
|
+
execute(properties) {
|
|
99
|
+
const id = properties[modelPropertyName]
|
|
100
|
+
return modelRuntime().update(id, { ...properties.data, ...properties.identifiers, id })
|
|
101
|
+
}
|
|
102
|
+
})
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async function defineUpdateAction(config, context) {
|
|
106
|
+
const {
|
|
107
|
+
service, app, model, modelRuntime, modelPropertyName,
|
|
108
|
+
otherPropertyNames, joinedOthersPropertyName, modelName, writeableProperties, joinedOthersClassName
|
|
109
|
+
} = context
|
|
110
|
+
const eventName = joinedOthersPropertyName + 'Owned' + modelName + 'Updated'
|
|
111
|
+
const actionName = 'update' + joinedOthersClassName + 'Owned' + modelName
|
|
112
|
+
service.actions[actionName] = new ActionDefinition({
|
|
113
|
+
name: actionName,
|
|
114
|
+
properties: {
|
|
115
|
+
...(model.properties)
|
|
116
|
+
},
|
|
117
|
+
access: config.updateAccess || config.writeAccess,
|
|
118
|
+
skipValidation: true,
|
|
119
|
+
//queuedBy: otherPropertyNames,
|
|
120
|
+
waitForEvents: true,
|
|
121
|
+
async execute(properties, {client, service}, emit) {
|
|
122
|
+
const id = properties[modelPropertyName]
|
|
123
|
+
const entity = await modelRuntime().get(id)
|
|
124
|
+
if(!entity) throw 'not_found'
|
|
125
|
+
const entityIdParts = extractIdParts(otherPropertyNames, entity)
|
|
126
|
+
const idParts = extractIdParts(otherPropertyNames, properties)
|
|
127
|
+
if(JSON.stringify(entityIdParts) != JSON.stringify(idParts)) {
|
|
128
|
+
throw 'not_authorized'
|
|
129
|
+
}
|
|
130
|
+
const identifiers = extractIdentifiers(otherPropertyNames, properties)
|
|
131
|
+
const data = extractObjectData(writeableProperties, properties, entity)
|
|
132
|
+
await App.validation.validate(data, validators, { source: action, action, service, app, client })
|
|
133
|
+
emit({
|
|
134
|
+
type: eventName,
|
|
135
|
+
[modelPropertyName]: id,
|
|
136
|
+
identifiers,
|
|
137
|
+
data
|
|
138
|
+
})
|
|
139
|
+
}
|
|
140
|
+
})
|
|
141
|
+
const action = service.actions[actionName]
|
|
142
|
+
const validators = App.validation.getValidators(action, service, action)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
async function defineDeletedEvent(config, context) {
|
|
146
|
+
const {
|
|
147
|
+
service, modelRuntime, joinedOthersPropertyName, modelName, modelPropertyName
|
|
148
|
+
} = context
|
|
149
|
+
const eventName = joinedOthersPropertyName + 'Owned' + modelName + 'Deleted'
|
|
150
|
+
service.events[eventName] = new EventDefinition({
|
|
151
|
+
name: eventName,
|
|
152
|
+
execute(properties) {
|
|
153
|
+
const id = properties[modelPropertyName]
|
|
154
|
+
return modelRuntime().delete(id)
|
|
155
|
+
}
|
|
156
|
+
})
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
async function defineDeleteAction(config, context) {
|
|
160
|
+
const {
|
|
161
|
+
service, app, model, modelRuntime, modelPropertyName,
|
|
162
|
+
otherPropertyNames, joinedOthersPropertyName, modelName, writeableProperties, joinedOthersClassName
|
|
163
|
+
} = context
|
|
164
|
+
const eventName = joinedOthersPropertyName + 'Owned' + modelName + 'Deleted'
|
|
165
|
+
const actionName = 'delete' + joinedOthersClassName + 'Owned' + modelName
|
|
166
|
+
service.actions[actionName] = new ActionDefinition({
|
|
167
|
+
name: actionName,
|
|
168
|
+
properties: {
|
|
169
|
+
...(model.properties)
|
|
170
|
+
},
|
|
171
|
+
access: config.deleteAccess || config.writeAccess,
|
|
172
|
+
skipValidation: true,
|
|
173
|
+
//queuedBy: otherPropertyNames,
|
|
174
|
+
waitForEvents: true,
|
|
175
|
+
async execute(properties, {client, service}, emit) {
|
|
176
|
+
const id = properties[modelPropertyName]
|
|
177
|
+
const entity = await modelRuntime().get(id)
|
|
178
|
+
if(!entity) throw new Error('not_found')
|
|
179
|
+
const entityIdParts = extractIdParts(otherPropertyNames, entity)
|
|
180
|
+
const idParts = extractIdParts(otherPropertyNames, properties)
|
|
181
|
+
if(JSON.stringify(entityIdParts) != JSON.stringify(idParts)) {
|
|
182
|
+
throw new Error('not_authorized')
|
|
183
|
+
}
|
|
184
|
+
emit({
|
|
185
|
+
type: eventName,
|
|
186
|
+
[modelPropertyName]: id
|
|
187
|
+
})
|
|
188
|
+
}
|
|
189
|
+
})
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function defineSortIndex(context, sortFields) {
|
|
193
|
+
if(!Array.isArray(sortFields)) sortFields = [sortFields]
|
|
194
|
+
console.log("DEFINE SORT INDEX", sortFields)
|
|
195
|
+
const sortFieldsUc = sortFields.map(fd=>fd.slice(0, 1).toUpperCase() + fd.slice(1))
|
|
196
|
+
const indexName = 'by' + context.joinedOthersClassName + sortFieldsUc.join('')
|
|
197
|
+
context.model.indexes[indexName] = new IndexDefinition({
|
|
198
|
+
property: [...context.otherPropertyNames, ...sortFields]
|
|
199
|
+
})
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
module.exports = function(service, app) {
|
|
203
|
+
processModelsAnnotation(service, app, 'itemOf', (config, context) => {
|
|
204
|
+
|
|
205
|
+
defineProperties(context.model, context.others, context.otherPropertyNames)
|
|
206
|
+
defineIndex(context.model, context.joinedOthersClassName, context.otherPropertyNames)
|
|
207
|
+
|
|
208
|
+
if(config.sortBy) {
|
|
209
|
+
for(const sortFields of config.sortBy) {
|
|
210
|
+
defineSortIndex(context, sortFields)
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if(config.readAccess) {
|
|
215
|
+
defineView(config, context)
|
|
216
|
+
}
|
|
217
|
+
/// TODO: multiple views with limited fields
|
|
218
|
+
|
|
219
|
+
defineCreatedEvent(config, context)
|
|
220
|
+
defineUpdatedEvent(config, context)
|
|
221
|
+
defineDeletedEvent(config, context)
|
|
222
|
+
|
|
223
|
+
if(config.setAccess || config.writeAccess) {
|
|
224
|
+
defineCreateAction(config, context)
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if(config.updateAccess || config.writeAccess) {
|
|
228
|
+
defineUpdateAction(config, context)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if(config.resetAccess || config.writeAccess) {
|
|
232
|
+
defineDeleteAction(config, context)
|
|
233
|
+
}
|
|
234
|
+
})
|
|
235
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@live-change/relations-plugin",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.12",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -21,6 +21,6 @@
|
|
|
21
21
|
"url": "https://www.viamage.com/"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@live-change/framework": "^0.5.
|
|
24
|
+
"@live-change/framework": "^0.5.14"
|
|
25
25
|
}
|
|
26
26
|
}
|
package/propertyOf.js
CHANGED
|
@@ -1,86 +1,63 @@
|
|
|
1
1
|
const App = require("@live-change/framework")
|
|
2
2
|
const { PropertyDefinition, ViewDefinition, IndexDefinition, ActionDefinition, EventDefinition } = App
|
|
3
3
|
|
|
4
|
+
const {
|
|
5
|
+
extractIdParts, extractIdentifiers, extractObjectData, defineProperties, defineIndex,
|
|
6
|
+
processModelsAnnotation, generateId
|
|
7
|
+
} = require('./utils.js')
|
|
4
8
|
|
|
5
|
-
function defineProperties(parents, model, parentPropertyNames) {
|
|
6
|
-
for (let i = 0; i < parents.length; i++) {
|
|
7
|
-
model.properties[parentPropertyNames[i]] = new PropertyDefinition({
|
|
8
|
-
type: parents[i],
|
|
9
|
-
validation: ['nonEmpty']
|
|
10
|
-
})
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
9
|
|
|
14
|
-
function
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
})
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function defineView(joinedParentsPropertyName, modelName, service, config, modelRuntime, parents, parentPropertyNames) {
|
|
10
|
+
function defineView(config, context) {
|
|
11
|
+
const { service, modelRuntime, otherPropertyNames, joinedOthersPropertyName, joinedOthersClassName,
|
|
12
|
+
modelName, others, model } = context
|
|
21
13
|
const viewProperties = {}
|
|
22
|
-
for (let i = 0; i <
|
|
23
|
-
viewProperties[
|
|
24
|
-
type:
|
|
14
|
+
for (let i = 0; i < others.length; i++) {
|
|
15
|
+
viewProperties[otherPropertyNames[i]] = new PropertyDefinition({
|
|
16
|
+
type: others[i],
|
|
25
17
|
validation: ['nonEmpty']
|
|
26
18
|
})
|
|
27
19
|
}
|
|
28
|
-
const viewName =
|
|
20
|
+
const viewName = config.name || ((config.prefix ? (prefix + joinedOthersClassName) : joinedOthersPropertyName) +
|
|
21
|
+
'Owned' + modelName + (config.suffix || ''))
|
|
29
22
|
service.views[viewName] = new ViewDefinition({
|
|
30
23
|
name: viewName,
|
|
31
24
|
properties: {
|
|
32
25
|
...viewProperties
|
|
33
26
|
},
|
|
34
|
-
|
|
27
|
+
returns: {
|
|
28
|
+
type: model,
|
|
29
|
+
},
|
|
30
|
+
access: config.access,
|
|
35
31
|
daoPath(properties, { client, context }) {
|
|
36
|
-
const idParts = extractIdParts(
|
|
32
|
+
const idParts = extractIdParts(otherPropertyNames, properties)
|
|
37
33
|
const id = idParts.length > 1 ? idParts.map(p => JSON.stringify(p)).join(':') : idParts[0]
|
|
38
|
-
const path = modelRuntime().path(id)
|
|
39
|
-
console.log("PROPERTY ID", id ,"PATH", path, "OF", properties)
|
|
40
|
-
//return modelRuntime().indexObjectPath('by' + parents.join('And'), idParts)
|
|
34
|
+
const path = config.fields ? modelRuntime().limitedPath(id, config.fields) : modelRuntime().path(id)
|
|
41
35
|
return path
|
|
42
36
|
}
|
|
43
37
|
})
|
|
44
38
|
}
|
|
45
39
|
|
|
46
|
-
function
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
return idParts
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function extractIdentifiers(parentPropertyNames, properties) {
|
|
55
|
-
const identifiers = {}
|
|
56
|
-
const idParts = []
|
|
57
|
-
for (const propertyName of parentPropertyNames) {
|
|
58
|
-
identifiers[propertyName] = properties[propertyName]
|
|
59
|
-
idParts.push(properties[propertyName])
|
|
60
|
-
}
|
|
61
|
-
identifiers.id = idParts.length > 1 ? idParts.map(p => JSON.stringify(p)).join(':') : idParts[0]
|
|
62
|
-
return identifiers
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function extractObjectData(writeableProperties, properties, defaults) {
|
|
66
|
-
let updateObject = {}
|
|
67
|
-
for (const propertyName of writeableProperties) {
|
|
68
|
-
if (properties.hasOwnProperty(propertyName)) {
|
|
69
|
-
newObject[propertyName] = properties[propertyName]
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
return App.utils.mergeDeep({}, defaults, updateObject)
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
async function defineSetAction(joinedParentsPropertyName, modelName, service, parentPropertyNames, modelRuntime, joinedParentsClassName, model, config, writeableProperties, defaults, app) {
|
|
76
|
-
const eventName = joinedParentsPropertyName + 'Owned' + modelName + 'Set'
|
|
40
|
+
async function defineSetEvent(config, context) {
|
|
41
|
+
const {
|
|
42
|
+
service, modelRuntime, joinedOthersPropertyName, modelName, otherPropertyNames
|
|
43
|
+
} = context
|
|
44
|
+
const eventName = joinedOthersPropertyName + 'Owned' + modelName + 'Set'
|
|
77
45
|
service.events[eventName] = new EventDefinition({
|
|
78
46
|
name: eventName,
|
|
79
47
|
execute(properties) {
|
|
80
|
-
|
|
48
|
+
const id = generateId(otherPropertyNames, properties.identifiers)
|
|
49
|
+
return modelRuntime().create({ ...properties.data, ...properties.identifiers, id })
|
|
81
50
|
}
|
|
82
51
|
})
|
|
83
|
-
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function defineSetAction(config, context) {
|
|
55
|
+
const {
|
|
56
|
+
service, app, model, defaults,
|
|
57
|
+
otherPropertyNames, joinedOthersPropertyName, modelName, writeableProperties, joinedOthersClassName
|
|
58
|
+
} = context
|
|
59
|
+
const eventName = joinedOthersPropertyName + 'Owned' + modelName + 'Set'
|
|
60
|
+
const actionName = 'set' + joinedOthersClassName + 'Owned' + modelName
|
|
84
61
|
service.actions[actionName] = new ActionDefinition({
|
|
85
62
|
name: actionName,
|
|
86
63
|
properties: {
|
|
@@ -88,12 +65,12 @@ async function defineSetAction(joinedParentsPropertyName, modelName, service, pa
|
|
|
88
65
|
},
|
|
89
66
|
access: config.setAccess || config.writeAccess,
|
|
90
67
|
skipValidation: true,
|
|
91
|
-
queuedBy:
|
|
68
|
+
queuedBy: otherPropertyNames,
|
|
92
69
|
waitForEvents: true,
|
|
93
70
|
async execute(properties, {client, service}, emit) {
|
|
94
|
-
const identifiers = extractIdentifiers(
|
|
71
|
+
const identifiers = extractIdentifiers(otherPropertyNames, properties)
|
|
95
72
|
const data = extractObjectData(writeableProperties, properties, defaults)
|
|
96
|
-
await App.validation.validate(data, validators, {source: action, action, service, app, client})
|
|
73
|
+
await App.validation.validate(data, validators, { source: action, action, service, app, client })
|
|
97
74
|
emit({
|
|
98
75
|
type: eventName,
|
|
99
76
|
identifiers, data
|
|
@@ -104,15 +81,27 @@ async function defineSetAction(joinedParentsPropertyName, modelName, service, pa
|
|
|
104
81
|
const validators = App.validation.getValidators(action, service, action)
|
|
105
82
|
}
|
|
106
83
|
|
|
107
|
-
async function
|
|
108
|
-
const
|
|
84
|
+
async function defineUpdateEvent(config, context) {
|
|
85
|
+
const {
|
|
86
|
+
service, modelRuntime, joinedOthersPropertyName, modelName, otherPropertyNames
|
|
87
|
+
} = context
|
|
88
|
+
const eventName = joinedOthersPropertyName + 'Owned' + modelName + 'Updated'
|
|
109
89
|
service.events[eventName] = new EventDefinition({
|
|
110
90
|
name: eventName,
|
|
111
91
|
execute(properties) {
|
|
112
|
-
|
|
92
|
+
const id = generateId(otherPropertyNames, properties.identifiers)
|
|
93
|
+
return modelRuntime().update(id, { ...properties.data, ...properties.identifiers })
|
|
113
94
|
}
|
|
114
95
|
})
|
|
115
|
-
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async function defineUpdateAction(config, context) {
|
|
99
|
+
const {
|
|
100
|
+
service, app, model, modelRuntime,
|
|
101
|
+
otherPropertyNames, joinedOthersPropertyName, modelName, writeableProperties, joinedOthersClassName
|
|
102
|
+
} = context
|
|
103
|
+
const eventName = joinedOthersPropertyName + 'Owned' + modelName + 'Updated'
|
|
104
|
+
const actionName = 'update' + joinedOthersClassName + 'Owned' + modelName
|
|
116
105
|
service.actions[actionName] = new ActionDefinition({
|
|
117
106
|
name: actionName,
|
|
118
107
|
properties: {
|
|
@@ -120,14 +109,15 @@ async function defineUpdateAction(joinedParentsPropertyName, modelName, service,
|
|
|
120
109
|
},
|
|
121
110
|
access: config.updateAccess || config.writeAccess,
|
|
122
111
|
skipValidation: true,
|
|
123
|
-
queuedBy:
|
|
112
|
+
queuedBy: otherPropertyNames,
|
|
124
113
|
waitForEvents: true,
|
|
125
114
|
async execute(properties, {client, service}, emit) {
|
|
126
|
-
const identifiers = extractIdentifiers(
|
|
127
|
-
const
|
|
115
|
+
const identifiers = extractIdentifiers(otherPropertyNames, properties)
|
|
116
|
+
const id = generateId(otherPropertyNames, properties)
|
|
117
|
+
const entity = await modelRuntime().get(id)
|
|
128
118
|
if (!entity) throw new Error('not_found')
|
|
129
119
|
const data = extractObjectData(writeableProperties, properties, entity)
|
|
130
|
-
await App.validation.validate(data, validators, {source: action, action, service, app, client})
|
|
120
|
+
await App.validation.validate(data, validators, { source: action, action, service, app, client })
|
|
131
121
|
emit({
|
|
132
122
|
type: eventName,
|
|
133
123
|
identifiers, data
|
|
@@ -138,23 +128,42 @@ async function defineUpdateAction(joinedParentsPropertyName, modelName, service,
|
|
|
138
128
|
const validators = App.validation.getValidators(action, service, action)
|
|
139
129
|
}
|
|
140
130
|
|
|
141
|
-
async function
|
|
142
|
-
const
|
|
131
|
+
async function defineResetEvent(config, context) {
|
|
132
|
+
const {
|
|
133
|
+
service, modelRuntime, joinedOthersPropertyName, modelName, otherPropertyNames
|
|
134
|
+
} = context
|
|
135
|
+
const eventName = joinedOthersPropertyName + 'Owned' + modelName + 'Reset'
|
|
143
136
|
service.events[eventName] = new EventDefinition({
|
|
144
137
|
name: eventName,
|
|
145
|
-
execute({identifiers}) {
|
|
146
|
-
|
|
138
|
+
execute({ identifiers }) {
|
|
139
|
+
const id = generateId(otherPropertyNames, identifiers)
|
|
140
|
+
return modelRuntime().delete(id)
|
|
147
141
|
}
|
|
148
142
|
})
|
|
149
|
-
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
async function defineResetAction(config, context) {
|
|
146
|
+
const {
|
|
147
|
+
service, modelRuntime, modelPropertyName,
|
|
148
|
+
otherPropertyNames, joinedOthersPropertyName, modelName, joinedOthersClassName, model
|
|
149
|
+
} = context
|
|
150
|
+
const eventName = joinedOthersPropertyName + 'Owned' + modelName + 'Reset'
|
|
151
|
+
const actionName = 'reset' + joinedOthersClassName + 'Owned' + modelName
|
|
150
152
|
service.actions[actionName] = new ActionDefinition({
|
|
151
153
|
name: actionName,
|
|
154
|
+
properties: {
|
|
155
|
+
[modelPropertyName]: {
|
|
156
|
+
type: model,
|
|
157
|
+
validation: ['nonEmpty']
|
|
158
|
+
}
|
|
159
|
+
},
|
|
152
160
|
access: config.resetAccess || config.writeAccess,
|
|
153
|
-
queuedBy:
|
|
161
|
+
queuedBy: otherPropertyNames,
|
|
154
162
|
waitForEvents: true,
|
|
155
163
|
async execute(properties, {client, service}, emit) {
|
|
156
|
-
const identifiers = extractIdentifiers(
|
|
157
|
-
const
|
|
164
|
+
const identifiers = extractIdentifiers(otherPropertyNames, properties)
|
|
165
|
+
const id = generateId(otherPropertyNames, properties)
|
|
166
|
+
const entity = await modelRuntime().get(id)
|
|
158
167
|
if (!entity) throw new Error('not_found')
|
|
159
168
|
emit({
|
|
160
169
|
type: eventName,
|
|
@@ -164,63 +173,37 @@ async function defineResetAction(joinedParentsPropertyName, modelName, service,
|
|
|
164
173
|
})
|
|
165
174
|
}
|
|
166
175
|
|
|
167
|
-
module.exports = function(service, app) {
|
|
168
|
-
if (!service) throw new Error("no service")
|
|
169
|
-
if (!app) throw new Error("no app")
|
|
170
|
-
|
|
171
|
-
for(let modelName in service.models) {
|
|
172
|
-
const model = service.models[modelName]
|
|
173
|
-
|
|
174
|
-
console.log("PO", modelName, model.propertyOf)
|
|
175
|
-
|
|
176
|
-
if(model.propertyOf) {
|
|
177
|
-
if(model.propertyOfProcessed) throw new Error("duplicated processing of propertyOf processor")
|
|
178
|
-
model.propertyOfProcessed = true
|
|
179
|
-
const originalModelProperties = { ...model.properties }
|
|
180
|
-
const modelProperties = Object.keys(model.properties)
|
|
181
|
-
const modelPropertyName = modelName.slice(0, 1).toLowerCase() + modelName.slice(1)
|
|
182
|
-
const defaults = App.utils.generateDefault(originalModelProperties)
|
|
183
|
-
function modelRuntime() {
|
|
184
|
-
return service._runtime.models[modelName]
|
|
185
|
-
}
|
|
186
|
-
if(!model.indexes) model.indexes = {}
|
|
187
176
|
|
|
188
|
-
let config = model.propertyOf // only single ownership is possible, but may be owned by objects set
|
|
189
|
-
if(typeof config == 'string' || Array.isArray(config)) config = { what: config }
|
|
190
177
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
const parents = (Array.isArray(config.what) ? config.what : [ config.what ])
|
|
194
|
-
.map(parent => parent.name ? parent.name : parent)
|
|
178
|
+
module.exports = function(service, app) {
|
|
179
|
+
processModelsAnnotation(service, app, 'propertyOf', (config, context) => {
|
|
195
180
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
const parentPropertyNames = parents.map(parent => parent.slice(0, 1).toLowerCase() + parent.slice(1))
|
|
199
|
-
const joinedParentsPropertyName = parentPropertyNames[0] +
|
|
200
|
-
(parents.length > 1 ? ('And' + parents.slice(1).join('And')) : '')
|
|
201
|
-
const joinedParentsClassName = parents.join('And')
|
|
181
|
+
defineProperties(context.model, context.others, context.otherPropertyNames)
|
|
182
|
+
defineIndex(context.model, context.joinedOthersClassName, context.otherPropertyNames)
|
|
202
183
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
184
|
+
if(config.readAccess) {
|
|
185
|
+
defineView({ ...config, access: config.readAccess }, context)
|
|
186
|
+
}
|
|
187
|
+
if(config.views) {
|
|
188
|
+
for(const view of config.views) {
|
|
189
|
+
defineView({ ...config, ...view }, context)
|
|
207
190
|
}
|
|
208
|
-
|
|
191
|
+
}
|
|
209
192
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
}
|
|
193
|
+
defineSetEvent(config, context)
|
|
194
|
+
defineUpdateEvent(config, context)
|
|
195
|
+
defineResetEvent(config, context)
|
|
214
196
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
}
|
|
197
|
+
if(config.setAccess || config.writeAccess) {
|
|
198
|
+
defineSetAction(config, context)
|
|
199
|
+
}
|
|
219
200
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
config, parentPropertyNames);
|
|
223
|
-
}
|
|
201
|
+
if(config.updateAccess || config.writeAccess) {
|
|
202
|
+
defineUpdateAction(config, context)
|
|
224
203
|
}
|
|
225
|
-
|
|
204
|
+
|
|
205
|
+
if(config.resetAccess || config.writeAccess) {
|
|
206
|
+
defineResetAction(config, context);
|
|
207
|
+
}
|
|
208
|
+
})
|
|
226
209
|
}
|
package/utils.js
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
const App = require("@live-change/framework")
|
|
2
|
+
const { PropertyDefinition, ViewDefinition, IndexDefinition, ActionDefinition, EventDefinition } = App
|
|
3
|
+
|
|
4
|
+
function extractIdParts(otherPropertyNames, properties) {
|
|
5
|
+
const idParts = []
|
|
6
|
+
for (const propertyName of otherPropertyNames) {
|
|
7
|
+
idParts.push(properties[propertyName])
|
|
8
|
+
}
|
|
9
|
+
return idParts
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function extractRange(properties) {
|
|
13
|
+
return {
|
|
14
|
+
gt: properties.gt,
|
|
15
|
+
gte: properties.gte,
|
|
16
|
+
lt: properties.lt,
|
|
17
|
+
lte: properties.lte,
|
|
18
|
+
reverse: properties.reverse,
|
|
19
|
+
limit: properties.limit
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function extractIdentifiers(otherPropertyNames, properties) {
|
|
24
|
+
const identifiers = {}
|
|
25
|
+
for (const propertyName of otherPropertyNames) {
|
|
26
|
+
identifiers[propertyName] = properties[propertyName]
|
|
27
|
+
}
|
|
28
|
+
return identifiers
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function generateId(otherPropertyNames, properties) {
|
|
32
|
+
return otherPropertyNames.length > 1
|
|
33
|
+
? otherPropertyNames.map(p => JSON.stringify(properties[p])).join(':')
|
|
34
|
+
: properties[otherPropertyNames[0]]
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function extractObjectData(writeableProperties, properties, defaults) {
|
|
38
|
+
let updateObject = {}
|
|
39
|
+
for (const propertyName of writeableProperties) {
|
|
40
|
+
if (properties.hasOwnProperty(propertyName)) {
|
|
41
|
+
newObject[propertyName] = properties[propertyName]
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return App.utils.mergeDeep({}, defaults, updateObject)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function defineProperties(model, types, names) {
|
|
48
|
+
for (let i = 0; i < types.length; i++) {
|
|
49
|
+
model.properties[names[i]] = new PropertyDefinition({
|
|
50
|
+
type: types[i],
|
|
51
|
+
validation: ['nonEmpty']
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function defineIndex(model, what, props) {
|
|
57
|
+
model.indexes['by' + what] = new IndexDefinition({
|
|
58
|
+
property: props
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function processModelsAnnotation(service, app, annotation, cb) {
|
|
63
|
+
if (!service) throw new Error("no service")
|
|
64
|
+
if (!app) throw new Error("no app")
|
|
65
|
+
|
|
66
|
+
for(let modelName in service.models) {
|
|
67
|
+
const model = service.models[modelName]
|
|
68
|
+
|
|
69
|
+
//console.log("PO", modelName, model[annotation])
|
|
70
|
+
|
|
71
|
+
if (model[annotation]) {
|
|
72
|
+
if (model[annotation + 'Processed']) throw new Error("duplicated processing of " + annotation + " processor")
|
|
73
|
+
model[annotation + 'Processed'] = true
|
|
74
|
+
const originalModelProperties = { ...model.properties }
|
|
75
|
+
const modelProperties = Object.keys(model.properties)
|
|
76
|
+
const modelPropertyName = modelName.slice(0, 1).toLowerCase() + modelName.slice(1)
|
|
77
|
+
const defaults = App.utils.generateDefault(originalModelProperties)
|
|
78
|
+
|
|
79
|
+
function modelRuntime() {
|
|
80
|
+
return service._runtime.models[modelName]
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (!model.indexes) model.indexes = {}
|
|
84
|
+
|
|
85
|
+
let config = model[annotation] // only single ownership is possible, but may be owned by objects set
|
|
86
|
+
if (typeof config == 'string' || Array.isArray(config)) config = {what: config}
|
|
87
|
+
|
|
88
|
+
console.log("MODEL " + modelName + " IS "+ annotation +" " + config.what)
|
|
89
|
+
|
|
90
|
+
const others = (Array.isArray(config.what) ? config.what : [config.what])
|
|
91
|
+
.map(other => other.name ? other.name : other)
|
|
92
|
+
|
|
93
|
+
const writeableProperties = modelProperties || config.writeableProperties
|
|
94
|
+
console.log("PPP", others)
|
|
95
|
+
const otherPropertyNames = others.map(other => other.slice(0, 1).toLowerCase() + other.slice(1))
|
|
96
|
+
const joinedOthersPropertyName = otherPropertyNames[0] +
|
|
97
|
+
(others.length > 1 ? ('And' + others.slice(1).join('And')) : '')
|
|
98
|
+
const joinedOthersClassName = others.join('And')
|
|
99
|
+
|
|
100
|
+
const context = {
|
|
101
|
+
service, app, model, originalModelProperties, modelProperties, modelPropertyName, defaults, modelRuntime,
|
|
102
|
+
otherPropertyNames, joinedOthersPropertyName, modelName, writeableProperties, joinedOthersClassName,
|
|
103
|
+
others
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
cb(config, context)
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
module.exports = {
|
|
112
|
+
extractIdParts, extractIdentifiers, extractObjectData, defineProperties, defineIndex,
|
|
113
|
+
processModelsAnnotation, extractRange, generateId
|
|
114
|
+
}
|