@aventara/core 1.0.0-rc.0 → 1.0.0-rc.2
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 +1434 -0
- package/ERRORS.md +142 -0
- package/README.md +247 -57
- package/dist/adapters/adapter-discovery-diagnostic.d.ts +4 -4
- 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 +25 -11
- package/dist/adapters/adapter-identifier.d.ts +6 -6
- package/dist/adapters/adapter-model.d.ts +18 -9
- package/dist/adapters/adapter-operation-executor.interface.d.ts +4 -4
- package/dist/adapters/adapter-operation.d.ts +3 -3
- package/dist/adapters/adapter-resource.d.ts +18 -9
- package/dist/adapters/adapter-sql-statement.d.ts +19 -0
- package/dist/adapters/adapter-transaction-executor.interface.d.ts +19 -0
- package/dist/adapters/adapter.interface.d.ts +59 -29
- package/dist/avz/avz-check.factory.d.ts +83 -0
- package/dist/avz/avz-check.factory.js +116 -0
- package/dist/avz/avz-check.registry.d.ts +35 -0
- package/dist/avz/avz-check.registry.js +9 -0
- package/dist/avz/avz.d.ts +203 -0
- package/dist/{json → avz}/avz.js +150 -8
- package/dist/{json → avz}/index.d.ts +2 -1
- package/dist/{json → avz}/json-shape.registry.d.ts +7 -7
- package/dist/{json → avz}/zod-issue.translator.d.ts +8 -2
- package/dist/{json → avz}/zod-issue.translator.js +7 -0
- package/dist/compiler/contract-compiler-diagnostic.d.ts +31 -5
- 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 +18 -18
- package/dist/compiler/contract.compiler.js +637 -442
- package/dist/compiler/create-requirements.projector.d.ts +49 -0
- package/dist/compiler/create-requirements.projector.js +423 -0
- package/dist/compiler/field-validator.compiler.d.ts +47 -0
- package/dist/compiler/field-validator.compiler.js +238 -0
- package/dist/config/any-framework-config.d.ts +19 -12
- package/dist/config/computed-fields.d.ts +62 -0
- package/dist/config/computed-fields.js +80 -0
- package/dist/config/config-diagnostic.d.ts +11 -4
- package/dist/config/config-diagnostic.guidance.d.ts +6 -0
- package/dist/config/config-diagnostic.guidance.js +32 -0
- package/dist/config/config-layer.d.ts +15 -6
- package/dist/config/config.resolver.d.ts +74 -31
- package/dist/config/config.resolver.js +108 -44
- package/dist/config/config.validator.d.ts +7 -7
- package/dist/config/config.validator.js +581 -72
- package/dist/config/define-resource.d.ts +57 -0
- package/dist/config/define-resource.js +14 -0
- package/dist/config/effective-fields.d.ts +19 -23
- package/dist/config/entrypoint.normalizer.d.ts +1 -1
- package/dist/config/exact-framework-config.d.ts +308 -0
- package/dist/config/field-compute.resolver.d.ts +21 -0
- package/dist/config/field-compute.resolver.js +123 -0
- package/dist/config/field-pipeline-config.d.ts +47 -0
- package/dist/config/forced-operation.validator.d.ts +10 -0
- package/dist/config/forced-operation.validator.js +66 -0
- package/dist/config/framework-config.d.ts +111 -39
- package/dist/config/framework-exemptions-config.d.ts +91 -0
- package/dist/config/framework-exemptions-config.js +1 -0
- package/dist/config/framework-field-definition.d.ts +78 -0
- package/dist/config/framework-field-definition.js +28 -0
- package/dist/config/framework-resources-config.d.ts +122 -0
- package/dist/config/framework-resources-config.js +1 -0
- package/dist/config/pipeline-config.d.ts +56 -20
- package/dist/config/pipeline-tree.resolver.d.ts +79 -0
- package/dist/config/pipeline-tree.resolver.js +220 -0
- package/dist/config/stage-type.eraser.d.ts +65 -0
- package/dist/config/stage-type.eraser.js +1 -0
- package/dist/contracts/capability.d.ts +21 -12
- package/dist/contracts/capability.js +2 -0
- package/dist/contracts/client-contract-structure.validator.d.ts +388 -63
- package/dist/contracts/client-contract-structure.validator.js +156 -10
- package/dist/contracts/contract-canonicalizer.d.ts +26 -3
- package/dist/contracts/contract-canonicalizer.js +156 -29
- package/dist/contracts/contract-hash.d.ts +12 -7
- package/dist/contracts/contract-hash.js +3 -2
- package/dist/contracts/contract-limits.d.ts +4 -1
- package/dist/contracts/contract-limits.js +1 -0
- package/dist/contracts/contract-lookup.d.ts +5 -5
- package/dist/contracts/contract-protocol.d.ts +4 -4
- package/dist/contracts/contract.d.ts +24 -16
- package/dist/contracts/create-requirements.d.ts +35 -0
- package/dist/contracts/create-requirements.js +1 -0
- package/dist/contracts/enum-definition.d.ts +1 -1
- package/dist/contracts/field-check.d.ts +101 -0
- package/dist/contracts/field-check.js +1 -0
- package/dist/contracts/field.d.ts +81 -42
- package/dist/contracts/identifier.d.ts +4 -4
- package/dist/contracts/json-shape.d.ts +12 -1
- package/dist/contracts/lifecycle-trait.d.ts +2 -2
- package/dist/contracts/resource-operations.d.ts +28 -28
- package/dist/contracts/resource.d.ts +15 -9
- package/dist/contracts/scalar-value-type.d.ts +15 -15
- package/dist/contracts/scalar.d.ts +3 -3
- package/dist/contracts/transaction-capability.d.ts +1 -1
- package/dist/contracts/wire-scalar-format.d.ts +4 -4
- package/dist/framework/contract-view.d.ts +213 -147
- package/dist/framework/framework-construction.error.d.ts +19 -10
- package/dist/framework/framework-construction.error.js +7 -3
- package/dist/framework/framework.d.ts +47 -23
- package/dist/framework/framework.factory.d.ts +8 -6
- package/dist/framework/framework.factory.js +49 -22
- package/dist/framework/operation-facade.d.ts +123 -52
- package/dist/framework/operation-facade.js +9 -1
- package/dist/index.d.ts +57 -50
- package/dist/index.js +7 -6
- package/dist/internal.d.ts +17 -10
- package/dist/internal.js +4 -1
- package/dist/operations/database-refusal.d.ts +51 -0
- package/dist/operations/database-refusal.js +45 -0
- package/dist/operations/operation-arguments.d.ts +343 -207
- package/dist/operations/operation-call.d.ts +27 -28
- package/dist/operations/operation-identity.d.ts +10 -10
- package/dist/operations/operation-result.d.ts +21 -21
- package/dist/operations/operation-validator-core.d.ts +6 -6
- package/dist/operations/operation-validator-core.js +99 -6
- package/dist/operations/operation-validator.d.ts +9 -9
- package/dist/operations/projection-scope.resolver.d.ts +6 -6
- package/dist/operations/structural-limits.walker.d.ts +6 -6
- package/dist/operations/structural-limits.walker.js +145 -0
- package/dist/operations/validation-code.d.ts +11 -6
- package/dist/operations/validation-code.guidance.d.ts +6 -0
- package/dist/operations/validation-code.guidance.js +90 -0
- package/dist/operations/validation-code.js +4 -0
- package/dist/operations/write-scope.resolver.d.ts +10 -6
- package/dist/operations/write-scope.resolver.js +2 -0
- package/dist/protocol/absent-route.responder.d.ts +13 -12
- package/dist/protocol/absent-route.responder.js +19 -19
- package/dist/protocol/contract-document.responder.d.ts +3 -3
- package/dist/protocol/contract-document.responder.js +2 -2
- package/dist/protocol/http-request.decoder.d.ts +17 -13
- package/dist/protocol/http-request.decoder.js +10 -10
- package/dist/protocol/http-request.reader.d.ts +3 -3
- package/dist/protocol/http-response.encoder.d.ts +4 -4
- package/dist/protocol/http-response.encoder.js +94 -55
- package/dist/protocol/http-status.table.d.ts +2 -2
- package/dist/protocol/operation-response.guard.d.ts +2 -2
- package/dist/protocol/protocol-surface.d.ts +4 -4
- package/dist/protocol/protocol.binder.d.ts +50 -27
- package/dist/protocol/protocol.binder.js +12 -9
- package/dist/protocol/protocol.handler.d.ts +22 -13
- package/dist/protocol/protocol.handler.js +91 -17
- package/dist/protocol/unmounted-route.error.d.ts +4 -4
- package/dist/protocol/unmounted-route.error.js +2 -2
- package/dist/runtime/caller-data.copier.d.ts +22 -5
- package/dist/runtime/caller-data.copier.js +31 -14
- package/dist/runtime/caller-data.door.d.ts +17 -11
- package/dist/runtime/caller-data.door.js +6 -4
- package/dist/runtime/computed-read-runtime.d.ts +7 -6
- package/dist/runtime/computed-read-runtime.js +76 -50
- package/dist/runtime/computed-value.error.d.ts +7 -6
- package/dist/runtime/computed-value.error.js +5 -4
- package/dist/runtime/context-executor.runtime.d.ts +59 -0
- package/dist/runtime/context-executor.runtime.js +275 -0
- package/dist/runtime/create-requirement.d.ts +44 -79
- package/dist/runtime/create-requirement.js +213 -73
- package/dist/runtime/decimal.d.ts +2 -2
- package/dist/runtime/decimal.js +1 -1
- package/dist/runtime/diagnostics-reporter.d.ts +54 -27
- package/dist/runtime/diagnostics-reporter.js +24 -0
- package/dist/runtime/error-boundary.d.ts +65 -8
- package/dist/runtime/error-boundary.js +49 -19
- 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 +10 -2
- package/dist/runtime/field-check.evaluator.d.ts +29 -0
- package/dist/runtime/field-check.evaluator.js +521 -0
- package/dist/runtime/field-compute.d.ts +64 -0
- package/dist/runtime/field-compute.js +1 -0
- package/dist/runtime/field-stage.plan.d.ts +15 -0
- package/dist/runtime/field-stage.plan.js +27 -0
- package/dist/runtime/field-stage.runtime.d.ts +37 -0
- package/dist/runtime/field-stage.runtime.js +147 -0
- package/dist/runtime/field-validator.runtime.d.ts +19 -0
- package/dist/runtime/field-validator.runtime.js +92 -0
- package/dist/runtime/framework-error-class.table.d.ts +33 -0
- package/dist/runtime/framework-error-class.table.js +25 -0
- package/dist/runtime/framework-error.d.ts +68 -8
- package/dist/runtime/framework-error.factory.d.ts +4 -0
- package/dist/runtime/framework-error.factory.js +15 -0
- package/dist/runtime/framework-error.js +23 -2
- package/dist/runtime/interceptor-next.error.d.ts +5 -0
- package/dist/runtime/interceptor-next.error.js +6 -0
- package/dist/runtime/json-value.d.ts +11 -6
- package/dist/runtime/level-lifecycle.runtime.d.ts +25 -0
- package/dist/runtime/level-lifecycle.runtime.js +39 -0
- package/dist/runtime/misuse-reporter.d.ts +12 -12
- package/dist/runtime/mutation-planner.d.ts +19 -10
- package/dist/runtime/mutation-planner.js +48 -35
- package/dist/runtime/nested-write.walker.d.ts +32 -0
- package/dist/runtime/nested-write.walker.js +73 -0
- 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 +33 -6
- package/dist/runtime/operation-response.d.ts +17 -17
- package/dist/runtime/operation-runtime.d.ts +127 -25
- package/dist/runtime/operation-runtime.js +441 -78
- package/dist/runtime/outcome-mapper.d.ts +16 -5
- package/dist/runtime/outcome-mapper.js +23 -6
- package/dist/runtime/output-validator.d.ts +10 -10
- package/dist/runtime/output-validator.js +3 -3
- package/dist/runtime/owned-execution.registry.d.ts +16 -6
- package/dist/runtime/pipe-output.validator.d.ts +43 -18
- package/dist/runtime/pipe-output.validator.js +15 -13
- package/dist/runtime/pipeline.d.ts +223 -34
- package/dist/runtime/readonly-value.d.ts +43 -0
- package/dist/runtime/readonly-value.js +150 -0
- package/dist/runtime/request-envelope.validator.d.ts +3 -3
- package/dist/runtime/request-envelope.validator.js +12 -7
- package/dist/runtime/request-id.d.ts +1 -1
- package/dist/runtime/request-state.d.ts +14 -0
- package/dist/runtime/request-state.js +1 -0
- package/dist/runtime/request-state.resolver.d.ts +12 -0
- package/dist/runtime/request-state.resolver.js +20 -0
- package/dist/runtime/scalar-runtime.d.ts +35 -16
- package/dist/runtime/scalar-runtime.js +102 -34
- package/dist/runtime/unsent-value.normalizer.d.ts +15 -0
- package/dist/runtime/unsent-value.normalizer.js +128 -0
- package/dist/transactions/deferred-operation.d.ts +35 -20
- package/dist/transactions/operation-arguments-encoder.d.ts +3 -3
- package/dist/transactions/operation-arguments-encoder.js +2 -2
- package/dist/transactions/operation-fingerprint.js +2 -2
- package/dist/transactions/sql-statement.d.ts +85 -0
- package/dist/transactions/sql-statement.js +47 -0
- package/dist/transactions/sql-statement.validator.d.ts +44 -0
- package/dist/transactions/sql-statement.validator.js +167 -0
- package/dist/transactions/transaction-envelope.d.ts +4 -4
- package/dist/transactions/transaction-integrity-error.d.ts +6 -6
- package/dist/transactions/transaction-integrity-error.js +5 -2
- package/dist/transactions/transaction-plan-assembler.d.ts +21 -11
- package/dist/transactions/transaction-plan-assembler.js +169 -32
- package/dist/transactions/transaction-plan-validator.d.ts +45 -20
- package/dist/transactions/transaction-plan-validator.js +96 -38
- package/dist/transactions/transaction-reference-collector.d.ts +5 -5
- package/dist/transactions/transaction-reference-resolver.d.ts +19 -2
- package/dist/transactions/transaction-reference-resolver.js +26 -14
- package/dist/transactions/transaction-reference-validator.d.ts +76 -4
- package/dist/transactions/transaction-reference-validator.js +129 -71
- package/dist/transactions/transaction-reference.d.ts +13 -13
- package/dist/transactions/transaction-reference.js +5 -0
- package/dist/transactions/transaction-request.d.ts +18 -5
- package/dist/transactions/transaction-response.d.ts +6 -6
- package/dist/transactions/transaction-runtime.d.ts +8 -7
- package/dist/transactions/transaction-runtime.js +191 -50
- package/dist/transactions/transaction-settlement.runtime.d.ts +51 -0
- package/dist/transactions/transaction-settlement.runtime.js +120 -0
- package/dist/transactions/transaction-slot-path-error.d.ts +4 -4
- package/dist/transactions/transaction-slot-path-error.js +2 -2
- package/dist/transactions/transaction-slot-writer.js +2 -2
- package/dist/transactions/transaction-stage.runtime.d.ts +82 -0
- package/dist/transactions/transaction-stage.runtime.js +126 -0
- package/package.json +9 -7
- package/src/runtime/field-check.evaluator.ts +720 -0
- package/dist/config/define-fields.d.ts +0 -42
- package/dist/config/define-fields.js +0 -3
- package/dist/config/framework-behaviors-config.d.ts +0 -30
- package/dist/config/framework-fields-config.d.ts +0 -42
- package/dist/config/framework-restrictions-config.d.ts +0 -142
- package/dist/json/avz.d.ts +0 -96
- package/dist/runtime/field-behavior.d.ts +0 -48
- /package/dist/{config/framework-behaviors-config.js → adapters/adapter-sql-statement.js} +0 -0
- /package/dist/{config/framework-fields-config.js → adapters/adapter-transaction-executor.interface.js} +0 -0
- /package/dist/{json → avz}/index.js +0 -0
- /package/dist/{json → avz}/json-shape.registry.js +0 -0
- /package/dist/config/{framework-restrictions-config.js → exact-framework-config.js} +0 -0
- /package/dist/{runtime/field-behavior.js → config/field-pipeline-config.js} +0 -0
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import { isOperationVariantAvailable } from "../contracts/resource-operations.js";
|
|
2
|
+
import { parseOperationIdentity } from "../operations/operation-identity.js";
|
|
3
|
+
import { validationIssue } from "../operations/validation-code.js";
|
|
4
|
+
import { readSqlTemplate } from "../transactions/sql-statement.js";
|
|
5
|
+
import { normalizeSqlValue } from "../transactions/sql-statement.validator.js";
|
|
6
|
+
import { AvTransactionIntegrityError } from "../transactions/transaction-integrity-error.js";
|
|
7
|
+
import { transactionInfrastructureFailure } from "../transactions/transaction-response.js";
|
|
8
|
+
import { copyAtDoor, refuseCallerData } from "./caller-data.door.js";
|
|
9
|
+
import { createReporter, } from "./diagnostics-reporter.js";
|
|
10
|
+
import { AdapterBoundary, sanitizeOperationFailure } from "./error-boundary.js";
|
|
11
|
+
import { thrownFailure } from "./framework-error.factory.js";
|
|
12
|
+
import { operationFailure } from "./operation-response.js";
|
|
13
|
+
import { mapValidationOutcome } from "./outcome-mapper.js";
|
|
14
|
+
import { readonlyView } from "./readonly-value.js";
|
|
15
|
+
const COMPUTE_STATE = "Compute's ctx.$state";
|
|
16
|
+
const STATE = Symbol("aventara.context");
|
|
17
|
+
const READ_FAMILY = "find";
|
|
18
|
+
function readOnlyRefusal(member) {
|
|
19
|
+
return new TypeError(`Compute's ctx is read-only: ${member} is not available in a compute stage. Put effects on other rows in an after hook.`);
|
|
20
|
+
}
|
|
21
|
+
function refusedStatement(issues) {
|
|
22
|
+
return mapValidationOutcome(issues);
|
|
23
|
+
}
|
|
24
|
+
function unavailable(message) {
|
|
25
|
+
return operationFailure("A2002", {
|
|
26
|
+
message,
|
|
27
|
+
issues: [validationIssue("V1006", [], message)],
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
export function createContextExecutor(dependencies) {
|
|
31
|
+
const { adapter, misuse } = dependencies;
|
|
32
|
+
const model = dependencies.model;
|
|
33
|
+
const stateOf = (context) => context[STATE];
|
|
34
|
+
const reporterOf = (scope) => createReporter(dependencies.diagnostics, {
|
|
35
|
+
kind: "transaction",
|
|
36
|
+
origin: "application",
|
|
37
|
+
requestId: scope.requestId,
|
|
38
|
+
});
|
|
39
|
+
const call = async (scope, resource, identity, args) => {
|
|
40
|
+
const response = await dependencies.run({
|
|
41
|
+
...identity,
|
|
42
|
+
origin: "application",
|
|
43
|
+
resource,
|
|
44
|
+
requestId: scope.requestId,
|
|
45
|
+
state: scope.state,
|
|
46
|
+
arguments: args === undefined ? {} : args,
|
|
47
|
+
}, scope.transaction);
|
|
48
|
+
if (response.cause !== null) {
|
|
49
|
+
throw thrownFailure(response);
|
|
50
|
+
}
|
|
51
|
+
return response.data;
|
|
52
|
+
};
|
|
53
|
+
const resourceTree = (scope, resource, readOnly) => {
|
|
54
|
+
const families = {};
|
|
55
|
+
const operations = model.resources[resource]?.operations ?? {};
|
|
56
|
+
for (const [family, variants] of Object.entries(operations)) {
|
|
57
|
+
if (readOnly && family !== READ_FAMILY) {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
const leaves = {};
|
|
61
|
+
for (const [variant, availability] of Object.entries(variants ?? {})) {
|
|
62
|
+
const identity = parseOperationIdentity(family, variant);
|
|
63
|
+
if (identity !== undefined &&
|
|
64
|
+
isOperationVariantAvailable(availability)) {
|
|
65
|
+
leaves[variant] = (args) => call(scope, resource, identity, args);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
families[family] = Object.freeze(leaves);
|
|
69
|
+
}
|
|
70
|
+
if (readOnly) {
|
|
71
|
+
const tree = Object.create(Object.prototype);
|
|
72
|
+
for (const [family, leaves] of Object.entries(families)) {
|
|
73
|
+
Object.defineProperty(tree, family, {
|
|
74
|
+
value: leaves,
|
|
75
|
+
enumerable: true,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
for (const family of Object.keys(operations)) {
|
|
79
|
+
if (family === READ_FAMILY) {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
Object.defineProperty(tree, family, {
|
|
83
|
+
get() {
|
|
84
|
+
throw readOnlyRefusal(`ctx.${resource}.${family}`);
|
|
85
|
+
},
|
|
86
|
+
enumerable: false,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
return Object.freeze(tree);
|
|
90
|
+
}
|
|
91
|
+
return Object.freeze(families);
|
|
92
|
+
};
|
|
93
|
+
const statementOf = (strings, values) => {
|
|
94
|
+
if (adapter.sqlStatements !== true) {
|
|
95
|
+
return {
|
|
96
|
+
ok: false,
|
|
97
|
+
response: unavailable("SQL statements are not available on this Adapter."),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
const text = readSqlTemplate(strings, values.length);
|
|
101
|
+
if (text === undefined) {
|
|
102
|
+
return {
|
|
103
|
+
ok: false,
|
|
104
|
+
response: refusedStatement([
|
|
105
|
+
validationIssue("V1001", ["strings"], "SQL must be written as a tagged template: ctx.$sql`…`."),
|
|
106
|
+
]),
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
const copy = copyAtDoor([...values]);
|
|
110
|
+
if (!copy.ok) {
|
|
111
|
+
return {
|
|
112
|
+
ok: false,
|
|
113
|
+
response: refusedStatement([
|
|
114
|
+
refuseCallerData(copy.error, ["values"], { origin: "application" }, misuse),
|
|
115
|
+
]),
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
const bound = [];
|
|
119
|
+
const issues = [];
|
|
120
|
+
for (const [position, value] of copy.value.entries()) {
|
|
121
|
+
const normalized = normalizeSqlValue(value, ["values", position]);
|
|
122
|
+
if (normalized.ok) {
|
|
123
|
+
bound.push(normalized.value);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
issues.push(...normalized.issues);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (issues.length > 0) {
|
|
130
|
+
return { ok: false, response: refusedStatement(issues) };
|
|
131
|
+
}
|
|
132
|
+
return { ok: true, statement: { strings: text, values: bound } };
|
|
133
|
+
};
|
|
134
|
+
const executeStatement = async (runner, inTransaction, statement, report) => {
|
|
135
|
+
if (inTransaction && typeof runner.executeSql !== "function") {
|
|
136
|
+
const error = new AvTransactionIntegrityError("statement-unavailable");
|
|
137
|
+
report(error, "A3002");
|
|
138
|
+
throw thrownFailure(transactionInfrastructureFailure());
|
|
139
|
+
}
|
|
140
|
+
const boundary = new AdapterBoundary();
|
|
141
|
+
try {
|
|
142
|
+
return await boundary.execute(async () => {
|
|
143
|
+
if (typeof runner.executeSql !== "function") {
|
|
144
|
+
throw new TypeError("Adapter declares sqlStatements but has no executeSql.");
|
|
145
|
+
}
|
|
146
|
+
const rows = await runner.executeSql(statement);
|
|
147
|
+
if (!Array.isArray(rows)) {
|
|
148
|
+
throw new TypeError("Adapter executeSql must resolve the statement's rows as an array.");
|
|
149
|
+
}
|
|
150
|
+
return [...rows];
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
catch (error) {
|
|
154
|
+
throw thrownFailure(sanitizeOperationFailure(error, boundary.originOf(error), report, {
|
|
155
|
+
path: ["values"],
|
|
156
|
+
arguments: statement.values,
|
|
157
|
+
}));
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
const openTransaction = async (scope, work) => {
|
|
161
|
+
if (typeof adapter.transaction !== "function") {
|
|
162
|
+
throw thrownFailure(unavailable("Transactions are not available on this Adapter."));
|
|
163
|
+
}
|
|
164
|
+
let thrown;
|
|
165
|
+
try {
|
|
166
|
+
return await adapter.transaction(async (executor) => {
|
|
167
|
+
try {
|
|
168
|
+
return await work(executor);
|
|
169
|
+
}
|
|
170
|
+
catch (error) {
|
|
171
|
+
thrown = { error };
|
|
172
|
+
throw error;
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
if (thrown !== undefined && error === thrown.error) {
|
|
178
|
+
throw error;
|
|
179
|
+
}
|
|
180
|
+
reporterOf(scope)(error, "A3002");
|
|
181
|
+
throw thrownFailure(transactionInfrastructureFailure());
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
const sql = async (scope, strings, values) => {
|
|
185
|
+
const prepared = statementOf(strings, values);
|
|
186
|
+
if (!prepared.ok) {
|
|
187
|
+
throw thrownFailure(prepared.response);
|
|
188
|
+
}
|
|
189
|
+
const report = reporterOf(scope);
|
|
190
|
+
const open = scope.transaction;
|
|
191
|
+
return open !== undefined
|
|
192
|
+
? executeStatement(open, true, prepared.statement, report)
|
|
193
|
+
: executeStatement(adapter, false, prepared.statement, report);
|
|
194
|
+
};
|
|
195
|
+
const contextOf = (prototype, scope, facts, readOnly = false) => {
|
|
196
|
+
const context = Object.create(prototype);
|
|
197
|
+
Object.defineProperty(context, STATE, {
|
|
198
|
+
value: { scope, facts, resources: new Map() },
|
|
199
|
+
});
|
|
200
|
+
for (const [key, value] of Object.entries(facts)) {
|
|
201
|
+
if (value !== undefined) {
|
|
202
|
+
Object.defineProperty(context, key, { value, enumerable: true });
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
Object.defineProperty(context, "$state", {
|
|
206
|
+
value: readOnly ? readonlyView(scope.state, COMPUTE_STATE) : scope.state,
|
|
207
|
+
enumerable: true,
|
|
208
|
+
});
|
|
209
|
+
return context;
|
|
210
|
+
};
|
|
211
|
+
const transactionOf = (prototype) => (context, work) => {
|
|
212
|
+
const { scope, facts } = stateOf(context);
|
|
213
|
+
if (typeof work !== "function") {
|
|
214
|
+
return Promise.reject(new TypeError("ctx.$transaction takes an async callback: (tx) => …"));
|
|
215
|
+
}
|
|
216
|
+
const run = work;
|
|
217
|
+
if (scope.transaction !== undefined) {
|
|
218
|
+
return (async () => run(context))();
|
|
219
|
+
}
|
|
220
|
+
if (dependencies.application.transactions === "none") {
|
|
221
|
+
return Promise.reject(thrownFailure(unavailable("Transactions are not available on the application Contract.")));
|
|
222
|
+
}
|
|
223
|
+
return openTransaction(scope, (executor) => run(contextOf(prototype, {
|
|
224
|
+
requestId: scope.requestId,
|
|
225
|
+
transaction: executor,
|
|
226
|
+
state: scope.state,
|
|
227
|
+
}, facts)));
|
|
228
|
+
};
|
|
229
|
+
const prototypeOf = (readOnly) => {
|
|
230
|
+
const prototype = {};
|
|
231
|
+
for (const resource of Object.keys(model.resources)) {
|
|
232
|
+
Object.defineProperty(prototype, resource, {
|
|
233
|
+
get() {
|
|
234
|
+
const state = stateOf(this);
|
|
235
|
+
let tree = state.resources.get(resource);
|
|
236
|
+
if (tree === undefined) {
|
|
237
|
+
tree = resourceTree(state.scope, resource, readOnly);
|
|
238
|
+
state.resources.set(resource, tree);
|
|
239
|
+
}
|
|
240
|
+
return tree;
|
|
241
|
+
},
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
if (readOnly) {
|
|
245
|
+
for (const member of ["$sql", "$transaction"]) {
|
|
246
|
+
Object.defineProperty(prototype, member, {
|
|
247
|
+
get() {
|
|
248
|
+
throw readOnlyRefusal(`ctx.${member}`);
|
|
249
|
+
},
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
return Object.freeze(prototype);
|
|
253
|
+
}
|
|
254
|
+
const transaction = transactionOf(prototype);
|
|
255
|
+
Object.defineProperty(prototype, "$sql", {
|
|
256
|
+
get() {
|
|
257
|
+
const { scope } = stateOf(this);
|
|
258
|
+
return (strings, ...values) => sql(scope, strings, values);
|
|
259
|
+
},
|
|
260
|
+
});
|
|
261
|
+
Object.defineProperty(prototype, "$transaction", {
|
|
262
|
+
get() {
|
|
263
|
+
return (work) => transaction(this, work);
|
|
264
|
+
},
|
|
265
|
+
});
|
|
266
|
+
return Object.freeze(prototype);
|
|
267
|
+
};
|
|
268
|
+
const full = prototypeOf(false);
|
|
269
|
+
const reads = prototypeOf(true);
|
|
270
|
+
return {
|
|
271
|
+
operation: (scope, facts) => contextOf(full, scope, facts),
|
|
272
|
+
transaction: (scope, facts) => contextOf(full, scope, facts),
|
|
273
|
+
compute: (scope, facts) => contextOf(reads, scope, facts, true),
|
|
274
|
+
};
|
|
275
|
+
}
|
|
@@ -1,101 +1,66 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
1
|
+
import type { AvContract } from "../contracts/contract.js";
|
|
2
|
+
import type { AvCreateRequirements } from "../contracts/create-requirements.js";
|
|
3
|
+
import type { AvOperationIdentity } from "../operations/operation-identity.js";
|
|
4
|
+
import type { AvValidationIssue } from "../operations/validation-code.js";
|
|
4
5
|
import type { ReferentialActionTable } from "./referential-action.js";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
* **The facts are an Adapter's.** Which values a store cannot create a row
|
|
9
|
-
* without is a property of the store's schema — a column with no default, a
|
|
10
|
-
* reference that must point somewhere — and only the Adapter can read it. The
|
|
11
|
-
* words are Aventara's, so an Adapter translates its provider's facts into them,
|
|
12
|
-
* and the reasoning over them is core's, so no Adapter re-implements it.
|
|
13
|
-
*
|
|
14
|
-
* None of this enters a Contract. A Contract carries no foreign-key detail and
|
|
15
|
-
* no knowledge of which relation is the other end of which, and a requirement
|
|
16
|
-
* needs both; it is a server-side fact, read once when the Framework is
|
|
17
|
-
* constructed, like the referential actions.
|
|
18
|
-
*
|
|
19
|
-
* **When the check runs.** After guards, pipes and computed write behaviours —
|
|
20
|
-
* the moment the arguments are what the Adapter will be handed — and before
|
|
21
|
-
* any `before` hook or Adapter work. Earlier would refuse a value a pipe or a
|
|
22
|
-
* computed behaviour was about to supply; later is the store's own refusal,
|
|
23
|
-
* which reaches the caller as an internal failure. A missing value is the
|
|
24
|
-
* caller's to fix, so it answers `A2004` with a `V1000` issue at the path where
|
|
25
|
-
* the value belongs.
|
|
26
|
-
*
|
|
27
|
-
* **One value, two spellings.** A relation that holds a reference has scalar
|
|
28
|
-
* fields that hold it too — the Adapter states which, on the relation's
|
|
29
|
-
* referential edge (`ReferentialEdge.references`), for every such relation,
|
|
30
|
-
* required or optional. A write that sets both — `authorId` and
|
|
31
|
-
* `author: { $connect: … }` in one record, at create or update — names the
|
|
32
|
-
* reference twice. No store can honour both, and which one the caller meant is
|
|
33
|
-
* not the framework's to guess, so it is the caller's `A2004` too: a `V1012`
|
|
34
|
-
* issue at the relation, in every record the check walks, before any Adapter
|
|
35
|
-
* work. The same edge is what a required relation may instead be written
|
|
36
|
-
* through, so the pairing has one source.
|
|
37
|
-
*
|
|
38
|
-
* **One store, one spelling per record.** A store may take a record's
|
|
39
|
-
* references only one way at a time — every relation that holds one written as
|
|
40
|
-
* a relation, or every one through its fields — and state it as the Contract's
|
|
41
|
-
* `referenceWrites: "uniform"`. Under it, a record that writes a relation
|
|
42
|
-
* holding a reference beside another relation's reference field is the caller's
|
|
43
|
-
* `A2004` as well: a `V1012` issue at the relation write.
|
|
44
|
-
*/
|
|
45
|
-
/** A relation edge, named by the Resource that holds it and its field there. */
|
|
46
|
-
export type CreateRequirementEdge = {
|
|
6
|
+
type Path = readonly (string | number)[];
|
|
7
|
+
/** One required field a `compute.create` stage was to fill and left missing. */
|
|
8
|
+
export type ComputedRequirementGap = {
|
|
47
9
|
readonly resource: string;
|
|
48
|
-
readonly relation: string;
|
|
49
|
-
};
|
|
50
|
-
/**
|
|
51
|
-
* One value a create of a Resource cannot do without.
|
|
52
|
-
*
|
|
53
|
-
* - `field` — a scalar with no default, generated value or other source: it
|
|
54
|
-
* must be written.
|
|
55
|
-
* - `relation` — a required to-one relation: it must be written (connected or
|
|
56
|
-
* created), or every field that holds its reference must be — the
|
|
57
|
-
* `references` of the relation's referential edge, less any the store fills
|
|
58
|
-
* itself (`DEFAULTED` or `GENERATED_ON_CREATE`). When the row is created
|
|
59
|
-
* **through** the relation's other end (`inverse`), the parent supplies it,
|
|
60
|
-
* and it is not required.
|
|
61
|
-
*/
|
|
62
|
-
export type CreateRequirement = {
|
|
63
|
-
readonly kind: "field";
|
|
64
10
|
readonly field: string;
|
|
65
|
-
|
|
66
|
-
readonly kind: "relation";
|
|
67
|
-
readonly relation: string;
|
|
68
|
-
readonly inverse?: CreateRequirementEdge;
|
|
11
|
+
readonly issue: AvValidationIssue;
|
|
69
12
|
};
|
|
70
13
|
/**
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* What the Adapter stated that the check reads: its create requirements, and
|
|
78
|
-
* its referential edges for the fields that hold each reference. Read once when
|
|
79
|
-
* the Framework is constructed.
|
|
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.
|
|
80
19
|
*/
|
|
81
20
|
export type RecordWriteFacts = {
|
|
82
|
-
readonly requirements: CreateRequirementTable;
|
|
83
21
|
readonly references: ReferentialActionTable;
|
|
22
|
+
readonly stated: (resource: string) => AvCreateRequirements | undefined;
|
|
84
23
|
};
|
|
85
24
|
/** The facts an Adapter stated, read off it once; an absent table states nothing. */
|
|
86
25
|
export declare function recordWriteFactsOf(adapter: {
|
|
87
|
-
readonly createRequirements?: CreateRequirementTable;
|
|
88
26
|
readonly referentialActions?: ReferentialActionTable;
|
|
27
|
+
readonly model?: {
|
|
28
|
+
readonly resources: Readonly<Record<string, unknown>>;
|
|
29
|
+
};
|
|
89
30
|
}): RecordWriteFacts;
|
|
90
31
|
/**
|
|
91
32
|
* The `V1000` issues for every create position in one operation's arguments
|
|
92
|
-
* that lacks a value the
|
|
33
|
+
* that lacks a value the active Contract requires — `create.*`'s `data`, `upsert`'s
|
|
93
34
|
* `create`, and every nested create under any write — and the `V1012` issues
|
|
94
35
|
* for every write record, create or update, that sets a relation and its
|
|
95
36
|
* reference both, in argument order. Empty when there are none. Total over
|
|
96
37
|
* malformed input.
|
|
97
38
|
*/
|
|
98
|
-
export declare function createRequirementIssues(contract:
|
|
39
|
+
export declare function createRequirementIssues(contract: AvContract, facts: Pick<RecordWriteFacts, "references">, request: AvOperationIdentity & {
|
|
40
|
+
readonly resource: string;
|
|
41
|
+
}, args: unknown, argumentsPath: Path): readonly AvValidationIssue[];
|
|
42
|
+
/**
|
|
43
|
+
* The `V1000` issues for every create position of one operation's arguments
|
|
44
|
+
* that lacks a value the active Contract requires, and the `V1012` issues for
|
|
45
|
+
* every write record that sets a relation and its reference both, on the
|
|
46
|
+
* arguments as the caller sent them, before any pipeline stage runs. Empty when
|
|
47
|
+
* there are none.
|
|
48
|
+
*/
|
|
49
|
+
export declare function preliminaryRecordIssues(contract: AvContract, facts: Pick<RecordWriteFacts, "references">, request: AvOperationIdentity & {
|
|
50
|
+
readonly resource: string;
|
|
51
|
+
}, args: unknown, argumentsPath: Path): readonly AvValidationIssue[];
|
|
52
|
+
/**
|
|
53
|
+
* Every required field a `compute.create` stage was to fill and that is still
|
|
54
|
+
* missing after write compute, at every create position of one operation's
|
|
55
|
+
* arguments (`create.*`'s `data`, `upsert`'s `create`, every nested create),
|
|
56
|
+
* in argument order, read against the Adapter's own statement of each
|
|
57
|
+
* Resource's create requirements; `computed` names the fields a Resource's
|
|
58
|
+
* `compute.create` stages fill.
|
|
59
|
+
* A field the parent supplies to a nested create, a group whose relation the
|
|
60
|
+
* record writes, and a value the caller sent are not missing. Empty when
|
|
61
|
+
* nothing is.
|
|
62
|
+
*/
|
|
63
|
+
export declare function computedRequirementGapsOf(contract: AvContract, facts: RecordWriteFacts, request: AvOperationIdentity & {
|
|
99
64
|
readonly resource: string;
|
|
100
|
-
}, args: unknown, argumentsPath: Path): readonly
|
|
65
|
+
}, args: unknown, argumentsPath: Path, computed: (resource: string) => ReadonlySet<string>): readonly ComputedRequirementGap[];
|
|
101
66
|
export {};
|