@live-change/simple-query 0.9.163 → 0.9.165
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/package.json +3 -3
- package/src/query.ts +23 -5
- package/src/simpleIndex.db.js +1 -1
- package/src/simpleQuery.db.js +128 -70
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@live-change/simple-query",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.165",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
},
|
|
23
23
|
"type": "module",
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@live-change/framework": "^0.9.
|
|
25
|
+
"@live-change/framework": "^0.9.165",
|
|
26
26
|
"pluralize": "^8.0.0"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
@@ -30,5 +30,5 @@
|
|
|
30
30
|
"typedoc-plugin-markdown": "^4.6.3",
|
|
31
31
|
"typedoc-plugin-rename-defaults": "^0.7.3"
|
|
32
32
|
},
|
|
33
|
-
"gitHead": "
|
|
33
|
+
"gitHead": "687dab16bd0c6594544cdab70cd7eecc17bb510c"
|
|
34
34
|
}
|
package/src/query.ts
CHANGED
|
@@ -102,7 +102,7 @@ interface QueryDefinitionSpecification {
|
|
|
102
102
|
sources?: Record<string, QuerySource>,
|
|
103
103
|
code?: QueryCode,
|
|
104
104
|
update?: boolean,
|
|
105
|
-
id: Function
|
|
105
|
+
id: Function,
|
|
106
106
|
timeout?: number,
|
|
107
107
|
requestTimeout?: number,
|
|
108
108
|
validation?: (parameters: FrameworkQueryParameters, context: ContextBase) => Promise<any>
|
|
@@ -216,6 +216,7 @@ export class QueryDefinition<SDS extends ServiceDefinitionSpecification> {
|
|
|
216
216
|
definition: QueryDefinitionSpecification
|
|
217
217
|
properties: Record<string, PropertyDefinition<any>>
|
|
218
218
|
rules: QueryRules
|
|
219
|
+
idFields: QueryInputLike[] | null
|
|
219
220
|
firstRule: QueryRule
|
|
220
221
|
rootSources: RuleSource[]
|
|
221
222
|
ruleSources: RuleSource[]
|
|
@@ -265,6 +266,15 @@ export class QueryDefinition<SDS extends ServiceDefinitionSpecification> {
|
|
|
265
266
|
}
|
|
266
267
|
}
|
|
267
268
|
|
|
269
|
+
printIdFields() {
|
|
270
|
+
console.log("ID FIELDS:")
|
|
271
|
+
if(this.idFields) {
|
|
272
|
+
for(const idField of this.idFields) {
|
|
273
|
+
console.log(` `, queryDescription(idField, ' '))
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
268
278
|
computeRules() {
|
|
269
279
|
const queryProperties = {}
|
|
270
280
|
for(const propertyName in this.definition.properties) {
|
|
@@ -282,6 +292,7 @@ export class QueryDefinition<SDS extends ServiceDefinitionSpecification> {
|
|
|
282
292
|
|
|
283
293
|
// run the code to collect relations
|
|
284
294
|
this.rules = this.definition.code(queryProperties, queryInputs)
|
|
295
|
+
this.idFields = this.definition.id ? this.definition.id(queryInputs) : null
|
|
285
296
|
}
|
|
286
297
|
|
|
287
298
|
markStaticRules() {
|
|
@@ -410,33 +421,38 @@ export class QueryDefinition<SDS extends ServiceDefinitionSpecification> {
|
|
|
410
421
|
|
|
411
422
|
const ruleParameters = JSON.parse(JSON.stringify(source.rule.$_parametersJSON(resultParameters)))
|
|
412
423
|
console.log("RULE PARAMETERS", ruleParameters)
|
|
424
|
+
const mandatory = this.idFields?.find(idField => source.input.$alias === idField.$alias) ? true : undefined
|
|
413
425
|
if(source.index) {
|
|
414
426
|
const indexExecution = {
|
|
415
427
|
...source.index.$_executionJSON(),
|
|
416
428
|
by: parameterEnsureRange(ruleParameters[Object.keys(ruleParameters)[0]])
|
|
417
429
|
}
|
|
430
|
+
/// TODO: decide if id field is mandatory - if exports aliases that are required in id Fields or market mandatory
|
|
418
431
|
const indexNext = [{
|
|
419
432
|
execution: {
|
|
420
433
|
operation: 'object',
|
|
421
|
-
...source.input.$_executionJSON(),
|
|
434
|
+
...source.input.$_executionJSON(),
|
|
422
435
|
by: {
|
|
423
436
|
type: 'result',
|
|
424
437
|
path: [indexExecution.alias, source.index.indexParts.at(-1).alias],
|
|
425
438
|
},
|
|
426
439
|
},
|
|
440
|
+
mandatory,
|
|
427
441
|
next
|
|
428
442
|
}]
|
|
429
443
|
return {
|
|
430
444
|
execution: indexExecution,
|
|
431
445
|
next: indexNext
|
|
432
446
|
}
|
|
433
|
-
}
|
|
447
|
+
}
|
|
448
|
+
|
|
434
449
|
const execution = {
|
|
435
|
-
...source.input.$_executionJSON(),
|
|
450
|
+
...source.input.$_executionJSON(),
|
|
436
451
|
by: ruleParameters[Object.keys(ruleParameters)[0]]
|
|
437
452
|
}
|
|
438
453
|
const executionPlan = {
|
|
439
454
|
execution,
|
|
455
|
+
mandatory,
|
|
440
456
|
next
|
|
441
457
|
}
|
|
442
458
|
return executionPlan
|
|
@@ -622,10 +638,12 @@ export class QueryDefinition<SDS extends ServiceDefinitionSpecification> {
|
|
|
622
638
|
prepareQuery() {
|
|
623
639
|
this.createIndexes()
|
|
624
640
|
|
|
625
|
-
console.log("########### PREPARING QUERY!!!!")
|
|
641
|
+
console.log("########### PREPARING QUERY!!!!")
|
|
626
642
|
|
|
627
643
|
this.printRules()
|
|
628
644
|
|
|
645
|
+
this.printIdFields()
|
|
646
|
+
|
|
629
647
|
this.printDependencies()
|
|
630
648
|
|
|
631
649
|
this.computeExecutionPlan()
|
package/src/simpleIndex.db.js
CHANGED
|
@@ -18,7 +18,7 @@ async function autoIndex(input, output, { plan, properties }) {
|
|
|
18
18
|
|
|
19
19
|
async function gatherOutputData(next, context, oldContext) {
|
|
20
20
|
const outputContext = { ...context }
|
|
21
|
-
const oldOutputContext = { ...
|
|
21
|
+
const oldOutputContext = { ...oldContext }
|
|
22
22
|
/// first execute next to gather all data
|
|
23
23
|
for(const nextStep of next) {
|
|
24
24
|
await fetch(nextStep, outputContext, oldOutputContext)
|
package/src/simpleQuery.db.js
CHANGED
|
@@ -64,6 +64,28 @@ async function simpleQuery(input, output, { _query, ...params }) {
|
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
function applyChange(results, obj, oldObj) {
|
|
68
|
+
if(oldObj) {
|
|
69
|
+
const index = results.findIndex(result => result.id === oldObj.id)
|
|
70
|
+
if(index !== -1) {
|
|
71
|
+
if(obj) {
|
|
72
|
+
results[index] = obj
|
|
73
|
+
} else {
|
|
74
|
+
results.splice(index, 1)
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
} else if(obj) {
|
|
78
|
+
const index = results.findIndex(result => result.id >= obj.id)
|
|
79
|
+
if(index === -1) {
|
|
80
|
+
results.push(obj)
|
|
81
|
+
} else if(results[index].id === obj.id) {
|
|
82
|
+
results[index] = obj
|
|
83
|
+
} else {
|
|
84
|
+
results.splice(index, 0, obj)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
67
89
|
class DataObservation {
|
|
68
90
|
|
|
69
91
|
#planStep = null
|
|
@@ -71,13 +93,16 @@ async function simpleQuery(input, output, { _query, ...params }) {
|
|
|
71
93
|
#source = null
|
|
72
94
|
#by = null
|
|
73
95
|
#onChange = null
|
|
74
|
-
|
|
96
|
+
#disposed = false
|
|
97
|
+
|
|
75
98
|
#observation = null
|
|
76
99
|
|
|
77
|
-
#
|
|
100
|
+
#dependentObservationsByNext
|
|
78
101
|
|
|
79
102
|
#resultsPromise = null
|
|
80
103
|
#results = []
|
|
104
|
+
#rawResults = []
|
|
105
|
+
|
|
81
106
|
#idFunction = null
|
|
82
107
|
|
|
83
108
|
constructor(planStep, context, source, by, onChange, idFunction) {
|
|
@@ -87,6 +112,11 @@ async function simpleQuery(input, output, { _query, ...params }) {
|
|
|
87
112
|
this.#by = by
|
|
88
113
|
this.#onChange = onChange
|
|
89
114
|
this.#idFunction = idFunction
|
|
115
|
+
|
|
116
|
+
this.#dependentObservationsByNext = new Array(planStep.next.length)
|
|
117
|
+
for(const nextIndex in planStep.next) {
|
|
118
|
+
this.#dependentObservationsByNext[nextIndex] = new Map()
|
|
119
|
+
}
|
|
90
120
|
}
|
|
91
121
|
|
|
92
122
|
async start() {
|
|
@@ -102,6 +132,8 @@ async function simpleQuery(input, output, { _query, ...params }) {
|
|
|
102
132
|
const id = obj?.id || oldObj?.id
|
|
103
133
|
if(!id) return
|
|
104
134
|
|
|
135
|
+
applyChange(this.#rawResults, obj, oldObj)
|
|
136
|
+
|
|
105
137
|
const nextContext = { ...context, [planStep.execution.alias]: obj }
|
|
106
138
|
const nextOldContext = { ...context, [planStep.execution.alias]: oldObj }
|
|
107
139
|
|
|
@@ -109,22 +141,24 @@ async function simpleQuery(input, output, { _query, ...params }) {
|
|
|
109
141
|
|
|
110
142
|
const oldJoinedResults = oldObj ? await this.#joinResults([ oldObj ]) : []
|
|
111
143
|
|
|
112
|
-
for(const
|
|
144
|
+
for(const nextStepIndex in planStep.next) {
|
|
145
|
+
const nextStep = planStep.next[nextStepIndex]
|
|
113
146
|
const nextSource = await getSource(nextStep.execution.sourceType, nextStep.execution.name)
|
|
114
|
-
const nextBy = decodeParameter(nextStep.execution.by, nextContext, params)
|
|
115
|
-
const nextOldBy = decodeParameter(nextStep.execution.by, nextOldContext, params)
|
|
116
|
-
const nextByKey = nextBy && serializeKeyData(
|
|
117
|
-
const nextOldByKey = nextOldBy && serializeKeyData(
|
|
147
|
+
const nextBy = obj && decodeParameter(nextStep.execution.by, nextContext, params)
|
|
148
|
+
const nextOldBy = oldObj && decodeParameter(nextStep.execution.by, nextOldContext, params)
|
|
149
|
+
const nextByKey = nextBy && serializeKeyData(nextBy)
|
|
150
|
+
const nextOldByKey = nextOldBy && serializeKeyData(nextOldBy)
|
|
118
151
|
if(nextByKey !== nextOldByKey) {
|
|
119
|
-
|
|
120
|
-
|
|
152
|
+
const nextDependentObservations = this.#dependentObservationsByNext[nextStepIndex]
|
|
153
|
+
if(nextOldBy && nextDependentObservations.has(nextOldByKey)) {
|
|
154
|
+
const dependentObservation = nextDependentObservations.get(nextOldByKey)
|
|
121
155
|
dependentObservation.dispose()
|
|
122
|
-
|
|
156
|
+
nextDependentObservations.delete(nextOldByKey)
|
|
123
157
|
}
|
|
124
|
-
if(!
|
|
158
|
+
if(nextBy && !nextDependentObservations.has(nextByKey)) {
|
|
125
159
|
const dependentObservation = new DataObservation(nextStep, nextContext, nextSource, nextBy,
|
|
126
160
|
(context, oldContext, observation) => this.handleDependentChange(context, oldContext, observation, id))
|
|
127
|
-
|
|
161
|
+
nextDependentObservations.set(nextByKey, dependentObservation)
|
|
128
162
|
await dependentObservation.start()
|
|
129
163
|
}
|
|
130
164
|
}
|
|
@@ -136,21 +170,7 @@ async function simpleQuery(input, output, { _query, ...params }) {
|
|
|
136
170
|
//output.debug(this.#planStep.execution.alias, "oldJoinedResults", oldJoinedResults, "from", oldObj)
|
|
137
171
|
//output.debug(this.#planStep.execution.alias, "newJoinedResults", newJoinedResults, "from", obj)
|
|
138
172
|
|
|
139
|
-
|
|
140
|
-
if(!oldJoinedResult) throw new Error("oldJoinedResult is null")
|
|
141
|
-
if(!newJoinedResults.some(newResult => newResult.id === oldJoinedResult.id))
|
|
142
|
-
this.#joinedChange(null, oldJoinedResult)
|
|
143
|
-
}
|
|
144
|
-
for(const newJoinedResult of newJoinedResults) {
|
|
145
|
-
const oldJoinedResult = oldJoinedResults.find(oldResult => oldResult.id === newJoinedResult.id)
|
|
146
|
-
if(oldJoinedResult) {
|
|
147
|
-
if(JSON.stringify(newJoinedResult) !== JSON.stringify(oldJoinedResult)) {
|
|
148
|
-
this.#joinedChange(newJoinedResult, oldJoinedResult)
|
|
149
|
-
}
|
|
150
|
-
} else {
|
|
151
|
-
this.#joinedChange(newJoinedResult, null)
|
|
152
|
-
}
|
|
153
|
-
}
|
|
173
|
+
await this.#joinedChanges(newJoinedResults, oldJoinedResults)
|
|
154
174
|
|
|
155
175
|
})
|
|
156
176
|
this.#resultsPromise = observationPromise.then(() => {
|
|
@@ -159,27 +179,27 @@ async function simpleQuery(input, output, { _query, ...params }) {
|
|
|
159
179
|
this.#observation = await observationPromise
|
|
160
180
|
}
|
|
161
181
|
|
|
162
|
-
async #joinedChange(obj, oldObj
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
182
|
+
async #joinedChange(obj, oldObj) {
|
|
183
|
+
applyChange(this.#results, obj, oldObj)
|
|
184
|
+
await this.#onChange(obj, oldObj, this)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
async #joinedChanges(newJoinedResults, oldJoinedResults) {
|
|
188
|
+
for(const oldJoinedResult of oldJoinedResults) {
|
|
189
|
+
if(!oldJoinedResult) throw new Error("oldJoinedResult is null")
|
|
190
|
+
if(!newJoinedResults.some(newResult => newResult.id === oldJoinedResult.id))
|
|
191
|
+
this.#joinedChange(null, oldJoinedResult)
|
|
192
|
+
}
|
|
193
|
+
for(const newJoinedResult of newJoinedResults) {
|
|
194
|
+
const oldJoinedResult = oldJoinedResults.find(oldResult => oldResult.id === newJoinedResult.id)
|
|
195
|
+
if(oldJoinedResult) {
|
|
196
|
+
if(JSON.stringify(newJoinedResult) !== JSON.stringify(oldJoinedResult)) {
|
|
197
|
+
this.#joinedChange(newJoinedResult, oldJoinedResult)
|
|
198
|
+
}
|
|
178
199
|
} else {
|
|
179
|
-
this.#
|
|
200
|
+
this.#joinedChange(newJoinedResult, null)
|
|
180
201
|
}
|
|
181
202
|
}
|
|
182
|
-
await this.#onChange(obj, oldObj, this)
|
|
183
203
|
}
|
|
184
204
|
|
|
185
205
|
async #joinResults(results) {
|
|
@@ -187,28 +207,42 @@ async function simpleQuery(input, output, { _query, ...params }) {
|
|
|
187
207
|
__result_id_patrs: [result.id],
|
|
188
208
|
[this.#planStep.execution.alias]: result
|
|
189
209
|
}))
|
|
190
|
-
//
|
|
191
|
-
for(const
|
|
192
|
-
const
|
|
210
|
+
//output.debug("joined results", joinedResults)
|
|
211
|
+
for(const nextId in this.#planStep.next) {
|
|
212
|
+
const nextDependentObservations = this.#dependentObservationsByNext[nextId]
|
|
213
|
+
const nextStep = this.#planStep.next[nextId]
|
|
193
214
|
// output.debug(" dep results", dependentObservation.#planStep.execution.alias, dependentResults)
|
|
194
|
-
joinedResults = joinedResults.
|
|
195
|
-
(joinedResult) => {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
215
|
+
joinedResults = (await Promise.all(joinedResults.map(
|
|
216
|
+
async (joinedResult) => {
|
|
217
|
+
const nextBy = decodeParameter(nextStep.execution.by, joinedResult, params)
|
|
218
|
+
const nextByKey = nextBy && serializeKeyData(nextBy)
|
|
219
|
+
const dependentObservation = nextDependentObservations.get(nextByKey)
|
|
220
|
+
let dependentResults = []
|
|
221
|
+
if(dependentObservation) {
|
|
222
|
+
dependentResults = await dependentObservation.results()
|
|
223
|
+
}
|
|
224
|
+
if(dependentResults.length === 0) {
|
|
225
|
+
if(nextStep.mandatory) return []
|
|
226
|
+
return [
|
|
227
|
+
{ /// TODO: check if optional (not mandatory)
|
|
228
|
+
...joinedResult,
|
|
229
|
+
[nextStep.execution.alias]: null
|
|
230
|
+
}
|
|
231
|
+
]
|
|
232
|
+
}
|
|
202
233
|
return dependentResults.map(dependentJoinedResult => ({
|
|
203
234
|
...dependentJoinedResult,
|
|
204
235
|
...joinedResult,
|
|
205
236
|
__result_id_patrs: joinedResult.__result_id_patrs.concat(dependentJoinedResult.__result_id_patrs)
|
|
206
237
|
}))
|
|
207
238
|
}
|
|
208
|
-
)
|
|
239
|
+
))).flat()
|
|
209
240
|
}
|
|
210
|
-
//output.debug("joinedResultsAfterDependencies", joinedResults)
|
|
211
|
-
for(const joinedResult of joinedResults) {
|
|
241
|
+
//output.debug("joinedResultsAfterDependencies", JSON.stringify(joinedResults, null, 2))
|
|
242
|
+
for(const joinedResult of joinedResults) {
|
|
243
|
+
/* if(this.#idFunction) {
|
|
244
|
+
output.debug("callIdFunction", _query.idFunction, "on", JSON.stringify(joinedResult, null, 2))
|
|
245
|
+
} */
|
|
212
246
|
joinedResult.id = serializeKey(
|
|
213
247
|
this.#idFunction ? this.#idFunction(joinedResult) : joinedResult.__result_id_patrs
|
|
214
248
|
)
|
|
@@ -223,28 +257,52 @@ async function simpleQuery(input, output, { _query, ...params }) {
|
|
|
223
257
|
|
|
224
258
|
async handleDependentChange(context, oldContext, observation, id) {
|
|
225
259
|
if(!this.#results) return
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
260
|
+
if(observation.#disposed) return
|
|
261
|
+
|
|
262
|
+
/* console.log("handleDependentChange", context, oldContext, id,
|
|
263
|
+
"observation", observation.#planStep.execution.alias,
|
|
264
|
+
"to", this.#planStep.execution.alias) */
|
|
265
|
+
|
|
266
|
+
const observationByJson = JSON.stringify(observation.#by)
|
|
267
|
+
|
|
268
|
+
const affectedRawResults = this.#rawResults.filter(result =>
|
|
269
|
+
JSON.stringify(decodeParameter(observation.#planStep.execution.by, {
|
|
270
|
+
[this.#planStep.execution.alias]: result
|
|
271
|
+
}, params)) === observationByJson
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
//console.log("affectedRawResults", affectedRawResults)
|
|
275
|
+
|
|
276
|
+
for(const affectedRawResult of affectedRawResults) {
|
|
277
|
+
const id = affectedRawResult.id
|
|
278
|
+
const newJoinedResults = await this.#joinResults([ affectedRawResult ])
|
|
279
|
+
const oldJoinedResults = this.#results.filter(
|
|
280
|
+
joinedResult => joinedResult[this.#planStep.execution.alias].id === id
|
|
281
|
+
)
|
|
282
|
+
//console.log("newJoinedResults", newJoinedResults)
|
|
283
|
+
//console.log("oldJoinedResults", oldJoinedResults)
|
|
284
|
+
await this.#joinedChanges(newJoinedResults, oldJoinedResults)
|
|
234
285
|
}
|
|
235
286
|
}
|
|
236
287
|
|
|
237
288
|
dispose() {
|
|
238
289
|
this.#observation.dispose()
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
290
|
+
for(const nextIndex in this.#dependentObservationsByNext) {
|
|
291
|
+
const nextDependentObservations = this.#dependentObservationsByNext[nextIndex]
|
|
292
|
+
for(const dependentObservation of nextDependentObservations.values()) {
|
|
293
|
+
dependentObservation.dispose()
|
|
294
|
+
}
|
|
295
|
+
nextDependentObservations.clear()
|
|
296
|
+
}
|
|
297
|
+
this.#results = []
|
|
298
|
+
this.#rawResults = []
|
|
242
299
|
this.#resultsPromise = null
|
|
243
300
|
this.#observation = null
|
|
244
301
|
this.#source = null
|
|
245
302
|
this.#by = null
|
|
246
303
|
this.#planStep = null
|
|
247
304
|
this.#context = null
|
|
305
|
+
this.#disposed = true
|
|
248
306
|
}
|
|
249
307
|
}
|
|
250
308
|
|