@live-change/simple-query 0.9.162 → 0.9.163
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 +86 -26
- package/src/simpleQuery.db.js +147 -54
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.163",
|
|
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.163",
|
|
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": "c410e1dacd07daed9a5c55367abd7f19d9a575cc"
|
|
34
34
|
}
|
package/src/query.ts
CHANGED
|
@@ -2,7 +2,16 @@ import {
|
|
|
2
2
|
PropertyDefinitionSpecification, ServiceDefinition, ServiceDefinitionSpecification
|
|
3
3
|
} from "@live-change/framework"
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
ModelDefinition, ForeignModelDefinition, ContextBase, QueryParameters as FrameworkQueryParameters,
|
|
7
|
+
QueryDefinition as FrameworkQueryDefinition,
|
|
8
|
+
QueryDefinitionSpecification as FrameworkQueryDefinitionSpecification,
|
|
9
|
+
ViewDefinition,
|
|
10
|
+
EventDefinition,
|
|
11
|
+
TriggerDefinition,
|
|
12
|
+
ActionDefinition,
|
|
13
|
+
ViewDefinitionSpecificationDaoPath
|
|
14
|
+
} from "@live-change/framework"
|
|
6
15
|
|
|
7
16
|
import { PropertyDefinition } from "@live-change/framework"
|
|
8
17
|
|
|
@@ -17,7 +26,7 @@ const simpleQueryCode = readFileSync(simpleQueryCodePath, 'utf8')
|
|
|
17
26
|
|
|
18
27
|
|
|
19
28
|
interface Range {
|
|
20
|
-
gt?: string
|
|
29
|
+
gt?: string
|
|
21
30
|
gte?: string
|
|
22
31
|
lt?: string
|
|
23
32
|
lte?: string,
|
|
@@ -51,7 +60,6 @@ class RuleSource {
|
|
|
51
60
|
dependsOn: RuleSource[]
|
|
52
61
|
index: IndexInfo | null
|
|
53
62
|
|
|
54
|
-
|
|
55
63
|
constructor(rule: QueryRule, input: QueryInput, source: QuerySource, type: string) {
|
|
56
64
|
this.rule = rule
|
|
57
65
|
this.input = input
|
|
@@ -94,6 +102,14 @@ interface QueryDefinitionSpecification {
|
|
|
94
102
|
sources?: Record<string, QuerySource>,
|
|
95
103
|
code?: QueryCode,
|
|
96
104
|
update?: boolean,
|
|
105
|
+
id: Function | string,
|
|
106
|
+
timeout?: number,
|
|
107
|
+
requestTimeout?: number,
|
|
108
|
+
validation?: (parameters: FrameworkQueryParameters, context: ContextBase) => Promise<any>
|
|
109
|
+
view?: Record<string, any>
|
|
110
|
+
event?: Record<string, any>
|
|
111
|
+
trigger?: Record<string, any>
|
|
112
|
+
action?: Record<string, any>
|
|
97
113
|
}
|
|
98
114
|
|
|
99
115
|
class OutputMapping {
|
|
@@ -181,7 +197,8 @@ class IndexInfo {
|
|
|
181
197
|
$_createQuery(service: ServiceDefinition<any>) {
|
|
182
198
|
return new QueryDefinition(service, {
|
|
183
199
|
name: this.name,
|
|
184
|
-
properties: {}
|
|
200
|
+
properties: {},
|
|
201
|
+
id: (x:any) => x
|
|
185
202
|
}, this.rules)
|
|
186
203
|
}
|
|
187
204
|
}
|
|
@@ -207,6 +224,8 @@ export class QueryDefinition<SDS extends ServiceDefinitionSpecification> {
|
|
|
207
224
|
executionPlan: ExecutionStep[]
|
|
208
225
|
indexPlan: ExecutionStep[]
|
|
209
226
|
|
|
227
|
+
preparedQuery: FrameworkQueryDefinition<FrameworkQueryDefinitionSpecification>
|
|
228
|
+
|
|
210
229
|
constructor(
|
|
211
230
|
serviceDefinition: ServiceDefinition<SDS>, definition: QueryDefinitionSpecification, rules: QueryRule[] = undefined
|
|
212
231
|
) {
|
|
@@ -340,7 +359,7 @@ export class QueryDefinition<SDS extends ServiceDefinitionSpecification> {
|
|
|
340
359
|
for(const key in this.rules) {
|
|
341
360
|
const rule = this.rules[key]
|
|
342
361
|
console.log(`${indent} RULE ${key}:`)
|
|
343
|
-
console.log(`${indent} ${queryDescription(rule, indent + ' ')}`)
|
|
362
|
+
console.log(`${indent} ${queryDescription(rule, indent + ' ')}`)
|
|
344
363
|
console.log(`${indent} SOURCES:`)
|
|
345
364
|
for(const ruleSource of this.ruleSources) {
|
|
346
365
|
if(ruleSource.rule !== rule) continue
|
|
@@ -377,32 +396,33 @@ export class QueryDefinition<SDS extends ServiceDefinitionSpecification> {
|
|
|
377
396
|
}
|
|
378
397
|
}
|
|
379
398
|
|
|
380
|
-
computeSourceExecutionPlan(source: RuleSource, resultParameters: string[]) {
|
|
381
|
-
/// TODO:
|
|
382
|
-
/// Poza tym przy pobieraniu wstecz nie koniecznie potrzeba indexów,
|
|
383
|
-
/// może trzeba wprowadzić index-forward i index-backward ?
|
|
384
|
-
/// A może trzeba wprowadzić analizę tego co mamy i co chcemy uzyskać w przyszłości ?
|
|
399
|
+
computeSourceExecutionPlan(source: RuleSource, resultParameters: string[]) {
|
|
400
|
+
/// TODO: Może trzeba wprowadzić analizę tego co mamy i co chcemy uzyskać w przyszłości ?
|
|
385
401
|
|
|
386
402
|
const next = source.dependentBy.map(dependent => {
|
|
387
403
|
const otherSource = this.ruleSources.find(s => s.rule === dependent.rule && s != dependent)
|
|
388
|
-
|
|
404
|
+
const nextStep = this.computeSourceExecutionPlan(otherSource, [...resultParameters, source.input.$alias])
|
|
405
|
+
return nextStep
|
|
389
406
|
})
|
|
390
407
|
|
|
391
408
|
console.log("COMPUTING SOURCE EXECUTION PLAN FOR", source.input.$_toQueryDescription(), "WITH", resultParameters)
|
|
392
409
|
console.log("RULE", queryDescription(source.rule, ' '))
|
|
393
410
|
|
|
394
411
|
const ruleParameters = JSON.parse(JSON.stringify(source.rule.$_parametersJSON(resultParameters)))
|
|
412
|
+
console.log("RULE PARAMETERS", ruleParameters)
|
|
395
413
|
if(source.index) {
|
|
396
414
|
const indexExecution = {
|
|
397
415
|
...source.index.$_executionJSON(),
|
|
398
|
-
by: ruleParameters[Object.keys(ruleParameters)[0]]
|
|
416
|
+
by: parameterEnsureRange(ruleParameters[Object.keys(ruleParameters)[0]])
|
|
399
417
|
}
|
|
400
418
|
const indexNext = [{
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
419
|
+
execution: {
|
|
420
|
+
operation: 'object',
|
|
421
|
+
...source.input.$_executionJSON(),
|
|
422
|
+
by: {
|
|
423
|
+
type: 'result',
|
|
424
|
+
path: [indexExecution.alias, source.index.indexParts.at(-1).alias],
|
|
425
|
+
},
|
|
406
426
|
},
|
|
407
427
|
next
|
|
408
428
|
}]
|
|
@@ -612,13 +632,34 @@ export class QueryDefinition<SDS extends ServiceDefinitionSpecification> {
|
|
|
612
632
|
console.log("EXECUTION PLAN:")
|
|
613
633
|
console.log(JSON.stringify(this.executionPlan, null, 2))
|
|
614
634
|
|
|
615
|
-
process.exit(0)
|
|
616
|
-
/// TODO: create indexes used by query
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
/// TODO: prepare query
|
|
635
|
+
//process.exit(0)
|
|
620
636
|
|
|
621
|
-
|
|
637
|
+
const idFunctionCode = (typeof this.definition.id === 'string')
|
|
638
|
+
? this.definition.id : `(${this.definition.id})`
|
|
639
|
+
|
|
640
|
+
console.log("ID FUNCTION", idFunctionCode)
|
|
641
|
+
|
|
642
|
+
this.preparedQuery = this.service.query({
|
|
643
|
+
name: this.definition.name,
|
|
644
|
+
properties: this.definition.properties,
|
|
645
|
+
returns: this.definition.returns,
|
|
646
|
+
code: simpleQueryCode,
|
|
647
|
+
sourceName: simpleQueryCodePath,
|
|
648
|
+
update: this.definition.update,
|
|
649
|
+
timeout: this.definition.timeout,
|
|
650
|
+
requestTimeout: this.definition.requestTimeout,
|
|
651
|
+
validation: this.definition.validation,
|
|
652
|
+
config: {
|
|
653
|
+
plan: this.executionPlan,
|
|
654
|
+
idFunction: idFunctionCode
|
|
655
|
+
},
|
|
656
|
+
view: this.definition.view,
|
|
657
|
+
trigger: this.definition.trigger,
|
|
658
|
+
action: this.definition.action,
|
|
659
|
+
event: this.definition.event
|
|
660
|
+
})
|
|
661
|
+
|
|
662
|
+
return this.preparedQuery
|
|
622
663
|
}
|
|
623
664
|
|
|
624
665
|
createIndex(name, mapping: OutputMapping[]) {
|
|
@@ -649,6 +690,22 @@ export class QueryDefinition<SDS extends ServiceDefinitionSpecification> {
|
|
|
649
690
|
}
|
|
650
691
|
}
|
|
651
692
|
|
|
693
|
+
function parameterIsRange(parameter: any) {
|
|
694
|
+
if(typeof parameter !== 'object' || parameter === null) return false
|
|
695
|
+
if(Array.isArray(parameter)) return parameterIsRange(parameter.at(-1))
|
|
696
|
+
if(parameter.type === 'object') return true
|
|
697
|
+
return false
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
function parameterEnsureRange(parameter: any) {
|
|
701
|
+
if(parameterIsRange(parameter)) return parameter
|
|
702
|
+
if(Array.isArray(parameter)) return [...parameter, { type: 'object', properties: {} }]
|
|
703
|
+
return {
|
|
704
|
+
type: 'array',
|
|
705
|
+
items: [parameter, { type: 'object', properties: {} }]
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
|
|
652
709
|
|
|
653
710
|
export type QueryFactoryFunction<SDS extends ServiceDefinitionSpecification> =
|
|
654
711
|
(definition: QueryDefinitionSpecification) => QueryDefinition<SDS>
|
|
@@ -675,7 +732,9 @@ function getSource(input: RuleInput): QuerySource {
|
|
|
675
732
|
function isStatic(element: any) {
|
|
676
733
|
if(typeof element !== "object" || element === null) return true
|
|
677
734
|
return element instanceof CanBeStatic ? element.$_isStatic() :
|
|
678
|
-
(element.constructor.name === "Object"
|
|
735
|
+
((element.constructor.name === "Object" || element.constructor.name === "Array")
|
|
736
|
+
? element[staticRuleSymbol]
|
|
737
|
+
: false)
|
|
679
738
|
}
|
|
680
739
|
|
|
681
740
|
function queryDescription(element: any, indent: string = "") {
|
|
@@ -706,6 +765,7 @@ function markStatic(element: any) {
|
|
|
706
765
|
function parameterJSON(element: any) {
|
|
707
766
|
if(typeof element !== "object" || element === null) return element
|
|
708
767
|
if(element instanceof QueryPropertyBase) return { type: 'property', path: element.$path }
|
|
768
|
+
if(Array.isArray(element)) return element.map(item => parameterJSON(item))
|
|
709
769
|
const output = {
|
|
710
770
|
type: 'object',
|
|
711
771
|
properties: {}
|
|
@@ -768,7 +828,7 @@ export class RangeRule extends QueryRule {
|
|
|
768
828
|
$_getSources(): RuleSource[] {
|
|
769
829
|
return [
|
|
770
830
|
new RuleSource(this, this.$input, getSource(this.$input), 'range')
|
|
771
|
-
].filter(s => s.input != null)
|
|
831
|
+
].filter(s => s.input?.$source != null)
|
|
772
832
|
}
|
|
773
833
|
|
|
774
834
|
$_parametersJSON(resultParameters: string[]) {
|
|
@@ -814,7 +874,7 @@ export class EqualsRule extends QueryRule {
|
|
|
814
874
|
return [
|
|
815
875
|
new RuleSource(this, this.$inputA, getSource(this.$inputA), 'object'),
|
|
816
876
|
new RuleSource(this, this.$inputB, getSource(this.$inputB), 'object')
|
|
817
|
-
].filter(s => s.input != null)
|
|
877
|
+
].filter(s => s.input?.$source != null)
|
|
818
878
|
}
|
|
819
879
|
|
|
820
880
|
$_parametersJSON(resultParameters: string[]) {
|
package/src/simpleQuery.db.js
CHANGED
|
@@ -1,11 +1,38 @@
|
|
|
1
1
|
async function simpleQuery(input, output, { _query, ...params }) {
|
|
2
2
|
|
|
3
3
|
const plan = _query.plan
|
|
4
|
-
const idFunction = idFunction && eval(`(${_query.idFunction})`)
|
|
4
|
+
const idFunction = _query.idFunction && eval(`(${_query.idFunction})`)
|
|
5
5
|
|
|
6
6
|
function sourceChangeStream(source, by) {
|
|
7
|
+
/// TODO: support arrays that have object - prefixed range queries
|
|
7
8
|
if(typeof by === 'string') return source.object(by)
|
|
8
|
-
if(Array.isArray(by))
|
|
9
|
+
if(Array.isArray(by)) {
|
|
10
|
+
if(typeof by.at(-1) === 'string') {
|
|
11
|
+
return source.object(serializeKey(by))
|
|
12
|
+
} else {
|
|
13
|
+
if(by.slice(0, -1).every(item => typeof item === 'string')) {
|
|
14
|
+
const prefix = serializeKeyData(by.slice(0, -1))
|
|
15
|
+
const range = by.at(-1)
|
|
16
|
+
const prefixedRange = {
|
|
17
|
+
gt: range.gt ? prefix + range.gt : undefined,
|
|
18
|
+
gte: range.gte ? prefix + range.gte : undefined,
|
|
19
|
+
lt: range.lt ? prefix + range.lt : undefined,
|
|
20
|
+
lte: range.lte ? prefix + range.lte : undefined,
|
|
21
|
+
reverse: range.reverse,
|
|
22
|
+
limit: range.limit,
|
|
23
|
+
}
|
|
24
|
+
if(!(prefixedRange.gt || prefixedRange.gte)) {
|
|
25
|
+
prefixedRange.gte = prefix
|
|
26
|
+
}
|
|
27
|
+
if(!(prefixedRange.lt || prefixedRange.lte)) {
|
|
28
|
+
prefixedRange.lte = prefix + "\xFF\xFF\xFF\xFF"
|
|
29
|
+
}
|
|
30
|
+
return source.range(prefixedRange)
|
|
31
|
+
} else {
|
|
32
|
+
throw new Error("Impossible to compute range from array: " + JSON.stringify(by))
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
9
36
|
return source.range(by)
|
|
10
37
|
}
|
|
11
38
|
|
|
@@ -50,14 +77,16 @@ async function simpleQuery(input, output, { _query, ...params }) {
|
|
|
50
77
|
#dependentObservations = new Map()
|
|
51
78
|
|
|
52
79
|
#resultsPromise = null
|
|
53
|
-
#results =
|
|
80
|
+
#results = []
|
|
81
|
+
#idFunction = null
|
|
54
82
|
|
|
55
|
-
constructor(planStep, context, source, by, onChange) {
|
|
83
|
+
constructor(planStep, context, source, by, onChange, idFunction) {
|
|
56
84
|
this.#planStep = planStep
|
|
57
85
|
this.#context = context
|
|
58
86
|
this.#source = source
|
|
59
87
|
this.#by = by
|
|
60
88
|
this.#onChange = onChange
|
|
89
|
+
this.#idFunction = idFunction
|
|
61
90
|
}
|
|
62
91
|
|
|
63
92
|
async start() {
|
|
@@ -65,46 +94,27 @@ async function simpleQuery(input, output, { _query, ...params }) {
|
|
|
65
94
|
const context = this.#context
|
|
66
95
|
if(!this.#source) this.#source = await getSource(planStep.execution.sourceType, planStep.execution.name)
|
|
67
96
|
if(!this.#by) this.#by = decodeParameter(planStep.execution.by, context, params)
|
|
68
|
-
|
|
69
|
-
const
|
|
97
|
+
//output.debug("STARTING OBSERVATION", planStep.execution.sourceType, planStep.execution.name, "BY", this.#by)
|
|
98
|
+
const sourceStream = sourceChangeStream(this.#source, this.#by)
|
|
99
|
+
const observationPromise = sourceStream.onChange(async (obj, oldObj) => {
|
|
100
|
+
/* output.debug(this.#planStep.execution.alias, "!", planStep.execution.sourceType, planStep.execution.name, "BY", this.#by,
|
|
101
|
+
'CHANGE', obj, oldObj) */
|
|
70
102
|
const id = obj?.id || oldObj?.id
|
|
71
103
|
if(!id) return
|
|
72
104
|
|
|
73
|
-
if(!this.#results) { // still fetching
|
|
74
|
-
results.push(obj)
|
|
75
|
-
} else { // already fetched - maintain memory list of results
|
|
76
|
-
if(oldObj) {
|
|
77
|
-
const index = this.#results.findIndex(result => result.id === oldObj.id)
|
|
78
|
-
if(index !== -1) {
|
|
79
|
-
if(obj) {
|
|
80
|
-
this.#results[index] = obj
|
|
81
|
-
} else {
|
|
82
|
-
this.#results.splice(index, 1)
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
} else if(obj) {
|
|
86
|
-
const index = this.#results.findIndex(result => result.id >= oldObj.id) // idempotency check
|
|
87
|
-
if(index === -1) {
|
|
88
|
-
results.push(obj)
|
|
89
|
-
} else if(this.#results[index].id === oldObj.id) {
|
|
90
|
-
this.#results[index] = obj
|
|
91
|
-
} else {
|
|
92
|
-
this.#results.splice(index, 0, obj)
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
105
|
const nextContext = { ...context, [planStep.execution.alias]: obj }
|
|
98
106
|
const nextOldContext = { ...context, [planStep.execution.alias]: oldObj }
|
|
99
107
|
|
|
100
|
-
const objectObservations = []
|
|
108
|
+
//const objectObservations = []
|
|
109
|
+
|
|
110
|
+
const oldJoinedResults = oldObj ? await this.#joinResults([ oldObj ]) : []
|
|
101
111
|
|
|
102
112
|
for(const nextStep of planStep.next) {
|
|
103
113
|
const nextSource = await getSource(nextStep.execution.sourceType, nextStep.execution.name)
|
|
104
114
|
const nextBy = decodeParameter(nextStep.execution.by, nextContext, params)
|
|
105
115
|
const nextOldBy = decodeParameter(nextStep.execution.by, nextOldContext, params)
|
|
106
|
-
const nextByKey = nextBy &&
|
|
107
|
-
const nextOldByKey = nextOldBy &&
|
|
116
|
+
const nextByKey = nextBy && serializeKeyData([nextStep.execution.alias, nextBy])
|
|
117
|
+
const nextOldByKey = nextOldBy && serializeKeyData([nextStep.execution.alias, nextOldBy])
|
|
108
118
|
if(nextByKey !== nextOldByKey) {
|
|
109
119
|
if(this.#dependentObservations.has(nextOldByKey)) {
|
|
110
120
|
const dependentObservation = this.#dependentObservations.get(nextOldByKey)
|
|
@@ -118,36 +128,110 @@ async function simpleQuery(input, output, { _query, ...params }) {
|
|
|
118
128
|
await dependentObservation.start()
|
|
119
129
|
}
|
|
120
130
|
}
|
|
121
|
-
if(nextByKey) objectObservations.push(this.#dependentObservations.get(nextByKey))
|
|
131
|
+
//if(nextByKey) objectObservations.push(this.#dependentObservations.get(nextByKey))
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const newJoinedResults = obj ? await this.#joinResults([ obj ]) : []
|
|
135
|
+
|
|
136
|
+
//output.debug(this.#planStep.execution.alias, "oldJoinedResults", oldJoinedResults, "from", oldObj)
|
|
137
|
+
//output.debug(this.#planStep.execution.alias, "newJoinedResults", newJoinedResults, "from", obj)
|
|
138
|
+
|
|
139
|
+
for(const oldJoinedResult of oldJoinedResults) {
|
|
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
|
+
}
|
|
122
153
|
}
|
|
123
154
|
|
|
124
|
-
/// TODO: do object observations cross product, add self, and push change to parent
|
|
125
155
|
})
|
|
126
156
|
this.#resultsPromise = observationPromise.then(() => {
|
|
127
|
-
this.#results
|
|
128
|
-
return results
|
|
157
|
+
return this.#results
|
|
129
158
|
})
|
|
130
159
|
this.#observation = await observationPromise
|
|
131
160
|
}
|
|
132
161
|
|
|
162
|
+
async #joinedChange(obj, oldObj, observation) {
|
|
163
|
+
if(oldObj) {
|
|
164
|
+
const index = this.#results.findIndex(result => result.id === oldObj.id)
|
|
165
|
+
if(index !== -1) {
|
|
166
|
+
if(obj) {
|
|
167
|
+
this.#results[index] = obj
|
|
168
|
+
} else {
|
|
169
|
+
this.#results.splice(index, 1)
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
} else if(obj) {
|
|
173
|
+
const index = this.#results.findIndex(result => result.id >= obj.id)
|
|
174
|
+
if(index === -1) {
|
|
175
|
+
this.#results.push(obj)
|
|
176
|
+
} else if(this.#results[index].id === obj.id) {
|
|
177
|
+
this.#results[index] = obj
|
|
178
|
+
} else {
|
|
179
|
+
this.#results.splice(index, 0, obj)
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
await this.#onChange(obj, oldObj, this)
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
async #joinResults(results) {
|
|
186
|
+
let joinedResults = results.map(result => ({
|
|
187
|
+
__result_id_patrs: [result.id],
|
|
188
|
+
[this.#planStep.execution.alias]: result
|
|
189
|
+
}))
|
|
190
|
+
// output.debug("joined results", joinedResults)
|
|
191
|
+
for(const dependentObservation of this.#dependentObservations.values()) {
|
|
192
|
+
const dependentResults = await dependentObservation.results()
|
|
193
|
+
// output.debug(" dep results", dependentObservation.#planStep.execution.alias, dependentResults)
|
|
194
|
+
joinedResults = joinedResults.flatMap(
|
|
195
|
+
(joinedResult) => {
|
|
196
|
+
if(dependentResults.length === 0) return [
|
|
197
|
+
{ /// TODO: check if optional (not mandatory)
|
|
198
|
+
...joinedResult,
|
|
199
|
+
[dependentObservation.#planStep.execution.alias]: null
|
|
200
|
+
}
|
|
201
|
+
]
|
|
202
|
+
return dependentResults.map(dependentJoinedResult => ({
|
|
203
|
+
...dependentJoinedResult,
|
|
204
|
+
...joinedResult,
|
|
205
|
+
__result_id_patrs: joinedResult.__result_id_patrs.concat(dependentJoinedResult.__result_id_patrs)
|
|
206
|
+
}))
|
|
207
|
+
}
|
|
208
|
+
)
|
|
209
|
+
}
|
|
210
|
+
//output.debug("joinedResultsAfterDependencies", joinedResults)
|
|
211
|
+
for(const joinedResult of joinedResults) {
|
|
212
|
+
joinedResult.id = serializeKey(
|
|
213
|
+
this.#idFunction ? this.#idFunction(joinedResult) : joinedResult.__result_id_patrs
|
|
214
|
+
)
|
|
215
|
+
}
|
|
216
|
+
return joinedResults
|
|
217
|
+
}
|
|
218
|
+
|
|
133
219
|
async results() {
|
|
134
220
|
if(!this.#results) return this.#results
|
|
135
221
|
return await this.#resultsPromise
|
|
136
222
|
}
|
|
137
223
|
|
|
138
224
|
async handleDependentChange(context, oldContext, observation, id) {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
...currentContext,
|
|
150
|
-
}, this)
|
|
225
|
+
if(!this.#results) return
|
|
226
|
+
// we need to find thre results affected by the change
|
|
227
|
+
for(const result of this.#results) { // bunary search can be used here for better performance
|
|
228
|
+
if(result.__result_id_patrs[0] === id) {
|
|
229
|
+
const oldResult = { ...result }
|
|
230
|
+
const alias = observation.#planStep.execution.alias
|
|
231
|
+
result[alias] = context[alias]
|
|
232
|
+
this.#onChange(result, oldResult, observation) /// TODO: handle cases when part is mandatory
|
|
233
|
+
}
|
|
234
|
+
}
|
|
151
235
|
}
|
|
152
236
|
|
|
153
237
|
dispose() {
|
|
@@ -164,12 +248,21 @@ async function simpleQuery(input, output, { _query, ...params }) {
|
|
|
164
248
|
}
|
|
165
249
|
}
|
|
166
250
|
|
|
167
|
-
const rootObservations = plan.map(step => new DataObservation(step, {}, null, null,
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
251
|
+
const rootObservations = plan.map(step => new DataObservation(step, {}, null, null,
|
|
252
|
+
(result, oldResult, observation) => {
|
|
253
|
+
if(result) delete result.__result_id_patrs
|
|
254
|
+
if(oldResult) delete oldResult.__result_id_patrs
|
|
255
|
+
output.change(result, oldResult)
|
|
256
|
+
},
|
|
257
|
+
idFunction
|
|
258
|
+
/* async (newContext, oldContext, observation) => {
|
|
259
|
+
const idParts = idFunction ? idFunction(newContext) : Object.values(newContext).map(v => v?.id)
|
|
260
|
+
const id = serializeKey(idParts)
|
|
261
|
+
await output.change({ ...newContext, id }, { ...oldContext, id })
|
|
262
|
+
} */
|
|
263
|
+
))
|
|
172
264
|
|
|
173
265
|
await Promise.all(rootObservations.map(observation => observation.start()))
|
|
266
|
+
await Promise.all(rootObservations.map(observation => observation.results()))
|
|
174
267
|
|
|
175
268
|
}
|