@live-change/relations-plugin 0.6.15 → 0.7.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/entity.js CHANGED
@@ -170,6 +170,18 @@ function defineDeleteAction(config, context) {
170
170
  const id = properties[modelPropertyName]
171
171
  const entity = await modelRuntime().get(id)
172
172
  if(!entity) throw new Error('not_found')
173
+ await Promise.all([
174
+ service.trigger({
175
+ type: 'delete'+service.name[0].toUpperCase()+service.name.slice(1)+'_'+modelName,
176
+ objectType: service.name+'_'+modelName,
177
+ object: id
178
+ }),
179
+ service.trigger({
180
+ type: 'deleteObject',
181
+ objectType: service.name+'_'+modelName,
182
+ object: id
183
+ })
184
+ ])
173
185
  emit({
174
186
  type: eventName,
175
187
  [modelPropertyName]: id
package/itemOf.js CHANGED
@@ -1,6 +1,7 @@
1
1
  const {
2
- defineProperties, defineIndex,
3
- processModelsAnnotation, addAccessControlParents
2
+ defineProperties, defineIndexes,
3
+ processModelsAnnotation, addAccessControlParents,
4
+ defineDeleteByOwnerEvents, defineParentDeleteTriggers
4
5
  } = require('./utils.js')
5
6
 
6
7
  const {
@@ -19,7 +20,7 @@ module.exports = function(service, app) {
19
20
 
20
21
  context.identifiers = defineProperties(context.model, context.others, context.otherPropertyNames)
21
22
  addAccessControlParents(context)
22
- defineIndex(context.model, context.joinedOthersClassName, context.otherPropertyNames)
23
+ defineIndexes(context.model, context.otherPropertyNames, context.others)
23
24
 
24
25
  if(config.sortBy) {
25
26
  for(const sortFields of config.sortBy) {
@@ -36,6 +37,7 @@ module.exports = function(service, app) {
36
37
  defineUpdatedEvent(config, context)
37
38
  defineTransferredEvent(config, context)
38
39
  defineDeletedEvent(config, context)
40
+ defineDeleteByOwnerEvents(config, context)
39
41
 
40
42
  if(config.createAccess || config.writeAccess || config.createAccessControl || config.writeAccessControl) {
41
43
  defineCreateAction(config, context)
@@ -48,5 +50,7 @@ module.exports = function(service, app) {
48
50
  if(config.deleteAccess || config.writeAccess || config.deleteAccessControl || config.writeAccessControl) {
49
51
  defineDeleteAction(config, context)
50
52
  }
53
+
54
+ if(!config.customDeleteTrigger) defineParentDeleteTriggers(config, context)
51
55
  })
52
56
  }
package/itemOfAny.js CHANGED
@@ -1,6 +1,7 @@
1
1
  const {
2
2
  defineAnyProperties, defineAnyIndexes,
3
- processModelsAnyAnnotation, addAccessControlAnyParents
3
+ processModelsAnyAnnotation, addAccessControlAnyParents, generateAnyId, defineDeleteByOwnerEvents,
4
+ defineParentDeleteTrigger
4
5
  } = require('./utilsAny.js')
5
6
 
6
7
  const {
@@ -37,6 +38,7 @@ module.exports = function(service, app) {
37
38
  defineUpdatedEvent(config, context)
38
39
  defineTransferredEvent(config, context)
39
40
  defineDeletedEvent(config, context)
41
+ defineDeleteByOwnerEvents(config, context, generateAnyId)
40
42
 
41
43
  if(config.createAccess || config.writeAccess || config.createAccessControl || config.writeAccessControl) {
42
44
  defineCreateAction(config, context)
@@ -49,5 +51,7 @@ module.exports = function(service, app) {
49
51
  if(config.deleteAccess || config.writeAccess || config.deleteAccessControl || config.writeAccessControl) {
50
52
  defineDeleteAction(config, context)
51
53
  }
54
+
55
+ if(!config.customDeleteTrigger) defineParentDeleteTrigger(config, context)
52
56
  })
53
57
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@live-change/relations-plugin",
3
- "version": "0.6.15",
3
+ "version": "0.7.0",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -21,8 +21,8 @@
21
21
  "url": "https://www.viamage.com/"
22
22
  },
23
23
  "dependencies": {
24
- "@live-change/framework": "^0.6.15",
24
+ "@live-change/framework": "^0.7.0",
25
25
  "pluralize": "8.0.0"
26
26
  },
27
- "gitHead": "9b5c0ac7db8788a5647685dde41577b38c994263"
27
+ "gitHead": "008e06c10d65b00478c103d625c621805837264b"
28
28
  }
@@ -166,6 +166,18 @@ function defineDeleteAction(config, context) {
166
166
  if(JSON.stringify(entityTypeAndIdParts) != JSON.stringify(typeAndIdParts)) {
167
167
  throw new Error('not_authorized')
168
168
  }
169
+ await Promise.all([
170
+ service.trigger({
171
+ type: 'delete'+service.name[0].toUpperCase()+service.name.slice(1)+'_'+modelName,
172
+ objectType: service.name+'_'+modelName,
173
+ object: id
174
+ }),
175
+ service.trigger({
176
+ type: 'deleteObject',
177
+ objectType: service.name+'_'+modelName,
178
+ object: id
179
+ })
180
+ ])
169
181
  emit({
170
182
  type: eventName,
171
183
  [modelPropertyName]: id
@@ -151,6 +151,18 @@ function defineDeleteAction(config, context) {
151
151
  if(JSON.stringify(entityIdParts) != JSON.stringify(idParts)) {
152
152
  throw new Error('not_authorized')
153
153
  }
154
+ await Promise.all([
155
+ service.trigger({
156
+ type: 'delete'+service.name[0].toUpperCase()+service.name.slice(1)+'_'+modelName,
157
+ objectType: service.name+'_'+modelName,
158
+ object: id
159
+ }),
160
+ service.trigger({
161
+ type: 'deleteObject',
162
+ objectType: service.name+'_'+modelName,
163
+ object: id
164
+ })
165
+ ])
154
166
  emit({
155
167
  type: eventName,
156
168
  [modelPropertyName]: id
package/propertyOf.js CHANGED
@@ -1,6 +1,7 @@
1
1
  const {
2
- defineProperties, defineIndex,
3
- processModelsAnnotation, generateId, addAccessControlParents
2
+ defineProperties, defineIndexes,
3
+ processModelsAnnotation, generateId, addAccessControlParents,
4
+ defineDeleteByOwnerEvents, defineParentDeleteTriggers
4
5
  } = require('./utils.js')
5
6
 
6
7
  const { defineSetEvent, defineUpdatedEvent, defineTransferredEvent, defineResetEvent } = require('./propertyEvents.js')
@@ -17,7 +18,7 @@ module.exports = function(service, app) {
17
18
 
18
19
  context.identifiers = defineProperties(context.model, context.others, context.otherPropertyNames)
19
20
  addAccessControlParents(context)
20
- defineIndex(context.model, context.joinedOthersClassName, context.otherPropertyNames)
21
+ defineIndexes(context.model, context.otherPropertyNames, context.others)
21
22
 
22
23
  if(config.readAccess || config.writeAccess || config.readAccessControl || config.writeAccessControl) {
23
24
  defineView({ ...config }, context)
@@ -32,6 +33,7 @@ module.exports = function(service, app) {
32
33
  defineUpdatedEvent(config, context, generateId)
33
34
  defineTransferredEvent(config, context, generateId)
34
35
  defineResetEvent(config, context, generateId)
36
+ defineDeleteByOwnerEvents(config, context)
35
37
 
36
38
  if(config.setAccess || config.writeAccess || config.setAccessControl || config.writeAccessControl) {
37
39
  defineSetAction(config, context)
@@ -49,5 +51,7 @@ module.exports = function(service, app) {
49
51
  if(config.resetAccess || config.writeAccess || config.resetAccessControl || config.writeAccessControl) {
50
52
  defineResetAction(config, context);
51
53
  }
54
+
55
+ if(!config.customDeleteTrigger) defineParentDeleteTriggers(config, context)
52
56
  })
53
57
  }
package/propertyOfAny.js CHANGED
@@ -1,6 +1,7 @@
1
1
  const {
2
2
  defineAnyProperties, defineAnyIndexes,
3
- processModelsAnyAnnotation, generateAnyId, addAccessControlAnyParents
3
+ processModelsAnyAnnotation, generateAnyId, addAccessControlAnyParents,
4
+ defineDeleteByOwnerEvents, defineParentDeleteTrigger
4
5
  } = require('./utilsAny.js')
5
6
 
6
7
  const {
@@ -10,6 +11,7 @@ const {
10
11
  const {
11
12
  defineObjectView, defineRangeViews, defineSetAction, defineUpdateAction, defineSetOrUpdateAction, defineResetAction
12
13
  } = require('./singularRelationAnyUtils.js')
14
+ const {defineResetByOwner} = require("./propertyEvents");
13
15
 
14
16
  module.exports = function(service, app) {
15
17
  processModelsAnyAnnotation(service, app, 'propertyOfAny', false, (config, context) => {
@@ -38,6 +40,7 @@ module.exports = function(service, app) {
38
40
  defineUpdatedEvent(config, context, generateAnyId)
39
41
  defineTransferredEvent(config, context, generateAnyId)
40
42
  defineResetEvent(config, context, generateAnyId)
43
+ defineDeleteByOwnerEvents(config, context, generateAnyId)
41
44
 
42
45
  if(config.setAccess || config.writeAccess || config.setAccessControl || config.writeAccessControl) {
43
46
  defineSetAction(config, context)
@@ -56,5 +59,7 @@ module.exports = function(service, app) {
56
59
  defineResetAction(config, context);
57
60
  }
58
61
 
62
+ if(!config.customDeleteTrigger) defineParentDeleteTrigger(config, context)
63
+
59
64
  })
60
65
  }
@@ -225,6 +225,18 @@ function defineResetAction(config, context) {
225
225
  const id = generateAnyId(otherPropertyNames, properties)
226
226
  const entity = await modelRuntime().get(id)
227
227
  if (!entity) throw new Error('not_found')
228
+ await Promise.all([
229
+ service.trigger({
230
+ type: 'delete'+service.name[0].toUpperCase()+service.name.slice(1)+'_'+modelName,
231
+ objectType: service.name+'_'+modelName,
232
+ object: id
233
+ }),
234
+ service.trigger({
235
+ type: 'deleteObject',
236
+ objectType: service.name+'_'+modelName,
237
+ object: id
238
+ })
239
+ ])
228
240
  emit({
229
241
  type: eventName,
230
242
  identifiers
@@ -170,6 +170,18 @@ function defineResetAction(config, context) {
170
170
  const id = generateId(otherPropertyNames, properties)
171
171
  const entity = await modelRuntime().get(id)
172
172
  if (!entity) throw new Error('not_found')
173
+ await Promise.all([
174
+ service.trigger({
175
+ type: 'delete'+service.name[0].toUpperCase()+service.name.slice(1)+'_'+modelName,
176
+ objectType: service.name+'_'+modelName,
177
+ object: id
178
+ }),
179
+ service.trigger({
180
+ type: 'deleteObject',
181
+ objectType: service.name+'_'+modelName,
182
+ object: id
183
+ })
184
+ ])
173
185
  emit({
174
186
  type: eventName,
175
187
  identifiers
package/utils.js CHANGED
@@ -1,5 +1,9 @@
1
1
  const App = require("@live-change/framework")
2
- const { PropertyDefinition, ViewDefinition, IndexDefinition, ActionDefinition, EventDefinition } = App
2
+ const app = App.app()
3
+ const { allCombinations } = require("./combinations.js");
4
+ const {
5
+ PropertyDefinition, ViewDefinition, IndexDefinition, ActionDefinition, EventDefinition, TriggerDefinition
6
+ } = App
3
7
 
4
8
  function extractIdParts(otherPropertyNames, properties) {
5
9
  const idParts = []
@@ -52,6 +56,16 @@ function defineIndex(model, what, props) {
52
56
  property: props
53
57
  })
54
58
  }
59
+ function defineIndexes(model, props, types) {
60
+ const propCombinations = allCombinations(Object.keys(props))
61
+ for(const propCombination of propCombinations) {
62
+ const upperCaseProps = propCombination.map(id => {
63
+ const prop = props[id]
64
+ return prop[0].toUpperCase() + prop.slice(1)
65
+ })
66
+ defineIndex(model, upperCaseProps.join('And'), propCombination.map(id => types[id]))
67
+ }
68
+ }
55
69
 
56
70
  function processModelsAnnotation(service, app, annotation, multiple, cb) {
57
71
  if (!service) throw new Error("no service")
@@ -93,12 +107,12 @@ function processModelsAnnotation(service, app, annotation, multiple, cb) {
93
107
 
94
108
  console.log("MODEL " + modelName + " IS " + annotation + " " + config.what)
95
109
 
96
- const others = (Array.isArray(config.what) ? config.what : [config.what])
97
- .map(other => other.name ? other.name : other)
110
+ const what = (Array.isArray(config.what) ? config.what : [config.what])
111
+ const others = what.map(other => other.getTypeName ? other.getTypeName() : (other.name ? other.name : other))
98
112
 
99
113
  const writeableProperties = modelProperties || config.writeableProperties
100
114
  //console.log("PPP", others)
101
- const otherPropertyNames = others.map(other => other.slice(0, 1).toLowerCase() + other.slice(1))
115
+ const otherPropertyNames = what.map(other => other.name ? other.name : other)
102
116
  const joinedOthersPropertyName = otherPropertyNames[0] +
103
117
  (others.length > 1 ? ('And' + others.slice(1).join('And')) : '')
104
118
  const joinedOthersClassName = others.join('And')
@@ -142,7 +156,96 @@ function prepareAccessControl(accessControl, names, types) {
142
156
  }
143
157
  }
144
158
 
159
+ function defineDeleteByOwnerEvents(config, context, generateId) {
160
+ const {
161
+ service, modelRuntime, joinedOthersPropertyName, modelName, modelPropertyName, otherPropertyNames, reverseRelationWord
162
+ } = context
163
+ for(const propertyName of otherPropertyNames) {
164
+ const eventName = propertyName + reverseRelationWord + modelName + 'DeleteByOwner'
165
+ service.events[eventName] = new EventDefinition({
166
+ name: eventName,
167
+ async execute({owner}) {
168
+ const runtime = modelRuntime()
169
+ const tableName = runtime.tableName
170
+ const prefix = JSON.stringify(owner)
171
+ const indexName = tableName + '_by' + propertyName[0].toUpperCase() + propertyName.slice(1)
172
+ const bucketSize = 128
173
+ let bucket
174
+ do {
175
+ bucket = await app.dao.get(['database', 'indexRange', app.databaseName, indexName, {
176
+ gte: prefix + ':',
177
+ lte: prefix + '_\xFF\xFF\xFF\xFF',
178
+ limit: bucketSize
179
+ }])
180
+ const deletePromises = bucket.map(({to}) => runtime.delete(to))
181
+ await Promise.all(deletePromises)
182
+ } while (bucket.length == bucketSize)
183
+ }
184
+ })
185
+ }
186
+ }
187
+
188
+ function defineParentDeleteTriggers(config, context) {
189
+ const {
190
+ service, modelRuntime, modelPropertyName, identifiers, others,
191
+ otherPropertyNames, joinedOthersPropertyName, modelName, joinedOthersClassName, model,
192
+ reverseRelationWord
193
+ } = context
194
+ for(const index in others) {
195
+ const otherType = others[index]
196
+ const propertyName = otherPropertyNames[index]
197
+ const triggerName = 'delete' + otherType[0].toUpperCase() + otherType.slice(1)
198
+ if(!service.triggers[triggerName]) service.triggers[triggerName] = []
199
+ service.triggers[triggerName].push(new TriggerDefinition({
200
+ name: triggerName,
201
+ properties: {
202
+ object: {
203
+ type: String
204
+ }
205
+ },
206
+ async execute({ object }, {client, service}, emit) {
207
+ const tableName = modelRuntime().tableName
208
+ const prefix = JSON.stringify(object)
209
+ const indexName = tableName + 'by' + propertyName[0].toUpperCase() + propertyName.slice(1)
210
+ const bucketSize = 32
211
+ let found = false
212
+ let bucket
213
+ do {
214
+ bucket = await app.dao.get(['database', 'indexRange', app.databaseName, indexName, {
215
+ gte: prefix + ':',
216
+ lte: prefix + '_\xFF\xFF\xFF\xFF',
217
+ limit: bucketSize
218
+ }])
219
+ if(bucket.length > 0) found = true
220
+ const deleteTriggerPromises = bucket.map(({to}) => [
221
+ service.trigger({
222
+ type: 'delete'+service.name[0].toUpperCase()+service.name.slice(1)+'_'+modelName,
223
+ objectType: service.name+'_'+modelName,
224
+ object: to
225
+ }),
226
+ service.trigger({
227
+ type: 'deleteObject',
228
+ objectType: service.name+'_'+modelName,
229
+ object: to
230
+ })
231
+ ]).flat()
232
+ await Promise.all(deleteTriggerPromises)
233
+ } while (bucket.length == bucketSize)
234
+ if(found) {
235
+ const eventName = propertyName + reverseRelationWord + modelName + 'DeleteByOwner'
236
+ emit({
237
+ type: eventName,
238
+ owner: object
239
+ })
240
+ }
241
+ await Promise.all(promises)
242
+ }
243
+ }))
244
+ }
245
+ }
246
+
145
247
  module.exports = {
146
- extractIdParts, extractIdentifiers, extractObjectData, defineProperties, defineIndex,
147
- processModelsAnnotation, generateId, addAccessControlParents, prepareAccessControl
248
+ extractIdParts, extractIdentifiers, extractObjectData, defineProperties, defineIndex, defineIndexes,
249
+ processModelsAnnotation, generateId, addAccessControlParents, prepareAccessControl,
250
+ defineDeleteByOwnerEvents, defineParentDeleteTriggers
148
251
  }
package/utilsAny.js CHANGED
@@ -1,5 +1,8 @@
1
1
  const App = require("@live-change/framework")
2
- const { PropertyDefinition, ViewDefinition, IndexDefinition, ActionDefinition, EventDefinition } = App
2
+ const app = App.app()
3
+ const {
4
+ PropertyDefinition, ViewDefinition, IndexDefinition, ActionDefinition, EventDefinition, TriggerDefinition
5
+ } = App
3
6
  const { allCombinations } = require("./combinations.js")
4
7
 
5
8
  function extractTypeAndIdParts(otherPropertyNames, properties) {
@@ -143,10 +146,101 @@ function prepareAccessControl(accessControl, names) {
143
146
  }
144
147
  }
145
148
 
149
+ function defineDeleteByOwnerEvents(config, context, generateId) {
150
+ const {
151
+ service, modelRuntime, joinedOthersPropertyName, modelName, modelPropertyName, otherPropertyNames, reverseRelationWord
152
+ } = context
153
+ for(const propertyName of otherPropertyNames) {
154
+ const eventName = propertyName + reverseRelationWord + modelName + 'DeleteByOwner'
155
+ service.events[eventName] = new EventDefinition({
156
+ name: eventName,
157
+ async execute({ ownerType, owner }) {
158
+ const runtime = modelRuntime()
159
+ const tableName = runtime.tableName
160
+ const prefix = JSON.stringify(ownerType) + ':' + JSON.stringify(owner)
161
+ const indexName = tableName + '_by' + propertyName[0].toUpperCase() + propertyName.slice(1)
162
+ const bucketSize = 128
163
+ let bucket
164
+ do {
165
+ bucket = await app.dao.get(['database', 'indexRange', app.databaseName, indexName, {
166
+ gte: prefix + ':',
167
+ lte: prefix + '_\xFF\xFF\xFF\xFF',
168
+ limit: bucketSize
169
+ }])
170
+ const deletePromises = bucket.map(({to}) => runtime.delete(to))
171
+ await Promise.all(deletePromises)
172
+ } while (bucket.length == bucketSize)
173
+ }
174
+ })
175
+ }
176
+ }
177
+
178
+ function defineParentDeleteTrigger(config, context) {
179
+ const {
180
+ service, modelRuntime, modelPropertyName, identifiers,
181
+ otherPropertyNames, joinedOthersPropertyName, modelName, joinedOthersClassName, model,
182
+ reverseRelationWord
183
+ } = context
184
+ const triggerName = 'deleteObject'
185
+ if(!service.triggers[triggerName]) service.triggers[triggerName] = []
186
+ service.triggers[triggerName].push(new TriggerDefinition({
187
+ name: triggerName,
188
+ properties: {
189
+ objectType: {
190
+ type: String,
191
+ },
192
+ object: {
193
+ type: String
194
+ }
195
+ },
196
+ async execute({ objectType, object }, {client, service}, emit) {
197
+ const tableName = modelRuntime().tableName
198
+ const prefix = JSON.stringify(objectType) + ':' + JSON.stringify(object)
199
+ const promises = otherPropertyNames.map(async (propertyName) => {
200
+ const indexName = tableName + '_by' + propertyName[0].toUpperCase() + propertyName.slice(1)
201
+ const bucketSize = 32
202
+ let found = false
203
+ let bucket
204
+ do {
205
+ bucket = await app.dao.get(['database', 'indexRange', app.databaseName, indexName, {
206
+ gte: prefix + ':',
207
+ lte: prefix + '_\xFF\xFF\xFF\xFF',
208
+ limit: bucketSize
209
+ }])
210
+ if(bucket.length > 0) found = true
211
+ const deleteTriggerPromises = bucket.map(({to}) => [
212
+ service.trigger({
213
+ type: 'delete'+service.name[0].toUpperCase()+service.name.slice(1)+'_'+modelName,
214
+ objectType: service.name+'_'+modelName,
215
+ object: to
216
+ }),
217
+ service.trigger({
218
+ type: 'deleteObject',
219
+ objectType: service.name+'_'+modelName,
220
+ object: to
221
+ })
222
+ ]).flat()
223
+ await Promise.all(deleteTriggerPromises)
224
+ } while (bucket.length == bucketSize)
225
+ if(found) {
226
+ const eventName = propertyName + reverseRelationWord + modelName + 'DeleteByOwner'
227
+ emit({
228
+ type: eventName,
229
+ ownerType: objectType,
230
+ owner: object
231
+ })
232
+ }
233
+ })
234
+ await Promise.all(promises)
235
+ }
236
+ }))
237
+ }
238
+
146
239
  module.exports = {
147
240
  extractTypeAndIdParts, extractIdentifiersWithTypes, defineAnyProperties,
148
241
  defineAnyIndex, defineAnyIndexes,
149
242
  processModelsAnyAnnotation, generateAnyId,
150
243
  addAccessControlAnyParents,
151
- prepareAccessControl
244
+ prepareAccessControl,
245
+ defineDeleteByOwnerEvents, defineParentDeleteTrigger
152
246
  }