@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 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.8",
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.8"
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 defineIndex(model, joinedParentsClassName, parentPropertyNames) {
15
- model.indexes['by' + joinedParentsClassName] = new IndexDefinition({
16
- property: parentPropertyNames
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 < parents.length; i++) {
23
- viewProperties[parentPropertyNames[i]] = new PropertyDefinition({
24
- type: parents[i],
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 = joinedParentsPropertyName + 'Owned' + modelName
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
- access: config.readAccess,
27
+ returns: {
28
+ type: model,
29
+ },
30
+ access: config.access,
35
31
  daoPath(properties, { client, context }) {
36
- const idParts = extractIdParts(parentPropertyNames, properties)
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 extractIdParts(parentPropertyNames, properties) {
47
- const idParts = []
48
- for (const propertyName of parentPropertyNames) {
49
- idParts.push(properties[propertyName])
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
- return modelRuntime().create({ ...properties.data, ...properties.identifiers })
48
+ const id = generateId(otherPropertyNames, properties.identifiers)
49
+ return modelRuntime().create({ ...properties.data, ...properties.identifiers, id })
81
50
  }
82
51
  })
83
- const actionName = 'set' + joinedParentsClassName + 'Owned' + modelName
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: parentPropertyNames,
68
+ queuedBy: otherPropertyNames,
92
69
  waitForEvents: true,
93
70
  async execute(properties, {client, service}, emit) {
94
- const identifiers = extractIdentifiers(parentPropertyNames, properties)
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 defineUpdateAction(joinedParentsPropertyName, modelName, service, modelRuntime, joinedParentsClassName, model, config, parentPropertyNames, writeableProperties, app) {
108
- const eventName = joinedParentsPropertyName + 'Owned' + modelName + 'Updated'
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
- return modelRuntime().update(properties.identifiers.id, {...properties.data, ...properties.identifiers})
92
+ const id = generateId(otherPropertyNames, properties.identifiers)
93
+ return modelRuntime().update(id, { ...properties.data, ...properties.identifiers })
113
94
  }
114
95
  })
115
- const actionName = 'update' + joinedParentsClassName + 'Owned' + modelName
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: parentPropertyNames,
112
+ queuedBy: otherPropertyNames,
124
113
  waitForEvents: true,
125
114
  async execute(properties, {client, service}, emit) {
126
- const identifiers = extractIdentifiers(parentPropertyNames, properties)
127
- const entity = await modelRuntime().get(identifiers.id)
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 defineResetAction(joinedParentsPropertyName, modelName, service, modelRuntime, joinedParentsClassName, config, parentPropertyNames) {
142
- const eventName = joinedParentsPropertyName + 'Owned' + modelName + 'Reset'
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
- return modelRuntime().delete(identifiers.id)
138
+ execute({ identifiers }) {
139
+ const id = generateId(otherPropertyNames, identifiers)
140
+ return modelRuntime().delete(id)
147
141
  }
148
142
  })
149
- const actionName = 'reset' + joinedParentsClassName + 'Owned' + modelName
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: parentPropertyNames,
161
+ queuedBy: otherPropertyNames,
154
162
  waitForEvents: true,
155
163
  async execute(properties, {client, service}, emit) {
156
- const identifiers = extractIdentifiers(parentPropertyNames, properties)
157
- const entity = await modelRuntime().get(identifiers.id)
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
- console.log("MODEL " + modelName + " IS PROPERTY OF " + config.what)
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
- const writeableProperties = modelProperties || config.writableProperties
197
- console.log("PPP", parents)
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
- defineProperties(parents, model, parentPropertyNames)
204
- defineIndex(model, joinedParentsClassName, parentPropertyNames)
205
- if(config.readAccess) {
206
- defineView(joinedParentsPropertyName, modelName, service, config, modelRuntime, parents, parentPropertyNames)
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
- /// TODO: multiple views with limited fields
191
+ }
209
192
 
210
- if(config.setAccess || config.writeAccess) {
211
- defineSetAction(joinedParentsPropertyName, modelName, service, parentPropertyNames,
212
- modelRuntime, joinedParentsClassName, model, config, writeableProperties, defaults, app)
213
- }
193
+ defineSetEvent(config, context)
194
+ defineUpdateEvent(config, context)
195
+ defineResetEvent(config, context)
214
196
 
215
- if(config.updateAccess || config.writeAccess) {
216
- defineUpdateAction(joinedParentsPropertyName, modelName, service, modelRuntime, joinedParentsClassName,
217
- model, config, parentPropertyNames, writeableProperties, app)
218
- }
197
+ if(config.setAccess || config.writeAccess) {
198
+ defineSetAction(config, context)
199
+ }
219
200
 
220
- if(config.resetAccess || config.writeAccess) {
221
- defineResetAction(joinedParentsPropertyName, modelName, service, modelRuntime, joinedParentsClassName,
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
+ }