@aventara/core 1.0.0-rc.1 → 1.0.0-rc.10
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/CHANGELOG.md +943 -16
- package/ERRORS.md +142 -0
- package/README.md +274 -16
- package/dist/adapters/adapter-discovery-diagnostic.guidance.d.ts +6 -0
- package/dist/adapters/adapter-discovery-diagnostic.guidance.js +7 -0
- package/dist/adapters/adapter-field.d.ts +22 -0
- package/dist/adapters/adapter-identifier.d.ts +9 -0
- package/dist/adapters/adapter-identifier.js +6 -1
- package/dist/adapters/adapter-model.d.ts +9 -0
- package/dist/adapters/adapter-operation.d.ts +18 -3
- package/dist/adapters/adapter-resource.d.ts +5 -0
- package/dist/adapters/adapter.interface.d.ts +10 -0
- package/dist/avz/avz.d.ts +1 -1
- package/dist/avz/json-shape.registry.d.ts +2 -1
- package/dist/compiler/contract-compiler-diagnostic.guidance.d.ts +6 -0
- package/dist/compiler/contract-compiler-diagnostic.guidance.js +97 -0
- package/dist/compiler/contract.compiler.d.ts +6 -0
- package/dist/compiler/contract.compiler.js +227 -24
- package/dist/compiler/managed-elsewhere.projector.d.ts +52 -0
- package/dist/compiler/managed-elsewhere.projector.js +179 -0
- package/dist/compiler/managed-elsewhere.validator.d.ts +9 -0
- package/dist/compiler/managed-elsewhere.validator.js +74 -0
- package/dist/config/computed-fields.d.ts +62 -0
- package/dist/config/computed-fields.js +73 -0
- package/dist/config/config-diagnostic.guidance.d.ts +6 -0
- package/dist/config/config-diagnostic.guidance.js +32 -0
- package/dist/config/config.resolver.d.ts +24 -0
- package/dist/config/config.resolver.js +65 -0
- package/dist/config/config.validator.js +222 -8
- package/dist/config/define-resource.d.ts +1 -5
- package/dist/config/entrypoint.normalizer.d.ts +3 -2
- package/dist/config/exact-framework-config.d.ts +67 -22
- package/dist/config/field-compute.resolver.d.ts +2 -0
- package/dist/config/field-compute.resolver.js +8 -0
- package/dist/config/framework-config.d.ts +53 -15
- package/dist/config/framework-resources-config.d.ts +25 -14
- package/dist/config/pipeline-config.d.ts +4 -4
- package/dist/config/pipeline-tree.resolver.d.ts +2 -2
- package/dist/contracts/access-route.rules.d.ts +10 -0
- package/dist/contracts/access-route.rules.js +45 -0
- package/dist/contracts/capability.d.ts +26 -1
- package/dist/contracts/capability.js +20 -0
- package/dist/contracts/client-contract-structure.validator.d.ts +301 -89
- package/dist/contracts/client-contract-structure.validator.js +37 -2
- package/dist/contracts/contract-access.d.ts +29 -0
- package/dist/contracts/contract-access.js +1 -0
- package/dist/contracts/contract-canonicalizer.d.ts +9 -1
- package/dist/contracts/contract-canonicalizer.js +30 -4
- package/dist/contracts/contract-hash.d.ts +0 -1
- package/dist/contracts/contract-hash.js +1 -1
- package/dist/contracts/contract.d.ts +27 -1
- package/dist/contracts/field.d.ts +58 -1
- package/dist/contracts/json-schema.projector.d.ts +11 -0
- package/dist/contracts/json-schema.projector.js +78 -0
- package/dist/contracts/scalar-value-type.d.ts +3 -1
- package/dist/framework/access-facade.d.ts +116 -0
- package/dist/framework/access-facade.js +120 -0
- package/dist/framework/contract-view.d.ts +120 -16
- package/dist/framework/framework-construction.error.d.ts +14 -4
- package/dist/framework/framework-construction.error.js +18 -2
- package/dist/framework/framework.d.ts +26 -5
- package/dist/framework/framework.factory.d.ts +1 -1
- package/dist/framework/framework.factory.js +115 -23
- package/dist/framework/operation-facade.d.ts +80 -13
- package/dist/framework/operation-facade.js +2 -1
- package/dist/index.d.ts +17 -5
- package/dist/index.js +1 -0
- package/dist/internal.d.ts +7 -2
- package/dist/internal.js +6 -0
- package/dist/operations/database-refusal.d.ts +51 -0
- package/dist/operations/database-refusal.js +45 -0
- package/dist/operations/operation-arguments.d.ts +148 -60
- package/dist/operations/operation-call.d.ts +9 -5
- package/dist/operations/operation-result.d.ts +6 -4
- package/dist/operations/operation-validator-core.js +159 -36
- package/dist/operations/operation-validator.d.ts +1 -1
- package/dist/operations/structural-limits.walker.d.ts +1 -1
- package/dist/operations/validation-code.guidance.d.ts +6 -0
- package/dist/operations/validation-code.guidance.js +90 -0
- package/dist/operations/write-scope.resolver.d.ts +4 -0
- package/dist/operations/write-scope.resolver.js +2 -0
- package/dist/policy/access-provider.interface.d.ts +91 -0
- package/dist/policy/access-provider.interface.js +1 -0
- package/dist/policy/access-provider.registry.d.ts +17 -0
- package/dist/policy/access-provider.registry.js +15 -0
- package/dist/policy/access-question.d.ts +20 -0
- package/dist/policy/access-question.js +1 -0
- package/dist/policy/access-question.registry.d.ts +5 -0
- package/dist/policy/access-question.registry.js +19 -0
- package/dist/policy/access-question.runtime.d.ts +36 -0
- package/dist/policy/access-question.runtime.js +297 -0
- package/dist/policy/access-verb.table.d.ts +56 -0
- package/dist/policy/access-verb.table.js +21 -0
- package/dist/policy/access-verbs.d.ts +46 -0
- package/dist/policy/access-verbs.js +1 -0
- package/dist/policy/policy-admission.d.ts +20 -0
- package/dist/policy/policy-admission.js +409 -0
- package/dist/policy/policy-after-update.runtime.d.ts +79 -0
- package/dist/policy/policy-after-update.runtime.js +208 -0
- package/dist/policy/policy-condition.d.ts +15 -0
- package/dist/policy/policy-condition.js +36 -0
- package/dist/policy/policy-engine.d.ts +205 -0
- package/dist/policy/policy-engine.js +1 -0
- package/dist/policy/policy-named-rows.d.ts +18 -0
- package/dist/policy/policy-named-rows.js +51 -0
- package/dist/policy/policy-nested-write.runtime.d.ts +44 -0
- package/dist/policy/policy-nested-write.runtime.js +545 -0
- package/dist/policy/policy-read.runtime.d.ts +81 -0
- package/dist/policy/policy-read.runtime.js +503 -0
- package/dist/policy/policy-reference-write.runtime.d.ts +51 -0
- package/dist/policy/policy-reference-write.runtime.js +345 -0
- package/dist/policy/policy-request.d.ts +41 -0
- package/dist/policy/policy-request.js +63 -0
- package/dist/policy/policy-session.d.ts +106 -0
- package/dist/policy/policy-session.js +295 -0
- package/dist/policy/policy-startup.validator.d.ts +10 -0
- package/dist/policy/policy-startup.validator.js +112 -0
- package/dist/policy/policy-write.runtime.d.ts +39 -0
- package/dist/policy/policy-write.runtime.js +532 -0
- package/dist/prebuilt/core-version.generated.d.ts +2 -0
- package/dist/prebuilt/core-version.generated.js +1 -0
- package/dist/prebuilt/prebuilt-changes.d.ts +29 -0
- package/dist/prebuilt/prebuilt-changes.js +65 -0
- package/dist/prebuilt/prebuilt-contracts.d.ts +40 -0
- package/dist/prebuilt/prebuilt-contracts.emitter.d.ts +16 -0
- package/dist/prebuilt/prebuilt-contracts.emitter.js +50 -0
- package/dist/prebuilt/prebuilt-contracts.js +1 -0
- package/dist/prebuilt/prebuilt-contracts.loader.d.ts +19 -0
- package/dist/prebuilt/prebuilt-contracts.loader.js +77 -0
- package/dist/prebuilt/prebuilt-inputs.fingerprint.d.ts +16 -0
- package/dist/prebuilt/prebuilt-inputs.fingerprint.js +229 -0
- package/dist/protocol/absent-route.responder.d.ts +9 -27
- package/dist/protocol/absent-route.responder.js +36 -3
- package/dist/protocol/contract-document.responder.d.ts +2 -1
- package/dist/protocol/http-request.decoder.d.ts +19 -3
- package/dist/protocol/http-request.decoder.js +24 -1
- package/dist/protocol/http-request.reader.d.ts +6 -3
- package/dist/protocol/http-request.reader.js +1 -0
- package/dist/protocol/http-response.encoder.js +2 -2
- package/dist/protocol/protocol-headers.d.ts +3 -3
- package/dist/protocol/protocol-surface.d.ts +6 -1
- package/dist/protocol/protocol-surface.js +7 -0
- package/dist/protocol/protocol.binder.d.ts +16 -1
- package/dist/protocol/protocol.binder.js +4 -1
- package/dist/protocol/protocol.handler.d.ts +12 -1
- package/dist/protocol/protocol.handler.js +86 -17
- package/dist/runtime/caller-data.copier.d.ts +18 -3
- package/dist/runtime/caller-data.copier.js +21 -8
- package/dist/runtime/caller-data.door.d.ts +13 -6
- package/dist/runtime/computed-read-runtime.d.ts +6 -1
- package/dist/runtime/computed-read-runtime.js +232 -45
- package/dist/runtime/computed-value.error.d.ts +3 -2
- package/dist/runtime/computed-value.error.js +3 -2
- package/dist/runtime/context-executor.runtime.d.ts +4 -3
- package/dist/runtime/context-executor.runtime.js +4 -2
- package/dist/runtime/core-class.brand.d.ts +10 -0
- package/dist/runtime/core-class.brand.js +21 -0
- package/dist/runtime/create-requirement.d.ts +31 -5
- package/dist/runtime/create-requirement.js +129 -21
- package/dist/runtime/decimal.d.ts +14 -0
- package/dist/runtime/decimal.js +21 -0
- package/dist/runtime/diagnostics-reporter.d.ts +44 -9
- package/dist/runtime/diagnostics-reporter.js +13 -1
- package/dist/runtime/error-boundary.d.ts +9 -2
- package/dist/runtime/error-boundary.js +12 -0
- package/dist/runtime/error-guidance.d.ts +12 -0
- package/dist/runtime/error-guidance.js +1 -0
- package/dist/runtime/error.catalog.d.ts +49 -0
- package/dist/runtime/error.catalog.js +49 -0
- package/dist/runtime/execution-options.d.ts +8 -0
- package/dist/runtime/field-check.evaluator.d.ts +0 -2
- package/dist/runtime/field-check.evaluator.js +1 -1
- package/dist/runtime/field-compute.d.ts +11 -10
- package/dist/runtime/field-stage.runtime.d.ts +3 -1
- package/dist/runtime/field-stage.runtime.js +8 -4
- package/dist/runtime/field-validator.runtime.d.ts +19 -1
- package/dist/runtime/field-validator.runtime.js +47 -8
- package/dist/runtime/framework-error.js +9 -0
- package/dist/runtime/framework-warning.emitter.d.ts +6 -0
- package/dist/runtime/framework-warning.emitter.js +8 -0
- package/dist/runtime/json-value.d.ts +10 -5
- package/dist/runtime/level-lifecycle.runtime.d.ts +4 -3
- package/dist/runtime/level-lifecycle.runtime.js +3 -5
- package/dist/runtime/mutation-planner.d.ts +1 -6
- package/dist/runtime/mutation-planner.js +3 -14
- package/dist/runtime/operation-code.guidance.d.ts +6 -0
- package/dist/runtime/operation-code.guidance.js +167 -0
- package/dist/runtime/operation-request.d.ts +16 -9
- package/dist/runtime/operation-runtime.d.ts +35 -17
- package/dist/runtime/operation-runtime.js +220 -49
- package/dist/runtime/outcome-mapper.d.ts +2 -1
- package/dist/runtime/output-validator.d.ts +1 -1
- package/dist/runtime/owned-execution.registry.d.ts +13 -3
- package/dist/runtime/pipe-output.validator.d.ts +10 -0
- package/dist/runtime/pipe-output.validator.js +4 -2
- package/dist/runtime/pipeline.d.ts +47 -22
- package/dist/runtime/readonly-value.d.ts +20 -5
- package/dist/runtime/readonly-value.js +74 -26
- package/dist/runtime/referential-action.d.ts +1 -1
- package/dist/runtime/scalar-runtime.d.ts +4 -11
- package/dist/runtime/scalar-runtime.js +91 -22
- package/dist/runtime/unsent-value.normalizer.d.ts +15 -0
- package/dist/runtime/unsent-value.normalizer.js +128 -0
- package/dist/transactions/operation-arguments-encoder.js +8 -3
- package/dist/transactions/operation-fingerprint.js +2 -2
- package/dist/transactions/sql-statement.d.ts +10 -2
- package/dist/transactions/sql-statement.validator.d.ts +2 -2
- package/dist/transactions/sql-statement.validator.js +38 -5
- package/dist/transactions/transaction-envelope.d.ts +5 -4
- package/dist/transactions/transaction-integrity-error.js +2 -0
- package/dist/transactions/transaction-plan-assembler.d.ts +12 -5
- package/dist/transactions/transaction-plan-assembler.js +48 -10
- package/dist/transactions/transaction-plan-validator.d.ts +23 -7
- package/dist/transactions/transaction-plan-validator.js +27 -1
- package/dist/transactions/transaction-reference-resolver.d.ts +3 -2
- package/dist/transactions/transaction-reference-validator.d.ts +43 -3
- package/dist/transactions/transaction-reference-validator.js +83 -57
- package/dist/transactions/transaction-reference.d.ts +1 -1
- package/dist/transactions/transaction-reference.js +5 -0
- package/dist/transactions/transaction-request.d.ts +8 -8
- package/dist/transactions/transaction-runtime.d.ts +5 -2
- package/dist/transactions/transaction-runtime.js +79 -27
- package/dist/transactions/transaction-settlement.runtime.d.ts +4 -3
- package/dist/transactions/transaction-slot-path-error.js +2 -0
- package/dist/transactions/transaction-stage.runtime.d.ts +5 -3
- package/dist/transactions/transaction-stage.runtime.js +7 -4
- package/package.json +6 -5
- package/src/runtime/field-check.evaluator.ts +1 -1
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { adapterPrimaryIdentifier } from "../adapters/adapter-identifier.js";
|
|
1
2
|
import { lookupField, lookupResource } from "../contracts/contract-lookup.js";
|
|
2
3
|
import { AvComputedValueError } from "./computed-value.error.js";
|
|
4
|
+
import { frozenCopy } from "./readonly-value.js";
|
|
3
5
|
import { normalizeScalarFieldValue } from "./scalar-runtime.js";
|
|
4
6
|
function isRecord(value) {
|
|
5
7
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
@@ -51,6 +53,11 @@ function addScalarProjection(core, model, active, compute, resourceName, fieldNa
|
|
|
51
53
|
const stage = readCompute(compute?.[resourceName]?.[fieldName]?.read);
|
|
52
54
|
if (stage !== undefined) {
|
|
53
55
|
appendUnique(computed, fieldName);
|
|
56
|
+
if (stage.dependsOn.length === 0) {
|
|
57
|
+
for (const member of adapterPrimaryIdentifier(model, resourceName)) {
|
|
58
|
+
appendUniqueProjection(adapterSelect, member);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
54
61
|
for (const dependency of stage.dependsOn) {
|
|
55
62
|
if (storedScalar(model, resourceName, dependency)) {
|
|
56
63
|
appendUniqueProjection(adapterSelect, dependency);
|
|
@@ -77,18 +84,27 @@ function projectionEntry(entry) {
|
|
|
77
84
|
function withoutProjectionChoice(value) {
|
|
78
85
|
return Object.fromEntries(Object.entries(value).filter(([key]) => key !== "select" && key !== "include"));
|
|
79
86
|
}
|
|
80
|
-
function
|
|
87
|
+
export function defaultProjectionFields(active, resourceName) {
|
|
81
88
|
const activeResource = lookupResource(active, resourceName);
|
|
89
|
+
if (activeResource === undefined) {
|
|
90
|
+
return [];
|
|
91
|
+
}
|
|
92
|
+
const fields = [];
|
|
93
|
+
for (const [fieldName, field] of Object.entries(activeResource.fields)) {
|
|
94
|
+
if (field.kind === "scalar" &&
|
|
95
|
+
field.capabilities.select === true &&
|
|
96
|
+
field.governed !== true) {
|
|
97
|
+
fields.push(fieldName);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return fields;
|
|
101
|
+
}
|
|
102
|
+
function defaultProjectionLevel(core, model, active, compute, resourceName) {
|
|
82
103
|
const adapterSelect = [];
|
|
83
104
|
const requested = [];
|
|
84
105
|
const computed = [];
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
if (field.kind !== "scalar" || field.capabilities.select !== true) {
|
|
88
|
-
continue;
|
|
89
|
-
}
|
|
90
|
-
addScalarProjection(core, model, active, compute, resourceName, fieldName, adapterSelect, requested, computed);
|
|
91
|
-
}
|
|
106
|
+
for (const fieldName of defaultProjectionFields(active, resourceName)) {
|
|
107
|
+
addScalarProjection(core, model, active, compute, resourceName, fieldName, adapterSelect, requested, computed);
|
|
92
108
|
}
|
|
93
109
|
return {
|
|
94
110
|
select: adapterSelect,
|
|
@@ -156,6 +172,12 @@ function planSelectLevel(core, model, active, compute, resourceName, select, col
|
|
|
156
172
|
}
|
|
157
173
|
for (const entry of select) {
|
|
158
174
|
if (typeof entry === "string") {
|
|
175
|
+
if (entry === "$defaults") {
|
|
176
|
+
for (const fieldName of defaultProjectionFields(active, resourceName)) {
|
|
177
|
+
addScalarProjection(core, model, active, compute, resourceName, fieldName, adapterSelect, requested, computed);
|
|
178
|
+
}
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
159
181
|
if (entry === "$count") {
|
|
160
182
|
adapterSelect.push(entry);
|
|
161
183
|
if (collectReducers) {
|
|
@@ -280,7 +302,175 @@ export function planReadOperation(core, model, active, compute, request, args) {
|
|
|
280
302
|
materialize: defaults.plan.computed.length > 0,
|
|
281
303
|
};
|
|
282
304
|
}
|
|
283
|
-
|
|
305
|
+
function resolveReadLevel(active, compute, plan, tail) {
|
|
306
|
+
const resource = lookupResource(active, plan.resource);
|
|
307
|
+
if (resource === undefined) {
|
|
308
|
+
return undefined;
|
|
309
|
+
}
|
|
310
|
+
const stages = [];
|
|
311
|
+
for (const fieldName of plan.computed) {
|
|
312
|
+
const field = lookupField(resource, fieldName);
|
|
313
|
+
const stage = readCompute(compute?.[plan.resource]?.[fieldName]?.read);
|
|
314
|
+
if (field?.kind !== "scalar" || stage === undefined) {
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
stages.push({
|
|
318
|
+
field: fieldName,
|
|
319
|
+
definition: field,
|
|
320
|
+
compute: stage.compute,
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
const relations = [];
|
|
324
|
+
let restFree = true;
|
|
325
|
+
for (const relation of [...plan.relations].reverse()) {
|
|
326
|
+
const level = resolveReadLevel(active, compute, relation.projection, tail && restFree);
|
|
327
|
+
relations.unshift({ relation, level });
|
|
328
|
+
restFree &&= level?.computeFree ?? true;
|
|
329
|
+
}
|
|
330
|
+
return {
|
|
331
|
+
plan,
|
|
332
|
+
stages,
|
|
333
|
+
relations,
|
|
334
|
+
computeFree: stages.length === 0 && restFree,
|
|
335
|
+
atOnce: tail && stages.length <= 1 && restFree,
|
|
336
|
+
plainKeys: plan.requested.every((field) => !(field in Object.prototype)),
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
function isNestedContainer(value) {
|
|
340
|
+
return (value !== null &&
|
|
341
|
+
typeof value === "object" &&
|
|
342
|
+
!(value instanceof Date) &&
|
|
343
|
+
!(value instanceof Uint8Array));
|
|
344
|
+
}
|
|
345
|
+
function isThenable(value) {
|
|
346
|
+
return (value !== null &&
|
|
347
|
+
(typeof value === "object" || typeof value === "function") &&
|
|
348
|
+
typeof value.then === "function");
|
|
349
|
+
}
|
|
350
|
+
function setOwn(target, key, value) {
|
|
351
|
+
if (key in target) {
|
|
352
|
+
Object.defineProperty(target, key, {
|
|
353
|
+
value,
|
|
354
|
+
writable: true,
|
|
355
|
+
enumerable: true,
|
|
356
|
+
configurable: true,
|
|
357
|
+
});
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
target[key] = value;
|
|
361
|
+
}
|
|
362
|
+
function answerOf(level, record) {
|
|
363
|
+
const answer = {};
|
|
364
|
+
for (const fieldName of level.plan.requested) {
|
|
365
|
+
if (!Object.hasOwn(record, fieldName)) {
|
|
366
|
+
continue;
|
|
367
|
+
}
|
|
368
|
+
if (level.plainKeys) {
|
|
369
|
+
answer[fieldName] = record[fieldName];
|
|
370
|
+
}
|
|
371
|
+
else {
|
|
372
|
+
setOwn(answer, fieldName, record[fieldName]);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
return answer;
|
|
376
|
+
}
|
|
377
|
+
function heldReadValue(active, level, stage, value) {
|
|
378
|
+
const validation = normalizeScalarFieldValue(active, stage.definition, value, "runtime", [
|
|
379
|
+
"resources",
|
|
380
|
+
level.plan.resource,
|
|
381
|
+
"fields",
|
|
382
|
+
stage.field,
|
|
383
|
+
"pipelines",
|
|
384
|
+
"compute",
|
|
385
|
+
"read",
|
|
386
|
+
]);
|
|
387
|
+
if (!validation.ok) {
|
|
388
|
+
throw new AvComputedValueError(level.plan.resource, stage.field, "read", validation.issues);
|
|
389
|
+
}
|
|
390
|
+
return validation.value;
|
|
391
|
+
}
|
|
392
|
+
function projectedAtOnce(level, value) {
|
|
393
|
+
if (!isRecord(value) || level === undefined) {
|
|
394
|
+
return value;
|
|
395
|
+
}
|
|
396
|
+
const record = { ...value };
|
|
397
|
+
relationsAtOnce(level, record);
|
|
398
|
+
return answerOf(level, record);
|
|
399
|
+
}
|
|
400
|
+
function relationsAtOnce(level, record) {
|
|
401
|
+
for (const { relation, level: nested } of level.relations) {
|
|
402
|
+
if (!Object.hasOwn(record, relation.field)) {
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
405
|
+
const value = record[relation.field];
|
|
406
|
+
if (value === null || value === undefined) {
|
|
407
|
+
continue;
|
|
408
|
+
}
|
|
409
|
+
if (relation.cardinality === "many") {
|
|
410
|
+
if (Array.isArray(value)) {
|
|
411
|
+
record[relation.field] = Array.from(value, (entry) => projectedAtOnce(nested, entry));
|
|
412
|
+
}
|
|
413
|
+
continue;
|
|
414
|
+
}
|
|
415
|
+
record[relation.field] = projectedAtOnce(nested, value);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
function computedAtOnce(active, level, stage, value, contextFactory) {
|
|
419
|
+
const record = { ...value };
|
|
420
|
+
const view = frozenCopy(record);
|
|
421
|
+
let computedValue;
|
|
422
|
+
try {
|
|
423
|
+
computedValue = stage.compute({
|
|
424
|
+
field: stage.field,
|
|
425
|
+
value: view[stage.field],
|
|
426
|
+
record: view,
|
|
427
|
+
ctx: contextFactory(),
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
catch (error) {
|
|
431
|
+
return Promise.reject(error);
|
|
432
|
+
}
|
|
433
|
+
const finish = (returned) => {
|
|
434
|
+
if (returned !== undefined) {
|
|
435
|
+
record[stage.field] = heldReadValue(active, level, stage, returned);
|
|
436
|
+
}
|
|
437
|
+
relationsAtOnce(level, record);
|
|
438
|
+
return answerOf(level, record);
|
|
439
|
+
};
|
|
440
|
+
const later = (error) => Promise.resolve().then(() => {
|
|
441
|
+
throw error;
|
|
442
|
+
});
|
|
443
|
+
let waits;
|
|
444
|
+
try {
|
|
445
|
+
waits = isThenable(computedValue);
|
|
446
|
+
}
|
|
447
|
+
catch (error) {
|
|
448
|
+
return later(error);
|
|
449
|
+
}
|
|
450
|
+
if (waits) {
|
|
451
|
+
const pending = computedValue;
|
|
452
|
+
return (async () => finish(await pending))();
|
|
453
|
+
}
|
|
454
|
+
try {
|
|
455
|
+
return finish(computedValue);
|
|
456
|
+
}
|
|
457
|
+
catch (error) {
|
|
458
|
+
return later(error);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
function materializeRecord(active, level, value, contextFactory) {
|
|
462
|
+
if (level?.atOnce !== true) {
|
|
463
|
+
return materializeInTurn(active, level, value, contextFactory);
|
|
464
|
+
}
|
|
465
|
+
if (!isRecord(value)) {
|
|
466
|
+
return value;
|
|
467
|
+
}
|
|
468
|
+
const [stage] = level.stages;
|
|
469
|
+
return stage === undefined
|
|
470
|
+
? projectedAtOnce(level, value)
|
|
471
|
+
: computedAtOnce(active, level, stage, value, contextFactory);
|
|
472
|
+
}
|
|
473
|
+
async function materializeRelation(active, level, relation, value, contextFactory) {
|
|
284
474
|
if (value === null || value === undefined) {
|
|
285
475
|
return value;
|
|
286
476
|
}
|
|
@@ -288,65 +478,62 @@ async function materializeRelation(active, compute, request, relation, value, co
|
|
|
288
478
|
if (!Array.isArray(value)) {
|
|
289
479
|
return value;
|
|
290
480
|
}
|
|
291
|
-
return Promise.all(value.map((entry) => materializeRecord(active,
|
|
481
|
+
return Promise.all(value.map((entry) => materializeRecord(active, level, entry, contextFactory)));
|
|
292
482
|
}
|
|
293
|
-
return materializeRecord(active,
|
|
483
|
+
return materializeRecord(active, level, value, contextFactory);
|
|
294
484
|
}
|
|
295
|
-
async function
|
|
296
|
-
if (!isRecord(value)) {
|
|
297
|
-
return value;
|
|
298
|
-
}
|
|
299
|
-
const resource = lookupResource(active, plan.resource);
|
|
300
|
-
if (resource === undefined) {
|
|
485
|
+
async function materializeInTurn(active, level, value, contextFactory) {
|
|
486
|
+
if (!isRecord(value) || level === undefined) {
|
|
301
487
|
return value;
|
|
302
488
|
}
|
|
489
|
+
const { stages } = level;
|
|
303
490
|
const record = { ...value };
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
491
|
+
let told;
|
|
492
|
+
if (stages.length > 1) {
|
|
493
|
+
told = { ...record };
|
|
494
|
+
for (const key of Object.keys(told)) {
|
|
495
|
+
const nested = told[key];
|
|
496
|
+
if (isNestedContainer(nested)) {
|
|
497
|
+
told[key] = frozenCopy(nested, true);
|
|
498
|
+
}
|
|
309
499
|
}
|
|
500
|
+
}
|
|
501
|
+
for (const stage of stages) {
|
|
502
|
+
const view = frozenCopy(told ?? record);
|
|
310
503
|
const computedValue = await stage.compute({
|
|
311
|
-
field:
|
|
312
|
-
value:
|
|
313
|
-
record,
|
|
504
|
+
field: stage.field,
|
|
505
|
+
value: view[stage.field],
|
|
506
|
+
record: view,
|
|
314
507
|
ctx: contextFactory(),
|
|
315
508
|
});
|
|
316
509
|
if (computedValue === undefined) {
|
|
317
510
|
continue;
|
|
318
511
|
}
|
|
319
|
-
const
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
fieldName,
|
|
324
|
-
"pipelines",
|
|
325
|
-
"compute",
|
|
326
|
-
"read",
|
|
327
|
-
]);
|
|
328
|
-
if (!validation.ok) {
|
|
329
|
-
throw new AvComputedValueError(plan.resource, fieldName, "read", validation.issues);
|
|
512
|
+
const held = heldReadValue(active, level, stage, computedValue);
|
|
513
|
+
record[stage.field] = held;
|
|
514
|
+
if (told !== undefined) {
|
|
515
|
+
told[stage.field] = held;
|
|
330
516
|
}
|
|
331
|
-
record[fieldName] = validation.value;
|
|
332
517
|
}
|
|
333
|
-
for (const relation of
|
|
518
|
+
for (const { relation, level: nested } of level.relations) {
|
|
334
519
|
if (!Object.hasOwn(record, relation.field)) {
|
|
335
520
|
continue;
|
|
336
521
|
}
|
|
337
|
-
record[relation.field] = await materializeRelation(active,
|
|
522
|
+
record[relation.field] = await materializeRelation(active, nested, relation, record[relation.field], contextFactory);
|
|
338
523
|
}
|
|
339
|
-
return
|
|
340
|
-
.filter((fieldName) => Object.hasOwn(record, fieldName))
|
|
341
|
-
.map((fieldName) => [fieldName, record[fieldName]]));
|
|
524
|
+
return answerOf(level, record);
|
|
342
525
|
}
|
|
343
|
-
export async function materializeReadOperation(active, compute,
|
|
526
|
+
export async function materializeReadOperation(active, compute, _request, plan, value, contextFactory) {
|
|
344
527
|
const projection = plan.projection;
|
|
345
528
|
if (!plan.materialize || projection === undefined) {
|
|
346
529
|
return value;
|
|
347
530
|
}
|
|
531
|
+
const level = resolveReadLevel(active, compute, projection, true);
|
|
348
532
|
if (Array.isArray(value)) {
|
|
349
|
-
|
|
533
|
+
const rows = value.map((entry) => materializeRecord(active, level, entry, contextFactory));
|
|
534
|
+
return rows.some((row) => row instanceof Promise)
|
|
535
|
+
? Promise.all(rows)
|
|
536
|
+
: Array.from(rows);
|
|
350
537
|
}
|
|
351
|
-
return materializeRecord(active,
|
|
538
|
+
return materializeRecord(active, level, value, contextFactory);
|
|
352
539
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { AvValidationIssue } from "../operations/validation-code.js";
|
|
2
2
|
/**
|
|
3
3
|
* What the diagnostics channel receives when a computed value — a read or write
|
|
4
|
-
* compute stage's return — is one its Contract refuses
|
|
4
|
+
* compute stage's return — is one its Contract refuses, or a `compute.create`
|
|
5
|
+
* stage returned `undefined` for a field a create cannot do without (rc.2): the developer's broken code,
|
|
5
6
|
* never the caller's. It is thrown, not a deliberate outcome, so the framework's
|
|
6
7
|
* boundary answers the caller the generic `A3000` and reports this error, with the
|
|
7
8
|
* issues, exactly once.
|
|
@@ -9,5 +10,5 @@ import type { AvValidationIssue } from "../operations/validation-code.js";
|
|
|
9
10
|
export declare class AvComputedValueError extends Error {
|
|
10
11
|
readonly issues: readonly AvValidationIssue[];
|
|
11
12
|
readonly name = "AvComputedValueError";
|
|
12
|
-
constructor(resource: string, field: string, stage: "read" | "create" | "update", issues: readonly AvValidationIssue[]);
|
|
13
|
+
constructor(resource: string, field: string, stage: "read" | "create" | "update", issues: readonly AvValidationIssue[], message?: string);
|
|
13
14
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
export class AvComputedValueError extends Error {
|
|
2
2
|
issues;
|
|
3
3
|
name = "AvComputedValueError";
|
|
4
|
-
constructor(resource, field, stage, issues) {
|
|
4
|
+
constructor(resource, field, stage, issues, message) {
|
|
5
5
|
const [first] = issues;
|
|
6
|
-
super(
|
|
6
|
+
super(message ??
|
|
7
|
+
`The compute.${stage} stage of ${resource}.${field} returned a value its Contract refuses${first === undefined ? "." : ` (${first.code}: ${first.message})`}`);
|
|
7
8
|
this.issues = issues;
|
|
8
9
|
}
|
|
9
10
|
}
|
|
@@ -7,7 +7,7 @@ import type { AvOperationFamily } from "../operations/operation-identity.js";
|
|
|
7
7
|
import { type AvDiagnosticsSink } from "./diagnostics-reporter.js";
|
|
8
8
|
import type { AvComputeContext } from "./field-compute.js";
|
|
9
9
|
import type { MisuseReporter } from "./misuse-reporter.js";
|
|
10
|
-
import type {
|
|
10
|
+
import type { AvApplicationOperationRequest } from "./operation-request.js";
|
|
11
11
|
import type { AvOperationResponse } from "./operation-response.js";
|
|
12
12
|
import type { AvContext, AvTransactionContext, AvTransportContext } from "./pipeline.js";
|
|
13
13
|
import type { AvState } from "./request-state.js";
|
|
@@ -35,8 +35,8 @@ export type ContextFacts = {
|
|
|
35
35
|
readonly $args: unknown;
|
|
36
36
|
};
|
|
37
37
|
/** Runs one raw application-origin call in `transaction`, or standalone. Total. */
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
type RawOperationRunner<M extends AvAdapterModel> = (request: AvApplicationOperationRequest, transaction: AvAdapterTransactionExecutor<M> | undefined) => Promise<AvOperationResponse>;
|
|
39
|
+
type ContextExecutorDependencies<M extends AvAdapterModel> = {
|
|
40
40
|
/** The model, as construction read it once: the ctx's Resources. */
|
|
41
41
|
readonly model: M;
|
|
42
42
|
readonly adapter: AvAdapter<M>;
|
|
@@ -57,3 +57,4 @@ export type ContextExecutor<M extends AvAdapterModel = AvAdapterModel> = {
|
|
|
57
57
|
};
|
|
58
58
|
/** Builds the ctx factory of one Framework over its model. */
|
|
59
59
|
export declare function createContextExecutor<M extends AvAdapterModel>(dependencies: ContextExecutorDependencies<M>): ContextExecutor<M>;
|
|
60
|
+
export {};
|
|
@@ -195,9 +195,10 @@ export function createContextExecutor(dependencies) {
|
|
|
195
195
|
const contextOf = (prototype, scope, facts, readOnly = false) => {
|
|
196
196
|
const context = Object.create(prototype);
|
|
197
197
|
Object.defineProperty(context, STATE, {
|
|
198
|
-
value: { scope, facts, resources:
|
|
198
|
+
value: { scope, facts, resources: undefined },
|
|
199
199
|
});
|
|
200
|
-
for (const
|
|
200
|
+
for (const key of Object.keys(facts)) {
|
|
201
|
+
const value = facts[key];
|
|
201
202
|
if (value !== undefined) {
|
|
202
203
|
Object.defineProperty(context, key, { value, enumerable: true });
|
|
203
204
|
}
|
|
@@ -232,6 +233,7 @@ export function createContextExecutor(dependencies) {
|
|
|
232
233
|
Object.defineProperty(prototype, resource, {
|
|
233
234
|
get() {
|
|
234
235
|
const state = stateOf(this);
|
|
236
|
+
state.resources ??= new Map();
|
|
235
237
|
let tree = state.resources.get(resource);
|
|
236
238
|
if (tree === undefined) {
|
|
237
239
|
tree = resourceTree(state.scope, resource, readOnly);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** The registered symbol every copy of this major brands class `name` with. */
|
|
2
|
+
export declare function coreBrandOf(name: string): symbol;
|
|
3
|
+
/** Whether `value` carries `brand`, wherever it was made: one `in`. */
|
|
4
|
+
export declare function hasCoreBrand(value: unknown, brand: symbol): boolean;
|
|
5
|
+
/**
|
|
6
|
+
* Brands `type`'s prototype as `name` and makes `instanceof type` read the brand.
|
|
7
|
+
* A developer's own subclass of `type` inherits the static `Symbol.hasInstance`, so
|
|
8
|
+
* on any constructor but `type` itself it answers as `instanceof` always does.
|
|
9
|
+
*/
|
|
10
|
+
export declare function brandCoreClass(type: abstract new (...args: never[]) => object, name: string): symbol;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { CORE_VERSION } from "../prebuilt/core-version.generated.js";
|
|
2
|
+
const CORE_MAJOR = CORE_VERSION.slice(0, CORE_VERSION.indexOf("."));
|
|
3
|
+
export function coreBrandOf(name) {
|
|
4
|
+
return Symbol.for(`aventara.core.${name}@${CORE_MAJOR}`);
|
|
5
|
+
}
|
|
6
|
+
export function hasCoreBrand(value, brand) {
|
|
7
|
+
return typeof value === "object" && value !== null && brand in value;
|
|
8
|
+
}
|
|
9
|
+
const ordinaryHasInstance = Function.prototype[Symbol.hasInstance];
|
|
10
|
+
export function brandCoreClass(type, name) {
|
|
11
|
+
const brand = coreBrandOf(name);
|
|
12
|
+
Object.defineProperty(type.prototype, brand, { value: true });
|
|
13
|
+
Object.defineProperty(type, Symbol.hasInstance, {
|
|
14
|
+
value: function hasInstance(value) {
|
|
15
|
+
return this === type
|
|
16
|
+
? hasCoreBrand(value, brand)
|
|
17
|
+
: ordinaryHasInstance.call(this, value);
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
return brand;
|
|
21
|
+
}
|
|
@@ -1,20 +1,32 @@
|
|
|
1
1
|
import type { AvContract } from "../contracts/contract.js";
|
|
2
|
+
import type { AvCreateRequirements } from "../contracts/create-requirements.js";
|
|
2
3
|
import type { AvOperationIdentity } from "../operations/operation-identity.js";
|
|
3
4
|
import type { AvValidationIssue } from "../operations/validation-code.js";
|
|
4
5
|
import type { ReferentialActionTable } from "./referential-action.js";
|
|
5
6
|
type Path = readonly (string | number)[];
|
|
7
|
+
/** One required field a `compute.create` stage was to fill and left missing. */
|
|
8
|
+
type ComputedRequirementGap = {
|
|
9
|
+
readonly resource: string;
|
|
10
|
+
readonly field: string;
|
|
11
|
+
readonly issue: AvValidationIssue;
|
|
12
|
+
};
|
|
6
13
|
/**
|
|
7
|
-
* What the Adapter stated
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
14
|
+
* What the Adapter stated that the checks read: its referential edges, for the
|
|
15
|
+
* fields that hold each reference, and its own create requirements per
|
|
16
|
+
* Resource, before any layer projected them (what write compute must not leave
|
|
17
|
+
* missing). Read once when the Framework is constructed. The requirements the
|
|
18
|
+
* caller is held to are the active Contract's.
|
|
11
19
|
*/
|
|
12
20
|
export type RecordWriteFacts = {
|
|
13
21
|
readonly references: ReferentialActionTable;
|
|
22
|
+
readonly stated: (resource: string) => AvCreateRequirements | undefined;
|
|
14
23
|
};
|
|
15
24
|
/** The facts an Adapter stated, read off it once; an absent table states nothing. */
|
|
16
25
|
export declare function recordWriteFactsOf(adapter: {
|
|
17
26
|
readonly referentialActions?: ReferentialActionTable;
|
|
27
|
+
readonly model?: {
|
|
28
|
+
readonly resources: Readonly<Record<string, unknown>>;
|
|
29
|
+
};
|
|
18
30
|
}): RecordWriteFacts;
|
|
19
31
|
/**
|
|
20
32
|
* The `V1000` issues for every create position in one operation's arguments
|
|
@@ -24,7 +36,21 @@ export declare function recordWriteFactsOf(adapter: {
|
|
|
24
36
|
* reference both, in argument order. Empty when there are none. Total over
|
|
25
37
|
* malformed input.
|
|
26
38
|
*/
|
|
27
|
-
export declare function createRequirementIssues(contract: AvContract, facts: RecordWriteFacts, request: AvOperationIdentity & {
|
|
39
|
+
export declare function createRequirementIssues(contract: AvContract, facts: Pick<RecordWriteFacts, "references">, request: AvOperationIdentity & {
|
|
28
40
|
readonly resource: string;
|
|
29
41
|
}, args: unknown, argumentsPath: Path): readonly AvValidationIssue[];
|
|
42
|
+
/**
|
|
43
|
+
* Every required field a `compute.create` stage was to fill and that is still
|
|
44
|
+
* missing after write compute, at every create position of one operation's
|
|
45
|
+
* arguments (`create.*`'s `data`, `upsert`'s `create`, every nested create),
|
|
46
|
+
* in argument order, read against the Adapter's own statement of each
|
|
47
|
+
* Resource's create requirements; `computed` names the fields a Resource's
|
|
48
|
+
* `compute.create` stages fill.
|
|
49
|
+
* A field the parent supplies to a nested create, a group whose relation the
|
|
50
|
+
* record writes, and a value the caller sent are not missing. Empty when
|
|
51
|
+
* nothing is.
|
|
52
|
+
*/
|
|
53
|
+
export declare function computedRequirementGapsOf(contract: AvContract, facts: RecordWriteFacts, request: AvOperationIdentity & {
|
|
54
|
+
readonly resource: string;
|
|
55
|
+
}, args: unknown, argumentsPath: Path, computed: (resource: string) => ReadonlySet<string>): readonly ComputedRequirementGap[];
|
|
30
56
|
export {};
|