@skipruntime/core 0.0.16 → 0.0.17
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/dist/src/api.d.ts +2 -2
- package/dist/src/api.d.ts.map +1 -1
- package/dist/src/binding.d.ts +20 -25
- package/dist/src/binding.d.ts.map +1 -1
- package/dist/src/binding.js.map +1 -1
- package/dist/src/index.d.ts +109 -35
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +530 -194
- package/dist/src/index.js.map +1 -1
- package/dist/src/internal.d.ts +0 -2
- package/dist/src/internal.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/api.ts +2 -2
- package/src/binding.ts +28 -63
- package/src/index.ts +715 -317
- package/src/internal.ts +0 -3
package/src/index.ts
CHANGED
|
@@ -26,7 +26,6 @@ import {
|
|
|
26
26
|
type Context,
|
|
27
27
|
type EagerCollection,
|
|
28
28
|
type Entry,
|
|
29
|
-
type ExternalService,
|
|
30
29
|
type LazyCollection,
|
|
31
30
|
type LazyCompute,
|
|
32
31
|
type Mapper,
|
|
@@ -37,6 +36,7 @@ import {
|
|
|
37
36
|
type Resource,
|
|
38
37
|
type SkipService,
|
|
39
38
|
type Watermark,
|
|
39
|
+
type ExternalService,
|
|
40
40
|
} from "./api.js";
|
|
41
41
|
|
|
42
42
|
import {
|
|
@@ -46,25 +46,26 @@ import {
|
|
|
46
46
|
SkipResourceInstanceInUseError,
|
|
47
47
|
SkipUnknownCollectionError,
|
|
48
48
|
} from "./errors.js";
|
|
49
|
-
import {
|
|
50
|
-
ResourceBuilder,
|
|
51
|
-
type Notifier,
|
|
52
|
-
type Executor,
|
|
53
|
-
type Handle,
|
|
54
|
-
type FromBinding,
|
|
55
|
-
} from "./binding.js";
|
|
49
|
+
import { type Notifier, type Handle, type FromBinding } from "./binding.js";
|
|
56
50
|
|
|
57
51
|
export * from "./api.js";
|
|
58
52
|
export * from "./errors.js";
|
|
59
53
|
|
|
60
54
|
export type JSONMapper = Mapper<Json, Json, Json, Json>;
|
|
61
55
|
export type JSONLazyCompute = LazyCompute<Json, Json>;
|
|
56
|
+
export type JSONOperator = JSONMapper | JSONLazyCompute | Reducer<Json, Json>;
|
|
57
|
+
|
|
58
|
+
export type HandlerInfo<P> = {
|
|
59
|
+
object: P;
|
|
60
|
+
name: string;
|
|
61
|
+
params: DepSafe[];
|
|
62
|
+
};
|
|
62
63
|
|
|
63
64
|
function instantiateUserObject<Params extends DepSafe[], Result extends object>(
|
|
64
65
|
what: string,
|
|
65
66
|
ctor: new (...params: Params) => Result,
|
|
66
67
|
params: Params,
|
|
67
|
-
): Result {
|
|
68
|
+
): HandlerInfo<Result> {
|
|
68
69
|
const checkedParams = params.map(checkOrCloneParam) as Params;
|
|
69
70
|
const obj = new ctor(...checkedParams);
|
|
70
71
|
Object.freeze(obj);
|
|
@@ -73,7 +74,118 @@ function instantiateUserObject<Params extends DepSafe[], Result extends object>(
|
|
|
73
74
|
`${what} classes must be defined at top-level.`,
|
|
74
75
|
);
|
|
75
76
|
}
|
|
76
|
-
return
|
|
77
|
+
return {
|
|
78
|
+
object: obj,
|
|
79
|
+
name: obj.constructor.name,
|
|
80
|
+
params: checkedParams,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export enum LoadStatus {
|
|
85
|
+
Incompatible,
|
|
86
|
+
Changed,
|
|
87
|
+
Same,
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export interface ChangeManager {
|
|
91
|
+
needInputReload(name: string): boolean;
|
|
92
|
+
needResourceReload(name: string): LoadStatus;
|
|
93
|
+
needExternalServiceReload(name: string, resource: string): boolean;
|
|
94
|
+
needMapperReload(name: string): boolean;
|
|
95
|
+
needReducerReload(name: string): boolean;
|
|
96
|
+
needLazyComputeReload(name: string): boolean;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export class ServiceDefinition {
|
|
100
|
+
constructor(
|
|
101
|
+
private service: SkipService,
|
|
102
|
+
private readonly externals: Map<string, ExternalService> = new Map(),
|
|
103
|
+
) {}
|
|
104
|
+
|
|
105
|
+
buildResource(name: string, parameters: Json): Resource {
|
|
106
|
+
const builder = this.service.resources[name];
|
|
107
|
+
if (!builder) throw new Error(`Resource '${name}' not exist.`);
|
|
108
|
+
return new builder(parameters);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
inputs(): string[] {
|
|
112
|
+
return this.service.initialData
|
|
113
|
+
? Object.keys(this.service.initialData)
|
|
114
|
+
: [];
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
resources(): string[] {
|
|
118
|
+
return Object.keys(this.service.resources);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
initialData(name: string): Entry<Json, Json>[] {
|
|
122
|
+
if (!this.service.initialData) throw new Error(`No initial data defined.`);
|
|
123
|
+
const data = this.service.initialData[name];
|
|
124
|
+
if (!data) throw new Error(`Initial data '${name}' not exist.`);
|
|
125
|
+
return data;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
createGraph(
|
|
129
|
+
inputCollections: NamedCollections,
|
|
130
|
+
context: Context,
|
|
131
|
+
): NamedCollections {
|
|
132
|
+
return this.service.createGraph(inputCollections, context);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
subscribe(
|
|
136
|
+
external: string,
|
|
137
|
+
writer: CollectionWriter<Json, Json>,
|
|
138
|
+
instance: string,
|
|
139
|
+
resource: string,
|
|
140
|
+
params: Json,
|
|
141
|
+
): Promise<void> {
|
|
142
|
+
if (!this.service.externalServices)
|
|
143
|
+
throw new Error(`No external services defined.`);
|
|
144
|
+
const supplier = this.service.externalServices[external];
|
|
145
|
+
if (!supplier)
|
|
146
|
+
throw new Error(`External services '${external}' not exist.`);
|
|
147
|
+
this.externals.set(`${external}/${instance}`, supplier);
|
|
148
|
+
// Ensure notification is made outside the current context update
|
|
149
|
+
return new Promise((resolve, reject) => {
|
|
150
|
+
setTimeout(() => {
|
|
151
|
+
supplier
|
|
152
|
+
.subscribe(instance, resource, params, {
|
|
153
|
+
update: writer.update.bind(writer),
|
|
154
|
+
error: (_) => {},
|
|
155
|
+
})
|
|
156
|
+
.then(resolve)
|
|
157
|
+
.catch(reject);
|
|
158
|
+
}, 0);
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
unsubscribe(external: string, instance: string) {
|
|
163
|
+
if (!this.service.externalServices)
|
|
164
|
+
throw new Error(`No external services defined.`);
|
|
165
|
+
const supplier = this.externals.get(`${external}/${instance}`);
|
|
166
|
+
if (!supplier)
|
|
167
|
+
throw new Error(`External services '${external}/${instance}' not exist.`);
|
|
168
|
+
supplier.unsubscribe(instance);
|
|
169
|
+
this.externals.delete(`${external}/${instance}`);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
async shutdown(): Promise<void> {
|
|
173
|
+
const promises: Promise<void>[] = [];
|
|
174
|
+
const uniqueServices = new Set(this.externals.values());
|
|
175
|
+
if (this.service.externalServices) {
|
|
176
|
+
for (const es of Object.values(this.service.externalServices)) {
|
|
177
|
+
uniqueServices.add(es);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
for (const es of uniqueServices) {
|
|
181
|
+
promises.push(es.shutdown());
|
|
182
|
+
}
|
|
183
|
+
await Promise.all(promises);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
derive(service: SkipService): ServiceDefinition {
|
|
187
|
+
return new ServiceDefinition(service, new Map(this.externals));
|
|
188
|
+
}
|
|
77
189
|
}
|
|
78
190
|
|
|
79
191
|
class Handles {
|
|
@@ -122,35 +234,27 @@ export class Stack {
|
|
|
122
234
|
}
|
|
123
235
|
}
|
|
124
236
|
|
|
125
|
-
export class Refs {
|
|
126
|
-
constructor(
|
|
127
|
-
public readonly binding: FromBinding,
|
|
128
|
-
public readonly skjson: JsonConverter,
|
|
129
|
-
public readonly handles: Handles,
|
|
130
|
-
public readonly needGC: () => boolean,
|
|
131
|
-
public readonly runWithGC: <T>(fn: () => T) => T,
|
|
132
|
-
) {}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
237
|
class LazyCollectionImpl<K extends Json, V extends Json>
|
|
136
238
|
extends SkManaged
|
|
137
239
|
implements LazyCollection<K, V>
|
|
138
240
|
{
|
|
139
241
|
constructor(
|
|
140
|
-
|
|
141
|
-
private readonly refs:
|
|
242
|
+
readonly lazyCollection: string,
|
|
243
|
+
private readonly refs: ToBinding,
|
|
142
244
|
) {
|
|
143
245
|
super();
|
|
144
246
|
Object.freeze(this);
|
|
145
247
|
}
|
|
146
248
|
|
|
147
249
|
getArray(key: K): (V & DepSafe)[] {
|
|
148
|
-
return this.refs
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
this.refs.
|
|
152
|
-
|
|
153
|
-
|
|
250
|
+
return this.refs
|
|
251
|
+
.json()
|
|
252
|
+
.importJSON(
|
|
253
|
+
this.refs.binding.SkipRuntime_LazyCollection__getArray(
|
|
254
|
+
this.lazyCollection,
|
|
255
|
+
this.refs.json().exportJSON(key),
|
|
256
|
+
),
|
|
257
|
+
) as (V & DepSafe)[];
|
|
154
258
|
}
|
|
155
259
|
|
|
156
260
|
getUnique(key: K, _default?: { ifNone?: V; ifMany?: V }): V & DepSafe {
|
|
@@ -174,19 +278,21 @@ class EagerCollectionImpl<K extends Json, V extends Json>
|
|
|
174
278
|
{
|
|
175
279
|
constructor(
|
|
176
280
|
public readonly collection: string,
|
|
177
|
-
private readonly refs:
|
|
281
|
+
private readonly refs: ToBinding,
|
|
178
282
|
) {
|
|
179
283
|
super();
|
|
180
284
|
Object.freeze(this);
|
|
181
285
|
}
|
|
182
286
|
|
|
183
287
|
getArray(key: K): (V & DepSafe)[] {
|
|
184
|
-
return this.refs
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
this.refs.
|
|
188
|
-
|
|
189
|
-
|
|
288
|
+
return this.refs
|
|
289
|
+
.json()
|
|
290
|
+
.importJSON(
|
|
291
|
+
this.refs.binding.SkipRuntime_Collection__getArray(
|
|
292
|
+
this.collection,
|
|
293
|
+
this.refs.json().exportJSON(key),
|
|
294
|
+
),
|
|
295
|
+
) as (V & DepSafe)[];
|
|
190
296
|
}
|
|
191
297
|
|
|
192
298
|
getUnique(key: K, _default?: { ifNone?: V; ifMany?: V }): V & DepSafe {
|
|
@@ -216,7 +322,7 @@ class EagerCollectionImpl<K extends Json, V extends Json>
|
|
|
216
322
|
slices(...ranges: [K, K][]): EagerCollection<K, V> {
|
|
217
323
|
const skcollection = this.refs.binding.SkipRuntime_Collection__slice(
|
|
218
324
|
this.collection,
|
|
219
|
-
this.refs.
|
|
325
|
+
this.refs.json().exportJSON(ranges),
|
|
220
326
|
);
|
|
221
327
|
return this.derive<K, V>(skcollection);
|
|
222
328
|
}
|
|
@@ -263,18 +369,20 @@ class EagerCollectionImpl<K extends Json, V extends Json>
|
|
|
263
369
|
this.refs.handles.register(mapperObj),
|
|
264
370
|
);
|
|
265
371
|
|
|
266
|
-
if (
|
|
372
|
+
if (
|
|
373
|
+
sknative in reducerObj.object &&
|
|
374
|
+
typeof reducerObj.object[sknative] == "string"
|
|
375
|
+
) {
|
|
267
376
|
return this.derive<K2, Accum>(
|
|
268
377
|
this.refs.binding.SkipRuntime_Collection__nativeMapReduce(
|
|
269
378
|
this.collection,
|
|
270
379
|
skmapper,
|
|
271
|
-
reducerObj[sknative],
|
|
380
|
+
reducerObj.object[sknative],
|
|
272
381
|
),
|
|
273
382
|
);
|
|
274
383
|
} else {
|
|
275
384
|
const skreducer = this.refs.binding.SkipRuntime_createReducer(
|
|
276
385
|
this.refs.handles.register(reducerObj),
|
|
277
|
-
this.refs.skjson.exportJSON(reducerObj.initial),
|
|
278
386
|
);
|
|
279
387
|
return this.derive<K2, Accum>(
|
|
280
388
|
this.refs.binding.SkipRuntime_Collection__mapReduce(
|
|
@@ -292,17 +400,19 @@ class EagerCollectionImpl<K extends Json, V extends Json>
|
|
|
292
400
|
...params: Params
|
|
293
401
|
): EagerCollection<K, Accum> {
|
|
294
402
|
const reducerObj = instantiateUserObject("Reducer", reducer, params);
|
|
295
|
-
if (
|
|
403
|
+
if (
|
|
404
|
+
sknative in reducerObj.object &&
|
|
405
|
+
typeof reducerObj.object[sknative] == "string"
|
|
406
|
+
) {
|
|
296
407
|
return this.derive<K, Accum>(
|
|
297
408
|
this.refs.binding.SkipRuntime_Collection__nativeReduce(
|
|
298
409
|
this.collection,
|
|
299
|
-
reducerObj[sknative],
|
|
410
|
+
reducerObj.object[sknative],
|
|
300
411
|
),
|
|
301
412
|
);
|
|
302
413
|
} else {
|
|
303
414
|
const skreducer = this.refs.binding.SkipRuntime_createReducer(
|
|
304
415
|
this.refs.handles.register(reducerObj),
|
|
305
|
-
this.refs.skjson.exportJSON(reducerObj.initial),
|
|
306
416
|
);
|
|
307
417
|
return this.derive<K, Accum>(
|
|
308
418
|
this.refs.binding.SkipRuntime_Collection__reduce(
|
|
@@ -319,7 +429,7 @@ class EagerCollectionImpl<K extends Json, V extends Json>
|
|
|
319
429
|
);
|
|
320
430
|
const mapped = this.refs.binding.SkipRuntime_Collection__merge(
|
|
321
431
|
this.collection,
|
|
322
|
-
this.refs.
|
|
432
|
+
this.refs.json().exportJSON(otherNames),
|
|
323
433
|
);
|
|
324
434
|
return this.derive<K, V>(mapped);
|
|
325
435
|
}
|
|
@@ -340,72 +450,71 @@ class EagerCollectionImpl<K extends Json, V extends Json>
|
|
|
340
450
|
class CollectionWriter<K extends Json, V extends Json> {
|
|
341
451
|
constructor(
|
|
342
452
|
public readonly collection: string,
|
|
343
|
-
private readonly refs:
|
|
453
|
+
private readonly refs: ToBinding,
|
|
454
|
+
private forkName: Nullable<string>,
|
|
344
455
|
) {}
|
|
345
456
|
|
|
346
457
|
async update(values: Entry<K, V>[], isInit: boolean): Promise<void> {
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
this.collection,
|
|
358
|
-
this.refs.skjson.exportJSON(values),
|
|
359
|
-
isInit,
|
|
360
|
-
this.refs.binding.SkipRuntime_createExecutor(exHdl),
|
|
361
|
-
);
|
|
362
|
-
});
|
|
363
|
-
if (errorHdl) reject(this.refs.handles.deleteHandle(errorHdl));
|
|
364
|
-
});
|
|
458
|
+
this.refs.setFork(this.forkName);
|
|
459
|
+
const uuid = crypto.randomUUID();
|
|
460
|
+
const fork = this.fork(uuid);
|
|
461
|
+
try {
|
|
462
|
+
await fork.update_(values, isInit);
|
|
463
|
+
fork.merge();
|
|
464
|
+
} catch (ex: unknown) {
|
|
465
|
+
fork.abortFork();
|
|
466
|
+
throw ex;
|
|
467
|
+
}
|
|
365
468
|
}
|
|
366
469
|
|
|
367
|
-
|
|
470
|
+
private update_(values: Entry<K, V>[], isInit: boolean): Promise<void> {
|
|
471
|
+
this.refs.setFork(this.getForkName());
|
|
368
472
|
if (!this.refs.needGC()) {
|
|
369
473
|
throw new SkipError("CollectionWriter.update cannot be performed.");
|
|
370
474
|
}
|
|
371
|
-
|
|
372
|
-
this.refs.binding.
|
|
475
|
+
return this.refs.runAsync(() =>
|
|
476
|
+
this.refs.binding.SkipRuntime_CollectionWriter__update(
|
|
373
477
|
this.collection,
|
|
374
|
-
this.refs.
|
|
478
|
+
this.refs.json().exportJSON(values),
|
|
479
|
+
isInit,
|
|
375
480
|
),
|
|
376
481
|
);
|
|
377
|
-
if (errorHdl) throw this.refs.handles.deleteHandle(errorHdl);
|
|
378
482
|
}
|
|
379
483
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
const errorHdl = this.refs.runWithGC(() =>
|
|
385
|
-
this.refs.binding.SkipRuntime_CollectionWriter__initialized(
|
|
386
|
-
this.collection,
|
|
387
|
-
this.refs.skjson.exportJSON(error ? this.toJSONError(error) : null),
|
|
388
|
-
),
|
|
389
|
-
);
|
|
390
|
-
if (errorHdl) throw this.refs.handles.deleteHandle(errorHdl);
|
|
484
|
+
private fork(name: string): CollectionWriter<K, V> {
|
|
485
|
+
this.refs.setFork(this.forkName);
|
|
486
|
+
this.refs.fork(name);
|
|
487
|
+
return new CollectionWriter(this.collection, this.refs, name);
|
|
391
488
|
}
|
|
392
489
|
|
|
393
|
-
private
|
|
394
|
-
if (
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
if (typeof error == "string") return error;
|
|
398
|
-
return JSON.parse(
|
|
399
|
-
JSON.stringify(error, Object.getOwnPropertyNames(error)),
|
|
400
|
-
) as Json;
|
|
490
|
+
private merge(): void {
|
|
491
|
+
if (!this.forkName) throw new Error("Unable to merge fork on main.");
|
|
492
|
+
this.refs.setFork(this.forkName);
|
|
493
|
+
this.refs.merge();
|
|
401
494
|
}
|
|
402
|
-
}
|
|
403
495
|
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
496
|
+
private abortFork(): void {
|
|
497
|
+
if (!this.forkName) throw new Error("Unable to abord fork on main.");
|
|
498
|
+
this.refs.setFork(this.forkName);
|
|
499
|
+
this.refs.abortFork();
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
private getForkName(): Nullable<string> {
|
|
503
|
+
const forkName = this.forkName;
|
|
504
|
+
if (!forkName) return null;
|
|
505
|
+
if (
|
|
506
|
+
!this.refs.runWithGC(() =>
|
|
507
|
+
this.refs.binding.SkipRuntime_Runtime__forkExists(forkName),
|
|
508
|
+
)
|
|
509
|
+
) {
|
|
510
|
+
this.forkName = null;
|
|
511
|
+
}
|
|
512
|
+
return this.forkName;
|
|
408
513
|
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
class ContextImpl implements Context {
|
|
517
|
+
constructor(private readonly refs: ToBinding) {}
|
|
409
518
|
|
|
410
519
|
createLazyCollection<
|
|
411
520
|
K extends Json,
|
|
@@ -433,15 +542,16 @@ class ContextImpl extends SkManaged implements Context {
|
|
|
433
542
|
this.refs.binding.SkipRuntime_Context__useExternalResource(
|
|
434
543
|
resource.service,
|
|
435
544
|
resource.identifier,
|
|
436
|
-
this.refs.
|
|
545
|
+
this.refs.json().exportJSON(resource.params ?? {}),
|
|
437
546
|
);
|
|
438
547
|
return new EagerCollectionImpl<K, V>(collection, this.refs);
|
|
439
548
|
}
|
|
440
549
|
|
|
441
550
|
jsonExtract(value: JsonObject, pattern: string): Json[] {
|
|
442
|
-
|
|
551
|
+
const skjson = this.refs.json();
|
|
552
|
+
return skjson.importJSON(
|
|
443
553
|
this.refs.binding.SkipRuntime_Context__jsonExtract(
|
|
444
|
-
|
|
554
|
+
skjson.exportJSON(value),
|
|
445
555
|
pattern,
|
|
446
556
|
),
|
|
447
557
|
) as Json[];
|
|
@@ -456,46 +566,39 @@ export class ServiceInstanceFactory {
|
|
|
456
566
|
}
|
|
457
567
|
}
|
|
458
568
|
|
|
459
|
-
type
|
|
460
|
-
payload: T;
|
|
461
|
-
errors: Json[];
|
|
462
|
-
};
|
|
463
|
-
|
|
464
|
-
export type SubscriptionID = Opaque<bigint, "subscription">;
|
|
569
|
+
export type SubscriptionID = Opaque<string, "subscription">;
|
|
465
570
|
|
|
466
571
|
/**
|
|
467
572
|
* A `ServiceInstance` is a running instance of a `SkipService`, providing access to its resources
|
|
468
573
|
* and operations to manage subscriptions and the service itself.
|
|
469
574
|
*/
|
|
470
575
|
export class ServiceInstance {
|
|
471
|
-
constructor(
|
|
576
|
+
constructor(
|
|
577
|
+
private readonly refs: ToBinding,
|
|
578
|
+
readonly forkName: Nullable<string>,
|
|
579
|
+
private definition: ServiceDefinition,
|
|
580
|
+
) {}
|
|
472
581
|
|
|
473
582
|
/**
|
|
474
583
|
* Instantiate a resource with some parameters and client session authentication token
|
|
475
584
|
* @param identifier - The resource instance identifier
|
|
476
585
|
* @param resource - A resource name, which must correspond to a key in this `SkipService`'s `resources` field
|
|
477
586
|
* @param params - Resource parameters, which will be passed to the resource constructor specified in this `SkipService`'s `resources` field
|
|
587
|
+
* @returns The resulting promise
|
|
478
588
|
*/
|
|
479
589
|
instantiateResource(
|
|
480
590
|
identifier: string,
|
|
481
591
|
resource: string,
|
|
482
592
|
params: Json,
|
|
483
593
|
): Promise<void> {
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
resource,
|
|
493
|
-
this.refs.skjson.exportJSON(params),
|
|
494
|
-
this.refs.binding.SkipRuntime_createExecutor(exHdl),
|
|
495
|
-
);
|
|
496
|
-
});
|
|
497
|
-
if (errorHdl) reject(this.refs.handles.deleteHandle(errorHdl));
|
|
498
|
-
});
|
|
594
|
+
this.refs.setFork(this.forkName);
|
|
595
|
+
return this.refs.runAsync(() =>
|
|
596
|
+
this.refs.binding.SkipRuntime_Runtime__createResource(
|
|
597
|
+
identifier,
|
|
598
|
+
resource,
|
|
599
|
+
this.refs.json().exportJSON(params),
|
|
600
|
+
),
|
|
601
|
+
);
|
|
499
602
|
}
|
|
500
603
|
|
|
501
604
|
/**
|
|
@@ -511,21 +614,21 @@ export class ServiceInstance {
|
|
|
511
614
|
const uuid = crypto.randomUUID();
|
|
512
615
|
await this.instantiateResource(uuid, resource, params);
|
|
513
616
|
try {
|
|
617
|
+
this.refs.setFork(this.forkName);
|
|
514
618
|
const result = this.refs.runWithGC(() => {
|
|
515
|
-
return this.refs
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
this.refs.
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
619
|
+
return this.refs
|
|
620
|
+
.json()
|
|
621
|
+
.importJSON(
|
|
622
|
+
this.refs.binding.SkipRuntime_Runtime__getAll(
|
|
623
|
+
resource,
|
|
624
|
+
this.refs.json().exportJSON(params),
|
|
625
|
+
),
|
|
626
|
+
true,
|
|
627
|
+
);
|
|
522
628
|
});
|
|
523
629
|
if (typeof result == "number")
|
|
524
630
|
throw this.refs.handles.deleteHandle(result as Handle<Error>);
|
|
525
|
-
|
|
526
|
-
if (info.errors.length > 0)
|
|
527
|
-
throw new SkipError(JSON.stringify(info.errors));
|
|
528
|
-
return info.payload;
|
|
631
|
+
return result as Entry<K, V>[];
|
|
529
632
|
} finally {
|
|
530
633
|
this.closeResourceInstance(uuid);
|
|
531
634
|
}
|
|
@@ -546,22 +649,21 @@ export class ServiceInstance {
|
|
|
546
649
|
const uuid = crypto.randomUUID();
|
|
547
650
|
await this.instantiateResource(uuid, resource, params);
|
|
548
651
|
try {
|
|
652
|
+
this.refs.setFork(this.forkName);
|
|
653
|
+
const skjson = this.refs.json();
|
|
549
654
|
const result = this.refs.runWithGC(() => {
|
|
550
|
-
return
|
|
655
|
+
return skjson.importJSON(
|
|
551
656
|
this.refs.binding.SkipRuntime_Runtime__getForKey(
|
|
552
657
|
resource,
|
|
553
|
-
|
|
554
|
-
|
|
658
|
+
skjson.exportJSON(params),
|
|
659
|
+
skjson.exportJSON(key),
|
|
555
660
|
),
|
|
556
661
|
true,
|
|
557
662
|
);
|
|
558
663
|
});
|
|
559
664
|
if (typeof result == "number")
|
|
560
665
|
throw this.refs.handles.deleteHandle(result as Handle<Error>);
|
|
561
|
-
|
|
562
|
-
if (info.errors.length > 0)
|
|
563
|
-
throw new SkipError(JSON.stringify(info.errors));
|
|
564
|
-
return info.payload;
|
|
666
|
+
return result as V[];
|
|
565
667
|
} finally {
|
|
566
668
|
this.closeResourceInstance(uuid);
|
|
567
669
|
}
|
|
@@ -572,6 +674,7 @@ export class ServiceInstance {
|
|
|
572
674
|
* @param resourceInstanceId - The resource identifier
|
|
573
675
|
*/
|
|
574
676
|
closeResourceInstance(resourceInstanceId: string): void {
|
|
677
|
+
this.refs.setFork(this.forkName);
|
|
575
678
|
const errorHdl = this.refs.runWithGC(() => {
|
|
576
679
|
return this.refs.binding.SkipRuntime_Runtime__closeResource(
|
|
577
680
|
resourceInstanceId,
|
|
@@ -599,6 +702,7 @@ export class ServiceInstance {
|
|
|
599
702
|
},
|
|
600
703
|
watermark?: string,
|
|
601
704
|
): SubscriptionID {
|
|
705
|
+
this.refs.setFork(this.forkName);
|
|
602
706
|
const session = this.refs.runWithGC(() => {
|
|
603
707
|
const sknotifier = this.refs.binding.SkipRuntime_createNotifier(
|
|
604
708
|
this.refs.handles.register(notifier),
|
|
@@ -620,7 +724,7 @@ export class ServiceInstance {
|
|
|
620
724
|
} else if (session < 0n) {
|
|
621
725
|
throw this.refs.handles.deleteHandle(Number(-session) as Handle<Error>);
|
|
622
726
|
}
|
|
623
|
-
return
|
|
727
|
+
return resourceInstanceId as SubscriptionID;
|
|
624
728
|
}
|
|
625
729
|
|
|
626
730
|
/**
|
|
@@ -628,6 +732,7 @@ export class ServiceInstance {
|
|
|
628
732
|
* @param id - The subscription identifier returned by a call to `subscribe`
|
|
629
733
|
*/
|
|
630
734
|
unsubscribe(id: SubscriptionID): void {
|
|
735
|
+
this.refs.setFork(this.forkName);
|
|
631
736
|
const errorHdl = this.refs.runWithGC(() => {
|
|
632
737
|
return this.refs.binding.SkipRuntime_Runtime__unsubscribe(id);
|
|
633
738
|
});
|
|
@@ -641,24 +746,45 @@ export class ServiceInstance {
|
|
|
641
746
|
* @param collection - the name of the input collection to update
|
|
642
747
|
* @param entries - entries to update in the collection.
|
|
643
748
|
*/
|
|
644
|
-
update<K extends Json, V extends Json>(
|
|
749
|
+
async update<K extends Json, V extends Json>(
|
|
645
750
|
collection: string,
|
|
646
751
|
entries: Entry<K, V>[],
|
|
647
752
|
): Promise<void> {
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
753
|
+
this.refs.setFork(this.forkName);
|
|
754
|
+
const uuid = crypto.randomUUID();
|
|
755
|
+
const fork = this.fork(uuid);
|
|
756
|
+
try {
|
|
757
|
+
await fork.update_(collection, entries);
|
|
758
|
+
fork.merge([]);
|
|
759
|
+
} catch (ex: unknown) {
|
|
760
|
+
fork.abortFork();
|
|
761
|
+
throw ex;
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
private async update_<K extends Json, V extends Json>(
|
|
766
|
+
collection: string,
|
|
767
|
+
entries: Entry<K, V>[],
|
|
768
|
+
): Promise<void> {
|
|
769
|
+
this.refs.setFork(this.forkName);
|
|
770
|
+
const result = this.refs.runWithGC(() => {
|
|
771
|
+
const json = this.refs.json();
|
|
772
|
+
return json.importJSON(
|
|
773
|
+
this.refs.binding.SkipRuntime_Runtime__update(
|
|
655
774
|
collection,
|
|
656
|
-
this.refs.
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
if (errorHdl) reject(this.refs.handles.deleteHandle(errorHdl));
|
|
775
|
+
this.refs.json().exportJSON(entries),
|
|
776
|
+
),
|
|
777
|
+
true,
|
|
778
|
+
);
|
|
661
779
|
});
|
|
780
|
+
if (Array.isArray(result)) {
|
|
781
|
+
const handles = result as Handle<Promise<void>>[];
|
|
782
|
+
const promises = handles.map((h) => this.refs.handles.deleteHandle(h));
|
|
783
|
+
await Promise.all(promises);
|
|
784
|
+
} else {
|
|
785
|
+
const errorHdl = result as Handle<Error>;
|
|
786
|
+
throw this.refs.handles.deleteHandle(errorHdl);
|
|
787
|
+
}
|
|
662
788
|
}
|
|
663
789
|
|
|
664
790
|
/**
|
|
@@ -667,21 +793,99 @@ export class ServiceInstance {
|
|
|
667
793
|
* @returns The promise of externals services shutdowns
|
|
668
794
|
*/
|
|
669
795
|
close(): Promise<unknown> {
|
|
796
|
+
this.refs.setFork(this.forkName);
|
|
670
797
|
const result = this.refs.runWithGC(() => {
|
|
671
|
-
return this.refs.
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
);
|
|
798
|
+
return this.refs.binding.SkipRuntime_closeService();
|
|
799
|
+
});
|
|
800
|
+
if (result >= 0) {
|
|
801
|
+
return this.refs.handles.deleteHandle(result as Handle<Promise<unknown>>);
|
|
802
|
+
} else {
|
|
803
|
+
const errorHdl = -(result as number) as Handle<Error>;
|
|
804
|
+
return Promise.reject(this.refs.handles.deleteHandle(errorHdl));
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
async reload(service: SkipService, changes: ChangeManager): Promise<void> {
|
|
809
|
+
if (this.forkName) {
|
|
810
|
+
throw new SkipError("Reload cannot be called in transaction.");
|
|
811
|
+
}
|
|
812
|
+
const definition = this.definition.derive(service);
|
|
813
|
+
this.refs.setFork(this.forkName);
|
|
814
|
+
const uuid = crypto.randomUUID();
|
|
815
|
+
const fork = this.fork(uuid);
|
|
816
|
+
let merged = false;
|
|
817
|
+
try {
|
|
818
|
+
const streamsToClose = await fork._reload(definition, changes);
|
|
819
|
+
fork.merge(streamsToClose);
|
|
820
|
+
merged = true;
|
|
821
|
+
this.closeResourceStreams(streamsToClose);
|
|
822
|
+
this.definition = definition;
|
|
823
|
+
} catch (ex: unknown) {
|
|
824
|
+
console.error(ex);
|
|
825
|
+
if (!merged) fork.abortFork();
|
|
826
|
+
throw ex;
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
private async _reload(
|
|
831
|
+
definition: ServiceDefinition,
|
|
832
|
+
changes: ChangeManager,
|
|
833
|
+
): Promise<string[]> {
|
|
834
|
+
this.refs.setFork(this.forkName);
|
|
835
|
+
const result = this.refs.runWithGC(() => {
|
|
836
|
+
this.refs.changes = this.refs.handles.register(changes);
|
|
837
|
+
const skservicehHdl = this.refs.handles.register(definition);
|
|
838
|
+
const skservice =
|
|
839
|
+
this.refs.binding.SkipRuntime_createService(skservicehHdl);
|
|
840
|
+
const res = this.refs.binding.SkipRuntime_Runtime__reload(skservice);
|
|
841
|
+
this.refs.handles.deleteHandle(this.refs.changes);
|
|
842
|
+
this.refs.changes = null;
|
|
843
|
+
return this.refs.json().importJSON(res, true);
|
|
675
844
|
});
|
|
676
845
|
if (Array.isArray(result)) {
|
|
677
|
-
const handles = result as Handle<Promise<void>>[];
|
|
846
|
+
const [handles, res] = result as [Handle<Promise<void>>[], string[]];
|
|
678
847
|
const promises = handles.map((h) => this.refs.handles.deleteHandle(h));
|
|
679
|
-
|
|
848
|
+
await Promise.all(promises);
|
|
849
|
+
return res;
|
|
680
850
|
} else {
|
|
681
851
|
const errorHdl = result as Handle<Error>;
|
|
682
|
-
|
|
852
|
+
throw this.refs.handles.deleteHandle(errorHdl);
|
|
683
853
|
}
|
|
684
854
|
}
|
|
855
|
+
|
|
856
|
+
/**
|
|
857
|
+
* Fork the service with current specified name.
|
|
858
|
+
* @param name - the name of the fork.
|
|
859
|
+
* @returns The forked ServiceInstance
|
|
860
|
+
*/
|
|
861
|
+
private fork(name: string): ServiceInstance {
|
|
862
|
+
if (this.forkName) throw new Error(`Unable to fork ${this.forkName}.`);
|
|
863
|
+
this.refs.setFork(this.forkName);
|
|
864
|
+
this.refs.fork(name);
|
|
865
|
+
return new ServiceInstance(this.refs, name, this.definition);
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
private merge(ignore: string[]): void {
|
|
869
|
+
if (!this.forkName) throw new Error("Unable to merge fork on main.");
|
|
870
|
+
this.refs.setFork(this.forkName);
|
|
871
|
+
this.refs.merge(ignore);
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
private abortFork(): void {
|
|
875
|
+
if (!this.forkName) throw new Error("Unable to abord fork on main.");
|
|
876
|
+
this.refs.setFork(this.forkName);
|
|
877
|
+
this.refs.abortFork();
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
private closeResourceStreams(streams: string[]): void {
|
|
881
|
+
this.refs.setFork(this.forkName);
|
|
882
|
+
const errorHdl = this.refs.runWithGC(() => {
|
|
883
|
+
return this.refs.binding.SkipRuntime_Runtime__closeResourceStreams(
|
|
884
|
+
this.refs.json().exportJSON(streams),
|
|
885
|
+
);
|
|
886
|
+
});
|
|
887
|
+
if (errorHdl) throw this.refs.handles.deleteHandle(errorHdl);
|
|
888
|
+
}
|
|
685
889
|
}
|
|
686
890
|
|
|
687
891
|
class ValuesImpl<T> implements Values<T> {
|
|
@@ -758,17 +962,21 @@ class ValuesImpl<T> implements Values<T> {
|
|
|
758
962
|
|
|
759
963
|
export class ToBinding {
|
|
760
964
|
private readonly stack: Stack;
|
|
761
|
-
private readonly handles: Handles;
|
|
762
965
|
private skjson?: JsonConverter;
|
|
966
|
+
private forkName: Nullable<string>;
|
|
967
|
+
readonly handles: Handles;
|
|
968
|
+
changes: Nullable<Handle<ChangeManager>>;
|
|
763
969
|
|
|
764
970
|
constructor(
|
|
765
|
-
|
|
766
|
-
|
|
971
|
+
public binding: FromBinding,
|
|
972
|
+
public runWithGC: <T>(fn: () => T) => T,
|
|
767
973
|
private getConverter: () => JsonConverter,
|
|
768
974
|
private getError: (skExc: Pointer<Internal.Exception>) => Error,
|
|
769
975
|
) {
|
|
770
976
|
this.stack = new Stack();
|
|
771
977
|
this.handles = new Handles();
|
|
978
|
+
this.forkName = null;
|
|
979
|
+
this.changes = null;
|
|
772
980
|
}
|
|
773
981
|
|
|
774
982
|
register<T>(v: T): Handle<T> {
|
|
@@ -795,17 +1003,29 @@ export class ToBinding {
|
|
|
795
1003
|
return this.stack.get();
|
|
796
1004
|
}
|
|
797
1005
|
|
|
1006
|
+
SkipRuntime_getFork(): Nullable<string> {
|
|
1007
|
+
return this.forkName;
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
SkipRuntime_getChangeManager(): number {
|
|
1011
|
+
return this.changes ?? 0;
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
setFork(name: Nullable<string>): void {
|
|
1015
|
+
this.forkName = name;
|
|
1016
|
+
}
|
|
1017
|
+
|
|
798
1018
|
// Mapper
|
|
799
1019
|
|
|
800
1020
|
SkipRuntime_Mapper__mapEntry(
|
|
801
|
-
skmapper: Handle<JSONMapper
|
|
1021
|
+
skmapper: Handle<HandlerInfo<JSONMapper>>,
|
|
802
1022
|
key: Pointer<Internal.CJSON>,
|
|
803
1023
|
values: Pointer<Internal.NonEmptyIterator>,
|
|
804
1024
|
): Pointer<Internal.CJArray> {
|
|
805
1025
|
const skjson = this.getJsonConverter();
|
|
806
1026
|
const mapper = this.handles.get(skmapper);
|
|
807
|
-
const context = new ContextImpl(this
|
|
808
|
-
const result = mapper.mapEntry(
|
|
1027
|
+
const context = new ContextImpl(this);
|
|
1028
|
+
const result = mapper.object.mapEntry(
|
|
809
1029
|
skjson.importJSON(key) as Json,
|
|
810
1030
|
new ValuesImpl<Json>(skjson, this.binding, values),
|
|
811
1031
|
context,
|
|
@@ -813,27 +1033,65 @@ export class ToBinding {
|
|
|
813
1033
|
return skjson.exportJSON(Array.from(result));
|
|
814
1034
|
}
|
|
815
1035
|
|
|
816
|
-
|
|
1036
|
+
SkipRuntime_Mapper__getInfo(
|
|
1037
|
+
skmapper: Handle<HandlerInfo<JSONMapper>>,
|
|
1038
|
+
): Pointer<Internal.CJObject> {
|
|
1039
|
+
return this.getInfo(skmapper);
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
SkipRuntime_Mapper__isEquals(
|
|
1043
|
+
mapper: Handle<HandlerInfo<JSONMapper>>,
|
|
1044
|
+
other: Handle<HandlerInfo<JSONMapper>>,
|
|
1045
|
+
): number {
|
|
1046
|
+
const object = this.handles.get(mapper);
|
|
1047
|
+
if (this.getChanges()?.needMapperReload(object.name)) {
|
|
1048
|
+
return 0;
|
|
1049
|
+
}
|
|
1050
|
+
return this.isEquals(mapper, other);
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
SkipRuntime_deleteMapper(mapper: Handle<HandlerInfo<JSONMapper>>): void {
|
|
817
1054
|
this.handles.deleteHandle(mapper);
|
|
818
1055
|
}
|
|
819
1056
|
|
|
820
1057
|
// LazyCompute
|
|
821
1058
|
|
|
822
1059
|
SkipRuntime_LazyCompute__compute(
|
|
823
|
-
sklazyCompute: Handle<JSONLazyCompute
|
|
1060
|
+
sklazyCompute: Handle<HandlerInfo<JSONLazyCompute>>,
|
|
824
1061
|
self: string,
|
|
825
1062
|
skkey: Pointer<Internal.CJSON>,
|
|
826
1063
|
): Pointer<Internal.CJArray> {
|
|
827
1064
|
const skjson = this.getJsonConverter();
|
|
828
1065
|
const lazyCompute = this.handles.get(sklazyCompute);
|
|
829
|
-
const
|
|
830
|
-
|
|
1066
|
+
const context = new ContextImpl(this);
|
|
1067
|
+
const result = lazyCompute.object.compute(
|
|
1068
|
+
new LazyCollectionImpl<Json, Json>(self, this),
|
|
831
1069
|
skjson.importJSON(skkey) as Json,
|
|
1070
|
+
context,
|
|
832
1071
|
);
|
|
833
1072
|
return skjson.exportJSON(Array.from(result));
|
|
834
1073
|
}
|
|
835
1074
|
|
|
836
|
-
|
|
1075
|
+
SkipRuntime_LazyCompute__getInfo(
|
|
1076
|
+
lazyCompute: Handle<HandlerInfo<JSONLazyCompute>>,
|
|
1077
|
+
): Pointer<Internal.CJObject> {
|
|
1078
|
+
return this.getInfo(lazyCompute);
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
SkipRuntime_LazyCompute__isEquals(
|
|
1082
|
+
lazyCompute: Handle<HandlerInfo<JSONLazyCompute>>,
|
|
1083
|
+
other: Handle<HandlerInfo<JSONLazyCompute>>,
|
|
1084
|
+
): number {
|
|
1085
|
+
const object = this.handles.get(lazyCompute);
|
|
1086
|
+
if (this.getChanges()?.needLazyComputeReload(object.name)) {
|
|
1087
|
+
return 0;
|
|
1088
|
+
}
|
|
1089
|
+
return this.isEquals(lazyCompute, other);
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
SkipRuntime_deleteLazyCompute(
|
|
1093
|
+
lazyCompute: Handle<HandlerInfo<JSONLazyCompute>>,
|
|
1094
|
+
): void {
|
|
837
1095
|
this.handles.deleteHandle(lazyCompute);
|
|
838
1096
|
}
|
|
839
1097
|
|
|
@@ -849,11 +1107,10 @@ export class ToBinding {
|
|
|
849
1107
|
const keysIds = skjson.importJSON(skcollections) as {
|
|
850
1108
|
[key: string]: string;
|
|
851
1109
|
};
|
|
852
|
-
const refs = this.refs();
|
|
853
1110
|
for (const [key, name] of Object.entries(keysIds)) {
|
|
854
|
-
collections[key] = new EagerCollectionImpl<Json, Json>(name,
|
|
1111
|
+
collections[key] = new EagerCollectionImpl<Json, Json>(name, this);
|
|
855
1112
|
}
|
|
856
|
-
const collection = resource.instantiate(collections, new ContextImpl(
|
|
1113
|
+
const collection = resource.instantiate(collections, new ContextImpl(this));
|
|
857
1114
|
return EagerCollectionImpl.getName(collection);
|
|
858
1115
|
}
|
|
859
1116
|
|
|
@@ -861,28 +1118,10 @@ export class ToBinding {
|
|
|
861
1118
|
this.handles.deleteHandle(resource);
|
|
862
1119
|
}
|
|
863
1120
|
|
|
864
|
-
//
|
|
1121
|
+
// ServiceDefinition
|
|
865
1122
|
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
skparams: Pointer<Internal.CJObject>,
|
|
869
|
-
): Pointer<Internal.Resource> {
|
|
870
|
-
const skjson = this.getJsonConverter();
|
|
871
|
-
const builder = this.handles.get(skbuilder);
|
|
872
|
-
const resource = builder.build(skjson.importJSON(skparams) as Json);
|
|
873
|
-
return this.binding.SkipRuntime_createResource(
|
|
874
|
-
this.handles.register(resource),
|
|
875
|
-
);
|
|
876
|
-
}
|
|
877
|
-
|
|
878
|
-
SkipRuntime_deleteResourceBuilder(builder: Handle<ResourceBuilder>): void {
|
|
879
|
-
this.handles.deleteHandle(builder);
|
|
880
|
-
}
|
|
881
|
-
|
|
882
|
-
// Service
|
|
883
|
-
|
|
884
|
-
SkipRuntime_Service__createGraph(
|
|
885
|
-
skservice: Handle<SkipService>,
|
|
1123
|
+
SkipRuntime_ServiceDefinition__createGraph(
|
|
1124
|
+
skservice: Handle<ServiceDefinition>,
|
|
886
1125
|
skcollections: Pointer<Internal.CJObject>,
|
|
887
1126
|
): Pointer<Internal.CJObject> {
|
|
888
1127
|
const skjson = this.getJsonConverter();
|
|
@@ -891,11 +1130,10 @@ export class ToBinding {
|
|
|
891
1130
|
const keysIds = skjson.importJSON(skcollections) as {
|
|
892
1131
|
[key: string]: string;
|
|
893
1132
|
};
|
|
894
|
-
const refs = this.refs();
|
|
895
1133
|
for (const [key, name] of Object.entries(keysIds)) {
|
|
896
|
-
collections[key] = new EagerCollectionImpl<Json, Json>(name,
|
|
1134
|
+
collections[key] = new EagerCollectionImpl<Json, Json>(name, this);
|
|
897
1135
|
}
|
|
898
|
-
const result = service.createGraph(collections, new ContextImpl(
|
|
1136
|
+
const result = service.createGraph(collections, new ContextImpl(this));
|
|
899
1137
|
const collectionsNames: { [name: string]: string } = {};
|
|
900
1138
|
for (const [name, collection] of Object.entries(result)) {
|
|
901
1139
|
collectionsNames[name] = EagerCollectionImpl.getName(collection);
|
|
@@ -903,10 +1141,111 @@ export class ToBinding {
|
|
|
903
1141
|
return skjson.exportJSON(collectionsNames);
|
|
904
1142
|
}
|
|
905
1143
|
|
|
906
|
-
|
|
1144
|
+
SkipRuntime_ServiceDefinition__inputs(
|
|
1145
|
+
skservice: Handle<ServiceDefinition>,
|
|
1146
|
+
): Pointer<Internal.CJArray<Internal.CJSON>> {
|
|
1147
|
+
const skjson = this.getJsonConverter();
|
|
1148
|
+
const service = this.handles.get(skservice);
|
|
1149
|
+
return skjson.exportJSON(service.inputs());
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
SkipRuntime_ServiceDefinition__resources(
|
|
1153
|
+
skservice: Handle<ServiceDefinition>,
|
|
1154
|
+
): Pointer<Internal.CJArray<Internal.CJSON>> {
|
|
1155
|
+
const skjson = this.getJsonConverter();
|
|
1156
|
+
const service = this.handles.get(skservice);
|
|
1157
|
+
return skjson.exportJSON(service.resources());
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
SkipRuntime_ServiceDefinition__initialData(
|
|
1161
|
+
skservice: Handle<ServiceDefinition>,
|
|
1162
|
+
name: string,
|
|
1163
|
+
): Pointer<Internal.CJArray<Internal.CJSON>> {
|
|
1164
|
+
const skjson = this.getJsonConverter();
|
|
1165
|
+
const service = this.handles.get(skservice);
|
|
1166
|
+
return skjson.exportJSON(service.initialData(name));
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
SkipRuntime_ServiceDefinition__buildResource(
|
|
1170
|
+
skservice: Handle<ServiceDefinition>,
|
|
1171
|
+
name: string,
|
|
1172
|
+
skparams: Pointer<Internal.CJObject>,
|
|
1173
|
+
): Pointer<Internal.Resource> {
|
|
1174
|
+
const skjson = this.getJsonConverter();
|
|
1175
|
+
const service = this.handles.get(skservice);
|
|
1176
|
+
const resource = service.buildResource(
|
|
1177
|
+
name,
|
|
1178
|
+
skjson.importJSON(skparams) as Json,
|
|
1179
|
+
);
|
|
1180
|
+
return this.binding.SkipRuntime_createResource(
|
|
1181
|
+
this.handles.register(resource),
|
|
1182
|
+
);
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
SkipRuntime_ServiceDefinition__subscribe(
|
|
1186
|
+
skservice: Handle<ServiceDefinition>,
|
|
1187
|
+
external: string,
|
|
1188
|
+
writerId: string,
|
|
1189
|
+
instance: string,
|
|
1190
|
+
resource: string,
|
|
1191
|
+
skparams: Pointer<Internal.CJObject>,
|
|
1192
|
+
): Handle<Promise<void>> {
|
|
1193
|
+
const skjson = this.getJsonConverter();
|
|
1194
|
+
const service = this.handles.get(skservice);
|
|
1195
|
+
const writer = new CollectionWriter(writerId, this, this.forkName);
|
|
1196
|
+
const params = skjson.importJSON(skparams, true) as Json;
|
|
1197
|
+
return this.handles.register(
|
|
1198
|
+
service.subscribe(external, writer, instance, resource, params),
|
|
1199
|
+
);
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
SkipRuntime_ServiceDefinition__unsubscribe(
|
|
1203
|
+
skservice: Handle<ServiceDefinition>,
|
|
1204
|
+
external: string,
|
|
1205
|
+
instance: string,
|
|
1206
|
+
): void {
|
|
1207
|
+
const service = this.handles.get(skservice);
|
|
1208
|
+
service.unsubscribe(external, instance);
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
SkipRuntime_ServiceDefinition__shutdown(
|
|
1212
|
+
skservice: Handle<ServiceDefinition>,
|
|
1213
|
+
): Handle<Promise<unknown>> {
|
|
1214
|
+
const service = this.handles.get(skservice);
|
|
1215
|
+
return this.handles.register(service.shutdown());
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
SkipRuntime_deleteService(service: Handle<ServiceDefinition>): void {
|
|
907
1219
|
this.handles.deleteHandle(service);
|
|
908
1220
|
}
|
|
909
1221
|
|
|
1222
|
+
// Change manager
|
|
1223
|
+
|
|
1224
|
+
SkipRuntime_ChangeManager__needInputReload(
|
|
1225
|
+
skmanager: Handle<ChangeManager>,
|
|
1226
|
+
name: string,
|
|
1227
|
+
): number {
|
|
1228
|
+
const manager = this.handles.get(skmanager);
|
|
1229
|
+
return manager.needInputReload(name) ? 1 : 0;
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
SkipRuntime_ChangeManager__needResourceReload(
|
|
1233
|
+
skmanager: Handle<ChangeManager>,
|
|
1234
|
+
name: string,
|
|
1235
|
+
): number {
|
|
1236
|
+
const manager = this.handles.get(skmanager);
|
|
1237
|
+
return manager.needResourceReload(name);
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
SkipRuntime_ChangeManager__needExternalServiceReload(
|
|
1241
|
+
skmanager: Handle<ChangeManager>,
|
|
1242
|
+
name: string,
|
|
1243
|
+
resource: string,
|
|
1244
|
+
): number {
|
|
1245
|
+
const manager = this.handles.get(skmanager);
|
|
1246
|
+
return manager.needExternalServiceReload(name, resource) ? 1 : 0;
|
|
1247
|
+
}
|
|
1248
|
+
|
|
910
1249
|
// Notifier
|
|
911
1250
|
|
|
912
1251
|
SkipRuntime_Notifier__subscribed<K extends Json, V extends Json>(
|
|
@@ -948,15 +1287,23 @@ export class ToBinding {
|
|
|
948
1287
|
|
|
949
1288
|
// Reducer
|
|
950
1289
|
|
|
1290
|
+
SkipRuntime_Reducer__init(
|
|
1291
|
+
skreducer: Handle<HandlerInfo<Reducer<Json, Json>>>,
|
|
1292
|
+
): Pointer<Internal.CJSON> {
|
|
1293
|
+
const skjson = this.getJsonConverter();
|
|
1294
|
+
const reducer = this.handles.get(skreducer);
|
|
1295
|
+
return skjson.exportJSON(reducer.object.initial);
|
|
1296
|
+
}
|
|
1297
|
+
|
|
951
1298
|
SkipRuntime_Reducer__add(
|
|
952
|
-
skreducer: Handle<Reducer<Json, Json
|
|
1299
|
+
skreducer: Handle<HandlerInfo<Reducer<Json, Json>>>,
|
|
953
1300
|
skacc: Nullable<Pointer<Internal.CJSON>>,
|
|
954
1301
|
skvalue: Pointer<Internal.CJSON>,
|
|
955
1302
|
): Pointer<Internal.CJSON> {
|
|
956
1303
|
const skjson = this.getJsonConverter();
|
|
957
1304
|
const reducer = this.handles.get(skreducer);
|
|
958
1305
|
return skjson.exportJSON(
|
|
959
|
-
reducer.add(
|
|
1306
|
+
reducer.object.add(
|
|
960
1307
|
skacc ? (skjson.importJSON(skacc) as Json) : null,
|
|
961
1308
|
skjson.importJSON(skvalue) as Json & DepSafe,
|
|
962
1309
|
),
|
|
@@ -964,165 +1311,216 @@ export class ToBinding {
|
|
|
964
1311
|
}
|
|
965
1312
|
|
|
966
1313
|
SkipRuntime_Reducer__remove(
|
|
967
|
-
skreducer: Handle<Reducer<Json, Json
|
|
1314
|
+
skreducer: Handle<HandlerInfo<Reducer<Json, Json>>>,
|
|
968
1315
|
skacc: Pointer<Internal.CJSON>,
|
|
969
1316
|
skvalue: Pointer<Internal.CJSON>,
|
|
970
1317
|
): Nullable<Pointer<Internal.CJSON>> {
|
|
971
1318
|
const skjson = this.getJsonConverter();
|
|
972
1319
|
const reducer = this.handles.get(skreducer);
|
|
973
1320
|
return skjson.exportJSON(
|
|
974
|
-
reducer.remove(
|
|
1321
|
+
reducer.object.remove(
|
|
975
1322
|
skjson.importJSON(skacc) as Json,
|
|
976
1323
|
skjson.importJSON(skvalue) as Json & DepSafe,
|
|
977
1324
|
),
|
|
978
1325
|
);
|
|
979
1326
|
}
|
|
980
1327
|
|
|
981
|
-
|
|
982
|
-
|
|
1328
|
+
SkipRuntime_Reducer__isEquals(
|
|
1329
|
+
reducer: Handle<HandlerInfo<Reducer<Json, Json>>>,
|
|
1330
|
+
other: Handle<HandlerInfo<Reducer<Json, Json>>>,
|
|
1331
|
+
): number {
|
|
1332
|
+
const object = this.handles.get(reducer);
|
|
1333
|
+
if (this.getChanges()?.needReducerReload(object.name)) {
|
|
1334
|
+
return 0;
|
|
1335
|
+
}
|
|
1336
|
+
return this.isEquals(reducer, other);
|
|
983
1337
|
}
|
|
984
1338
|
|
|
985
|
-
|
|
1339
|
+
SkipRuntime_Reducer__getInfo(
|
|
1340
|
+
reducer: Handle<HandlerInfo<Reducer<Json, Json>>>,
|
|
1341
|
+
): Pointer<Internal.CJObject> {
|
|
1342
|
+
return this.getInfo(reducer);
|
|
1343
|
+
}
|
|
986
1344
|
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
writerId: string,
|
|
990
|
-
instance: string,
|
|
991
|
-
resource: string,
|
|
992
|
-
skparams: Pointer<Internal.CJObject>,
|
|
1345
|
+
SkipRuntime_deleteReducer(
|
|
1346
|
+
reducer: Handle<HandlerInfo<Reducer<Json, Json>>>,
|
|
993
1347
|
): void {
|
|
994
|
-
|
|
995
|
-
const supplier = this.handles.get(sksupplier);
|
|
996
|
-
const writer = new CollectionWriter(writerId, this.refs());
|
|
997
|
-
const params = skjson.importJSON(skparams, true) as Json;
|
|
998
|
-
// Ensure notification is made outside the current context update
|
|
999
|
-
setTimeout(() => {
|
|
1000
|
-
supplier
|
|
1001
|
-
.subscribe(instance, resource, params, {
|
|
1002
|
-
update: writer.update.bind(writer),
|
|
1003
|
-
error: writer.error.bind(writer),
|
|
1004
|
-
})
|
|
1005
|
-
.then(() => writer.initialized())
|
|
1006
|
-
.catch((e: unknown) =>
|
|
1007
|
-
writer.initialized(
|
|
1008
|
-
e instanceof Error
|
|
1009
|
-
? e.message
|
|
1010
|
-
: JSON.stringify(e, Object.getOwnPropertyNames(e)),
|
|
1011
|
-
),
|
|
1012
|
-
);
|
|
1013
|
-
}, 0);
|
|
1348
|
+
this.handles.deleteHandle(reducer);
|
|
1014
1349
|
}
|
|
1015
1350
|
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1351
|
+
async initService(service: SkipService): Promise<ServiceInstance> {
|
|
1352
|
+
this.setFork(null);
|
|
1353
|
+
const uuid = crypto.randomUUID();
|
|
1354
|
+
this.fork(uuid);
|
|
1355
|
+
try {
|
|
1356
|
+
this.setFork(uuid);
|
|
1357
|
+
const definition = new ServiceDefinition(service);
|
|
1358
|
+
await this.initService_(definition);
|
|
1359
|
+
this.setFork(uuid);
|
|
1360
|
+
this.merge();
|
|
1361
|
+
return new ServiceInstance(this, null, definition);
|
|
1362
|
+
} catch (ex: unknown) {
|
|
1363
|
+
this.setFork(uuid);
|
|
1364
|
+
this.abortFork();
|
|
1365
|
+
throw ex;
|
|
1366
|
+
}
|
|
1022
1367
|
}
|
|
1023
1368
|
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1369
|
+
private initService_(definition: ServiceDefinition): Promise<void> {
|
|
1370
|
+
return this.runAsync(() => {
|
|
1371
|
+
const skservicehHdl = this.handles.register(definition);
|
|
1372
|
+
const skservice = this.binding.SkipRuntime_createService(skservicehHdl);
|
|
1373
|
+
return this.binding.SkipRuntime_initService(skservice);
|
|
1374
|
+
});
|
|
1029
1375
|
}
|
|
1030
1376
|
|
|
1031
|
-
|
|
1032
|
-
|
|
1377
|
+
//
|
|
1378
|
+
public getJsonConverter() {
|
|
1379
|
+
if (this.skjson == undefined) {
|
|
1380
|
+
this.skjson = this.getConverter();
|
|
1381
|
+
}
|
|
1382
|
+
return this.skjson;
|
|
1033
1383
|
}
|
|
1034
1384
|
|
|
1035
|
-
|
|
1385
|
+
public needGC() {
|
|
1386
|
+
return this.SkipRuntime_getContext() == null;
|
|
1387
|
+
}
|
|
1036
1388
|
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
checker.resolve();
|
|
1389
|
+
public json() {
|
|
1390
|
+
return this.getJsonConverter();
|
|
1040
1391
|
}
|
|
1041
1392
|
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
checker.reject(this.handles.deleteHandle(error));
|
|
1393
|
+
fork(name: string): void {
|
|
1394
|
+
const errorHdl = this.runWithGC(() =>
|
|
1395
|
+
this.binding.SkipRuntime_Runtime__fork(name),
|
|
1396
|
+
);
|
|
1397
|
+
if (errorHdl) throw this.handles.deleteHandle(errorHdl);
|
|
1048
1398
|
}
|
|
1049
1399
|
|
|
1050
|
-
|
|
1051
|
-
this.
|
|
1400
|
+
merge(ignore: string[] = []): void {
|
|
1401
|
+
const errorHdl = this.runWithGC(() =>
|
|
1402
|
+
this.binding.SkipRuntime_Runtime__merge(this.json().exportJSON(ignore)),
|
|
1403
|
+
);
|
|
1404
|
+
if (errorHdl) throw this.handles.deleteHandle(errorHdl);
|
|
1052
1405
|
}
|
|
1053
1406
|
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
const skremote = refs.binding.SkipRuntime_createExternalService(
|
|
1065
|
-
refs.handles.register(remote),
|
|
1066
|
-
);
|
|
1067
|
-
refs.binding.SkipRuntime_ExternalServiceMap__add(
|
|
1068
|
-
skExternalServices,
|
|
1069
|
-
name,
|
|
1070
|
-
skremote,
|
|
1071
|
-
);
|
|
1072
|
-
}
|
|
1073
|
-
}
|
|
1074
|
-
const skresources =
|
|
1075
|
-
refs.binding.SkipRuntime_ResourceBuilderMap__create();
|
|
1076
|
-
for (const [name, builder] of Object.entries(service.resources)) {
|
|
1077
|
-
const skbuilder = refs.binding.SkipRuntime_createResourceBuilder(
|
|
1078
|
-
refs.handles.register(new ResourceBuilder(builder)),
|
|
1079
|
-
);
|
|
1080
|
-
refs.binding.SkipRuntime_ResourceBuilderMap__add(
|
|
1081
|
-
skresources,
|
|
1082
|
-
name,
|
|
1083
|
-
skbuilder,
|
|
1084
|
-
);
|
|
1085
|
-
}
|
|
1086
|
-
const skservice = refs.binding.SkipRuntime_createService(
|
|
1087
|
-
refs.handles.register(service),
|
|
1088
|
-
refs.skjson.exportJSON(service.initialData ?? {}),
|
|
1089
|
-
skresources,
|
|
1090
|
-
skExternalServices,
|
|
1091
|
-
);
|
|
1092
|
-
const exHdl = refs.handles.register({
|
|
1093
|
-
resolve: () => {
|
|
1094
|
-
resolve(new ServiceInstance(refs));
|
|
1095
|
-
},
|
|
1096
|
-
reject: (ex: Error) => reject(ex),
|
|
1097
|
-
});
|
|
1098
|
-
return refs.binding.SkipRuntime_initService(
|
|
1099
|
-
skservice,
|
|
1100
|
-
refs.binding.SkipRuntime_createExecutor(exHdl),
|
|
1101
|
-
);
|
|
1102
|
-
});
|
|
1103
|
-
if (errorHdl) reject(refs.handles.deleteHandle(errorHdl));
|
|
1407
|
+
abortFork(): void {
|
|
1408
|
+
const errorHdl = this.runWithGC(() =>
|
|
1409
|
+
this.binding.SkipRuntime_Runtime__abortFork(),
|
|
1410
|
+
);
|
|
1411
|
+
if (errorHdl) throw this.handles.deleteHandle(errorHdl);
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1414
|
+
async runAsync(fn: () => Pointer<Internal.CJSON>): Promise<void> {
|
|
1415
|
+
const result = this.runWithGC(() => {
|
|
1416
|
+
return this.json().importJSON(fn(), true);
|
|
1104
1417
|
});
|
|
1418
|
+
if (Array.isArray(result)) {
|
|
1419
|
+
const handles = result as Handle<Promise<void>>[];
|
|
1420
|
+
const promises = handles.map((h) => this.handles.deleteHandle(h));
|
|
1421
|
+
await Promise.all(promises);
|
|
1422
|
+
} else {
|
|
1423
|
+
const errorHdl = result as Handle<Error>;
|
|
1424
|
+
throw this.handles.deleteHandle(errorHdl);
|
|
1425
|
+
}
|
|
1105
1426
|
}
|
|
1106
1427
|
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
if (
|
|
1110
|
-
|
|
1428
|
+
private deepEquals(a: Nullable<Json>, b: Nullable<Json>) {
|
|
1429
|
+
// Same reference or both NaN
|
|
1430
|
+
if (a === b) return true;
|
|
1431
|
+
if (a !== a && b !== b) return true; // NaN check
|
|
1432
|
+
|
|
1433
|
+
// Different types or one is null
|
|
1434
|
+
if (typeof a !== typeof b || a === null || b === null) return false;
|
|
1435
|
+
|
|
1436
|
+
// Primitives already checked by ===
|
|
1437
|
+
if (typeof a !== "object" || typeof b !== "object") return false;
|
|
1438
|
+
|
|
1439
|
+
// Arrays
|
|
1440
|
+
if (Array.isArray(a)) {
|
|
1441
|
+
if (!Array.isArray(b) || a.length !== b.length) return false;
|
|
1442
|
+
for (let i = 0; i < a.length; i++) {
|
|
1443
|
+
if (!this.deepEquals(a[i]!, b[i]!)) return false;
|
|
1444
|
+
}
|
|
1445
|
+
return true;
|
|
1111
1446
|
}
|
|
1112
|
-
|
|
1447
|
+
|
|
1448
|
+
// Different array status
|
|
1449
|
+
if (Array.isArray(b)) return false;
|
|
1450
|
+
|
|
1451
|
+
// Objects
|
|
1452
|
+
const keysA = Object.keys(a);
|
|
1453
|
+
const keysB = Object.keys(b);
|
|
1454
|
+
|
|
1455
|
+
if (keysA.length !== keysB.length) return false;
|
|
1456
|
+
|
|
1457
|
+
for (const key of keysA) {
|
|
1458
|
+
if (
|
|
1459
|
+
!Object.prototype.hasOwnProperty.call(b, key) ||
|
|
1460
|
+
!this.deepEquals(a[key]!, b[key]!)
|
|
1461
|
+
)
|
|
1462
|
+
return false;
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
return true;
|
|
1113
1466
|
}
|
|
1114
1467
|
|
|
1115
|
-
private
|
|
1116
|
-
|
|
1468
|
+
private getInfo<T>(
|
|
1469
|
+
skmapper: Handle<HandlerInfo<T>>,
|
|
1470
|
+
): Pointer<Internal.CJObject> {
|
|
1471
|
+
const skjson = this.getJsonConverter();
|
|
1472
|
+
const object = this.handles.get(skmapper);
|
|
1473
|
+
const name = object.name;
|
|
1474
|
+
const parameters = object.params.map((v) => {
|
|
1475
|
+
if (v instanceof EagerCollectionImpl) {
|
|
1476
|
+
return {
|
|
1477
|
+
type: "collection",
|
|
1478
|
+
value: v.collection,
|
|
1479
|
+
};
|
|
1480
|
+
}
|
|
1481
|
+
if (v instanceof LazyCollectionImpl) {
|
|
1482
|
+
return {
|
|
1483
|
+
type: "collection",
|
|
1484
|
+
value: v.lazyCollection,
|
|
1485
|
+
};
|
|
1486
|
+
}
|
|
1487
|
+
return { type: "data", value: v as Json };
|
|
1488
|
+
});
|
|
1489
|
+
return skjson.exportJSON({ name, parameters });
|
|
1117
1490
|
}
|
|
1118
1491
|
|
|
1119
|
-
private
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1492
|
+
private isEquals<T extends JSONOperator>(
|
|
1493
|
+
mapper: Handle<HandlerInfo<T>>,
|
|
1494
|
+
other: Handle<HandlerInfo<T>>,
|
|
1495
|
+
): number {
|
|
1496
|
+
const object = this.handles.get(mapper);
|
|
1497
|
+
const oobject = this.handles.get(other);
|
|
1498
|
+
if (object.object.constructor != oobject.object.constructor) {
|
|
1499
|
+
return 0;
|
|
1500
|
+
}
|
|
1501
|
+
if (object.params.length != oobject.params.length) return 0;
|
|
1502
|
+
for (const [i, param] of object.params.entries()) {
|
|
1503
|
+
const oparam = oobject.params[i];
|
|
1504
|
+
if (param instanceof EagerCollectionImpl) {
|
|
1505
|
+
if (oparam instanceof EagerCollectionImpl) {
|
|
1506
|
+
if (param.collection != oparam.collection) return 0;
|
|
1507
|
+
} else {
|
|
1508
|
+
return 0;
|
|
1509
|
+
}
|
|
1510
|
+
} else if (param instanceof LazyCollectionImpl) {
|
|
1511
|
+
if (oparam instanceof LazyCollectionImpl) {
|
|
1512
|
+
if (param.lazyCollection != oparam.lazyCollection) return 0;
|
|
1513
|
+
} else {
|
|
1514
|
+
return 0;
|
|
1515
|
+
}
|
|
1516
|
+
} else if (!this.deepEquals(param as Json, oparam as Json)) {
|
|
1517
|
+
return 0;
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
return 1;
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
private getChanges(): Nullable<ChangeManager> {
|
|
1524
|
+
return this.changes ? this.handles.get(this.changes) : null;
|
|
1127
1525
|
}
|
|
1128
1526
|
}
|