quidproquo-core 0.1.26 → 0.1.27
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/lib/commonjs/actions/keyValueStore/askKeyValueStoreQuery.d.ts +2 -1
- package/lib/commonjs/actions/keyValueStore/askKeyValueStoreQuery.js +1 -0
- package/lib/commonjs/actions/keyValueStore/askKeyValueStoreQuery.js.map +1 -1
- package/lib/commonjs/config/settings/keyValueStore.d.ts +2 -0
- package/lib/commonjs/config/settings/keyValueStore.js +20 -5
- package/lib/commonjs/config/settings/keyValueStore.js.map +1 -1
- package/lib/commonjs/logic/index.d.ts +1 -0
- package/lib/commonjs/logic/index.js +1 -0
- package/lib/commonjs/logic/index.js.map +1 -1
- package/lib/commonjs/logic/keyValueStore/KvsIndexNotFoundError.d.ts +5 -0
- package/lib/commonjs/logic/keyValueStore/KvsIndexNotFoundError.js +13 -0
- package/lib/commonjs/logic/keyValueStore/KvsIndexNotFoundError.js.map +1 -0
- package/lib/commonjs/logic/keyValueStore/flattenKvsQueryConditions.d.ts +3 -0
- package/lib/commonjs/logic/keyValueStore/flattenKvsQueryConditions.js +15 -0
- package/lib/commonjs/logic/keyValueStore/flattenKvsQueryConditions.js.map +1 -0
- package/lib/commonjs/logic/keyValueStore/index.d.ts +3 -0
- package/lib/commonjs/logic/keyValueStore/index.js +20 -0
- package/lib/commonjs/logic/keyValueStore/index.js.map +1 -0
- package/lib/commonjs/logic/keyValueStore/resolveKvsQueryIndex.d.ts +10 -0
- package/lib/commonjs/logic/keyValueStore/resolveKvsQueryIndex.js +31 -0
- package/lib/commonjs/logic/keyValueStore/resolveKvsQueryIndex.js.map +1 -0
- package/lib/commonjs/logic/scope/InvalidScopeError.d.ts +5 -1
- package/lib/commonjs/logic/scope/InvalidScopeError.js +14 -0
- package/lib/commonjs/logic/scope/InvalidScopeError.js.map +1 -1
- package/lib/commonjs/logic/scope/index.d.ts +1 -3
- package/lib/commonjs/logic/scope/index.js +1 -3
- package/lib/commonjs/logic/scope/index.js.map +1 -1
- package/lib/commonjs/logic/scope/kvsScopeGate.d.ts +8 -3
- package/lib/commonjs/logic/scope/kvsScopeGate.js +32 -35
- package/lib/commonjs/logic/scope/kvsScopeGate.js.map +1 -1
- package/lib/commonjs/logic/scope/kvsScopeRules.d.ts +61 -0
- package/lib/commonjs/logic/scope/kvsScopeRules.js +232 -0
- package/lib/commonjs/logic/scope/kvsScopeRules.js.map +1 -0
- package/lib/commonjs/logic/scope/validateScopeSegment.js +4 -4
- package/lib/commonjs/logic/scope/validateScopeSegment.js.map +1 -1
- package/lib/esm/actions/keyValueStore/askKeyValueStoreQuery.d.ts +2 -1
- package/lib/esm/actions/keyValueStore/askKeyValueStoreQuery.js +1 -0
- package/lib/esm/actions/keyValueStore/askKeyValueStoreQuery.js.map +1 -1
- package/lib/esm/config/settings/keyValueStore.d.ts +2 -0
- package/lib/esm/config/settings/keyValueStore.js +32 -16
- package/lib/esm/config/settings/keyValueStore.js.map +1 -1
- package/lib/esm/logic/index.d.ts +1 -0
- package/lib/esm/logic/index.js +1 -0
- package/lib/esm/logic/index.js.map +1 -1
- package/lib/esm/logic/keyValueStore/KvsIndexNotFoundError.d.ts +5 -0
- package/lib/esm/logic/keyValueStore/KvsIndexNotFoundError.js +9 -0
- package/lib/esm/logic/keyValueStore/KvsIndexNotFoundError.js.map +1 -0
- package/lib/esm/logic/keyValueStore/flattenKvsQueryConditions.d.ts +3 -0
- package/lib/esm/logic/keyValueStore/flattenKvsQueryConditions.js +11 -0
- package/lib/esm/logic/keyValueStore/flattenKvsQueryConditions.js.map +1 -0
- package/lib/esm/logic/keyValueStore/index.d.ts +3 -0
- package/lib/esm/logic/keyValueStore/index.js +4 -0
- package/lib/esm/logic/keyValueStore/index.js.map +1 -0
- package/lib/esm/logic/keyValueStore/resolveKvsQueryIndex.d.ts +10 -0
- package/lib/esm/logic/keyValueStore/resolveKvsQueryIndex.js +26 -0
- package/lib/esm/logic/keyValueStore/resolveKvsQueryIndex.js.map +1 -0
- package/lib/esm/logic/scope/InvalidScopeError.d.ts +5 -1
- package/lib/esm/logic/scope/InvalidScopeError.js +14 -0
- package/lib/esm/logic/scope/InvalidScopeError.js.map +1 -1
- package/lib/esm/logic/scope/index.d.ts +1 -3
- package/lib/esm/logic/scope/index.js +1 -3
- package/lib/esm/logic/scope/index.js.map +1 -1
- package/lib/esm/logic/scope/kvsScopeGate.d.ts +8 -3
- package/lib/esm/logic/scope/kvsScopeGate.js +28 -32
- package/lib/esm/logic/scope/kvsScopeGate.js.map +1 -1
- package/lib/esm/logic/scope/kvsScopeRules.d.ts +61 -0
- package/lib/esm/logic/scope/kvsScopeRules.js +220 -0
- package/lib/esm/logic/scope/kvsScopeRules.js.map +1 -0
- package/lib/esm/logic/scope/validateScopeSegment.js +4 -4
- package/lib/esm/logic/scope/validateScopeSegment.js.map +1 -1
- package/package.json +2 -2
- package/lib/commonjs/logic/scope/scopedKvsQueryOperation.d.ts +0 -42
- package/lib/commonjs/logic/scope/scopedKvsQueryOperation.js +0 -128
- package/lib/commonjs/logic/scope/scopedKvsQueryOperation.js.map +0 -1
- package/lib/commonjs/logic/scope/scopedKvsTranslator.d.ts +0 -32
- package/lib/commonjs/logic/scope/scopedKvsTranslator.js +0 -60
- package/lib/commonjs/logic/scope/scopedKvsTranslator.js.map +0 -1
- package/lib/commonjs/logic/scope/scopedKvsValue.d.ts +0 -12
- package/lib/commonjs/logic/scope/scopedKvsValue.js +0 -101
- package/lib/commonjs/logic/scope/scopedKvsValue.js.map +0 -1
- package/lib/esm/logic/scope/scopedKvsQueryOperation.d.ts +0 -42
- package/lib/esm/logic/scope/scopedKvsQueryOperation.js +0 -125
- package/lib/esm/logic/scope/scopedKvsQueryOperation.js.map +0 -1
- package/lib/esm/logic/scope/scopedKvsTranslator.d.ts +0 -32
- package/lib/esm/logic/scope/scopedKvsTranslator.js +0 -62
- package/lib/esm/logic/scope/scopedKvsTranslator.js.map +0 -1
- package/lib/esm/logic/scope/scopedKvsValue.d.ts +0 -12
- package/lib/esm/logic/scope/scopedKvsValue.js +0 -91
- package/lib/esm/logic/scope/scopedKvsValue.js.map +0 -1
|
@@ -9,11 +9,12 @@ export type KeyValueStoreQueryOptions = {
|
|
|
9
9
|
nextPageKey?: string;
|
|
10
10
|
filter?: KvsQueryOperation;
|
|
11
11
|
scope?: string;
|
|
12
|
+
indexName?: string;
|
|
12
13
|
consistentRead?: boolean;
|
|
13
14
|
};
|
|
14
15
|
export declare const askKeyValueStoreQueryBase: import("../..").ActionRequesterFunction<KeyValueStoreActionType.Query, [keyValueStoreName: string, keyCondition: KvsQueryOperation, options?: KeyValueStoreQueryOptions | undefined], {
|
|
15
16
|
keyValueStoreName: string;
|
|
16
17
|
keyCondition: KvsQueryOperation;
|
|
17
18
|
options: KeyValueStoreQueryOptions | undefined;
|
|
18
|
-
}, QpqPagedData<unknown>, "ResourceNotFound" | "ServiceUnavailable" | "InvalidScope" | "StoreNotFound">;
|
|
19
|
+
}, QpqPagedData<unknown>, "ResourceNotFound" | "ServiceUnavailable" | "InvalidScope" | "StoreNotFound" | "IndexNotFound">;
|
|
19
20
|
export declare function askKeyValueStoreQuery<KvsItem>(keyValueStoreName: string, keyCondition: KvsQueryOperation, options?: KeyValueStoreQueryOptions): AskResponse<QpqPagedData<KvsItem>>;
|
|
@@ -11,6 +11,7 @@ exports.askKeyValueStoreQueryBase = (0, createActionRequester_1.createActionRequ
|
|
|
11
11
|
'ResourceNotFound', // the underlying table does not exist
|
|
12
12
|
'InvalidScope', // scope is malformed or the store's partition key is not string-typed
|
|
13
13
|
'StoreNotFound', // the store is not declared in the qpq config (misconfiguration)
|
|
14
|
+
'IndexNotFound', // `indexName` names an index the store doesn't declare (misconfiguration)
|
|
14
15
|
],
|
|
15
16
|
getPayload: (keyValueStoreName, keyCondition, options) => ({
|
|
16
17
|
keyValueStoreName,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"askKeyValueStoreQuery.js","sourceRoot":"","sources":["../../../../src/actions/keyValueStore/askKeyValueStoreQuery.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"askKeyValueStoreQuery.js","sourceRoot":"","sources":["../../../../src/actions/keyValueStore/askKeyValueStoreQuery.ts"],"names":[],"mappings":";;;AAmDA,sDAOC;AAxDD,mFAAgF;AAChF,uEAAoE;AA8BvD,QAAA,yBAAyB,GAAG,IAAA,6CAAqB,GAAyB,CAAC;IACtF,UAAU,EAAE,iDAAuB,CAAC,KAAK;IACzC,UAAU,EAAE;QACV,oBAAoB,EAAE,uCAAuC;QAC7D,kBAAkB,EAAE,sCAAsC;QAC1D,cAAc,EAAE,sEAAsE;QACtF,eAAe,EAAE,iEAAiE;QAClF,eAAe,EAAE,0EAA0E;KAC5F;IACD,UAAU,EAAE,CAAC,iBAAyB,EAAE,YAA+B,EAAE,OAAmC,EAAE,EAAE,CAAC,CAAC;QAChH,iBAAiB;QACjB,YAAY;QACZ,OAAO;KACR,CAAC;CACH,CAAC,CAAC;AAEH,uFAAuF;AACvF,6DAA6D;AAC7D,QAAe,CAAC,CAAC,qBAAqB,CACpC,iBAAyB,EAEzB,YAA+B,EAC/B,OAAmC;IAEnC,OAAO,CAAC,KAAK,CAAC,CAAC,IAAA,iCAAyB,EAAC,iBAAiB,EAAE,YAAY,EAAE,OAAO,CAAC,CAA0B,CAAC;AAC/G,CAAC","sourcesContent":["import { QpqPagedData } from '../../types/QpqPagedData';\nimport { AskResponse } from '../../types/StorySession';\nimport { createActionRequester } from '../../types/utils/createActionRequester';\nimport { KeyValueStoreActionType } from './KeyValueStoreActionType';\nimport { KvsQueryOperation } from './types';\n\nexport type KeyValueStoreQueryOptions = {\n // Accepted but not implemented: no processor applies a TTL to query results.\n ttlInSeconds?: number;\n sortAscending?: boolean;\n limit?: number;\n nextPageKey?: string;\n filter?: KvsQueryOperation;\n // Composed into partition-key conditions by the processor; requires a string-typed partition key.\n scope?: string;\n // Query the declared index with this name (which defaults to its partition key attribute) and read in\n // its sort order. Without it the table, or else the first index, whose keys cover the key condition\n // serves it, so an index sharing the table's keys is only used when named here.\n indexName?: string;\n // Read the writer's own most recent writes, at the cost of a slower and (on DynamoDB) doubly-charged\n // read.\n //\n // Default reads are EVENTUALLY consistent, which is right for a viewer and wrong for a caller that just\n // wrote and is now reading back to decide something. That case is not hypothetical: a flow run appends\n // its terminal event and immediately re-lists the log to fold the outcome, and under load the terminal\n // event is intermittently not yet visible — so a run that succeeded reads back as having no outcome at\n // all, with nothing recorded to explain it.\n //\n // Use it for read-your-own-writes and for any fold used as a COORDINATION primitive (deciding \"am I\n // last\", \"did this finish\"). Do not use it for ordinary reads.\n consistentRead?: boolean;\n};\n\nexport const askKeyValueStoreQueryBase = createActionRequester<QpqPagedData<unknown>>()({\n actionType: KeyValueStoreActionType.Query,\n errorTypes: [\n 'ServiceUnavailable', // DynamoDB internal error / throttling\n 'ResourceNotFound', // the underlying table does not exist\n 'InvalidScope', // scope is malformed or the store's partition key is not string-typed\n 'StoreNotFound', // the store is not declared in the qpq config (misconfiguration)\n 'IndexNotFound', // `indexName` names an index the store doesn't declare (misconfiguration)\n ],\n getPayload: (keyValueStoreName: string, keyCondition: KvsQueryOperation, options?: KeyValueStoreQueryOptions) => ({\n keyValueStoreName,\n keyCondition,\n options,\n }),\n});\n\n// The stored item shape is only known to the caller, so the base returns unknown items\n// and this story casts the page to what the caller declared.\nexport function* askKeyValueStoreQuery<KvsItem>(\n keyValueStoreName: string,\n\n keyCondition: KvsQueryOperation,\n options?: KeyValueStoreQueryOptions,\n): AskResponse<QpqPagedData<KvsItem>> {\n return (yield* askKeyValueStoreQueryBase(keyValueStoreName, keyCondition, options)) as QpqPagedData<KvsItem>;\n}\n"]}
|
|
@@ -6,12 +6,14 @@ export type KvsKey<T extends object = any> = {
|
|
|
6
6
|
type: KvsKeyType;
|
|
7
7
|
};
|
|
8
8
|
export type KvsIndex<T extends object = any> = {
|
|
9
|
+
name: string;
|
|
9
10
|
partitionKey: KvsKey<T>;
|
|
10
11
|
sortKey?: KvsKey<T>;
|
|
11
12
|
};
|
|
12
13
|
export declare const kvsKey: <T extends object = any>(key: KeyOf<T>, type?: KvsKeyType) => KvsKey<T>;
|
|
13
14
|
type CompositeKvsKey<T extends object = any> = KvsKey<T> | KeyOf<T>;
|
|
14
15
|
type CompositeCompositeKvsIndex<T extends object = any> = {
|
|
16
|
+
name?: string;
|
|
15
17
|
partitionKey: CompositeKvsKey<T>;
|
|
16
18
|
sortKey?: CompositeKvsKey<T>;
|
|
17
19
|
};
|
|
@@ -19,25 +19,40 @@ const isCompositeKvsIndexACompositeCompositeKvsIndex = (compositeKvsIndex) => {
|
|
|
19
19
|
return typeof compositeKvsIndex !== 'string';
|
|
20
20
|
};
|
|
21
21
|
const convertCompositeKvsIndexToKvsIndex = (compositeKvsIndex) => {
|
|
22
|
+
var _a;
|
|
22
23
|
if (!isCompositeKvsIndexACompositeCompositeKvsIndex(compositeKvsIndex)) {
|
|
23
24
|
return {
|
|
25
|
+
name: compositeKvsIndex,
|
|
24
26
|
partitionKey: (0, exports.kvsKey)(compositeKvsIndex, 'string'),
|
|
25
27
|
};
|
|
26
28
|
}
|
|
29
|
+
const partitionKey = convertCompositeKvsKeyToKvsKey(compositeKvsIndex.partitionKey);
|
|
27
30
|
return {
|
|
28
|
-
|
|
31
|
+
name: (_a = compositeKvsIndex.name) !== null && _a !== void 0 ? _a : partitionKey.key,
|
|
32
|
+
partitionKey,
|
|
29
33
|
sortKey: compositeKvsIndex.sortKey ? convertCompositeKvsKeyToKvsKey(compositeKvsIndex.sortKey) : undefined,
|
|
30
34
|
};
|
|
31
35
|
};
|
|
32
36
|
const defineKeyValueStore = (keyValueStoreName, partitionKey, sortKeys = [], options) => {
|
|
33
37
|
var _a, _b, _c, _d;
|
|
34
|
-
|
|
38
|
+
const tablePartitionKey = convertCompositeKvsKeyToKvsKey(partitionKey);
|
|
39
|
+
const indexes = ((_a = options === null || options === void 0 ? void 0 : options.indexes) !== null && _a !== void 0 ? _a : []).map((convertCompositeKvsIndexToKvsIndex));
|
|
40
|
+
const duplicateIndexName = indexes.find((index, position) => indexes.findIndex((other) => other.name === index.name) !== position);
|
|
41
|
+
if (duplicateIndexName) {
|
|
42
|
+
throw new Error(`Key value store '${keyValueStoreName}' declares two indexes named '${duplicateIndexName.name}'; give one an explicit name`);
|
|
43
|
+
}
|
|
44
|
+
// A scoped store's indexes are partitioned per scope, which every backend can do
|
|
45
|
+
// for a string or number key but not a binary one.
|
|
46
|
+
if ((options === null || options === void 0 ? void 0 : options.scoped) && indexes.some((index) => index.partitionKey.type === 'binary' && index.partitionKey.key !== tablePartitionKey.key)) {
|
|
47
|
+
throw new Error(`Key value store '${keyValueStoreName}' is scoped, so its index partition keys must be strings or numbers`);
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
35
50
|
configSettingType: QPQConfig_1.QPQCoreConfigSettingType.keyValueStore,
|
|
36
51
|
uniqueKey: keyValueStoreName,
|
|
37
52
|
keyValueStoreName,
|
|
38
|
-
partitionKey:
|
|
53
|
+
partitionKey: tablePartitionKey,
|
|
39
54
|
sortKeys: sortKeys.map((convertCompositeKvsKeyToKvsKey)),
|
|
40
|
-
indexes
|
|
55
|
+
indexes,
|
|
41
56
|
global: (_b = options === null || options === void 0 ? void 0 : options.global) !== null && _b !== void 0 ? _b : false,
|
|
42
57
|
owner: options === null || options === void 0 ? void 0 : options.owner,
|
|
43
58
|
ttlAttribute: options === null || options === void 0 ? void 0 : options.ttlAttribute,
|
|
@@ -45,7 +60,7 @@ const defineKeyValueStore = (keyValueStoreName, partitionKey, sortKeys = [], opt
|
|
|
45
60
|
cryptoKeyName: options === null || options === void 0 ? void 0 : options.cryptoKeyName,
|
|
46
61
|
scoped: (_d = options === null || options === void 0 ? void 0 : options.scoped) !== null && _d !== void 0 ? _d : false,
|
|
47
62
|
onStream: options === null || options === void 0 ? void 0 : options.onStream,
|
|
48
|
-
}
|
|
63
|
+
};
|
|
49
64
|
};
|
|
50
65
|
exports.defineKeyValueStore = defineKeyValueStore;
|
|
51
66
|
//# sourceMappingURL=keyValueStore.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keyValueStore.js","sourceRoot":"","sources":["../../../../src/config/settings/keyValueStore.ts"],"names":[],"mappings":";;;AACA,4CAAqG;AAmB9F,MAAM,MAAM,GAAG,CAAyB,GAAa,EAAE,OAAmB,QAAQ,EAAa,EAAE,CAAC,CAAC;IACxG,GAAG;IACH,IAAI;CACL,CAAC,CAAC;AAHU,QAAA,MAAM,UAGhB;AAWH,MAAM,8BAA8B,GAAG,CAAyB,eAAmC,EAAa,EAAE;IAChH,oBAAoB;IACpB,IAAI,OAAO,eAAe,KAAK,QAAQ,EAAE,CAAC;QACxC,OAAO,IAAA,cAAM,EAAI,eAA2B,EAAE,QAAQ,CAAC,CAAC;IAC1D,CAAC;IAED,sBAAsB;IACtB,OAAO,eAA4B,CAAC;AACtC,CAAC,CAAC;AAEF,MAAM,8CAA8C,GAAG,CACrD,iBAAuC,EACa,EAAE;IACtD,OAAO,OAAO,iBAAiB,KAAK,QAAQ,CAAC;AAC/C,CAAC,CAAC;AAEF,MAAM,kCAAkC,GAAG,CAAyB,iBAAuC,EAAe,EAAE;IAC1H,IAAI,CAAC,8CAA8C,CAAI,iBAAiB,CAAC,EAAE,CAAC;QAC1E,OAAO;YACL,YAAY,EAAE,IAAA,cAAM,EAAI,iBAAiB,EAAE,QAAQ,CAAC;SACrD,CAAC;IACJ,CAAC;IAED,OAAO;QACL,YAAY,EAAE,8BAA8B,CAAI,iBAAiB,CAAC,YAAY,CAAC;QAC/E,OAAO,EAAE,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC,8BAA8B,CAAI,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS;KAC9G,CAAC;AACJ,CAAC,CAAC;AAuFK,MAAM,mBAAmB,GAAG,CACjC,iBAAyB,EAEzB,YAAgC,EAChC,WAAiC,EAAE,EAEnC,OAAmD,EACjB,EAAE;;IAAC,OAAA,CAAC;QACtC,iBAAiB,EAAE,oCAAwB,CAAC,aAAa;QACzD,SAAS,EAAE,iBAAiB;QAE5B,iBAAiB;QAEjB,YAAY,EAAE,8BAA8B,CAAI,YAAY,CAAC;QAC7D,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAA,8BAAiC,CAAA,CAAC;QAEzD,OAAO,EAAE,CAAC,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,OAAO,mCAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAA,kCAAqC,CAAA,CAAC;QAE5E,MAAM,EAAE,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,MAAM,mCAAI,KAAK;QAEhC,KAAK,EAAE,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,KAAK;QAErB,YAAY,EAAE,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,YAAY;QAEnC,0BAA0B,EAAE,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,0BAA0B,mCAAI,KAAK;QAExE,aAAa,EAAE,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,aAAa;QACrC,MAAM,EAAE,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,MAAM,mCAAI,KAAK;QAEhC,QAAQ,EAAE,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,QAAQ;KAC5B,CAAC,CAAA;CAAA,CAAC;AA9BU,QAAA,mBAAmB,uBA8B7B","sourcesContent":["import { CrossModuleOwner, KeyOf, QpqFunctionRuntime } from '../../types';\nimport { QPQConfigAdvancedSettings, QPQConfigSetting, QPQCoreConfigSettingType } from '../QPQConfig';\n\n// TODO: When we put validation on the QPQConfig, we need to make sure\n// Key Length and Data Type: DynamoDB has limitations on key length and data type.\n// Your KvsKeyType only supports 'string', 'number', and 'binary' types. Make sure\n// that you're validating these in convertKvsKeyToDynamodbAttribute function and\n// also ensure that key length is within DynamoDB's specified limits.\n\nexport type KvsKeyType = 'string' | 'number' | 'binary';\nexport type KvsKey<T extends object = any> = {\n key: KeyOf<T>;\n type: KvsKeyType;\n};\n\nexport type KvsIndex<T extends object = any> = {\n partitionKey: KvsKey<T>;\n sortKey?: KvsKey<T>;\n};\n\nexport const kvsKey = <T extends object = any>(key: KeyOf<T>, type: KvsKeyType = 'string'): KvsKey<T> => ({\n key,\n type,\n});\n\ntype CompositeKvsKey<T extends object = any> = KvsKey<T> | KeyOf<T>;\n\ntype CompositeCompositeKvsIndex<T extends object = any> = {\n partitionKey: CompositeKvsKey<T>;\n sortKey?: CompositeKvsKey<T>;\n};\n\nexport type CompositeKvsIndex<T extends object = any> = KeyOf<T> | CompositeCompositeKvsIndex<T>;\n\nconst convertCompositeKvsKeyToKvsKey = <T extends object = any>(compositeKvsKey: CompositeKvsKey<T>): KvsKey<T> => {\n // Must be a keyof T\n if (typeof compositeKvsKey === 'string') {\n return kvsKey<T>(compositeKvsKey as KeyOf<T>, 'string');\n }\n\n // must be a KvsKey<T>\n return compositeKvsKey as KvsKey<T>;\n};\n\nconst isCompositeKvsIndexACompositeCompositeKvsIndex = <T extends object = any>(\n compositeKvsIndex: CompositeKvsIndex<T>,\n): compositeKvsIndex is CompositeCompositeKvsIndex<T> => {\n return typeof compositeKvsIndex !== 'string';\n};\n\nconst convertCompositeKvsIndexToKvsIndex = <T extends object = any>(compositeKvsIndex: CompositeKvsIndex<T>): KvsIndex<T> => {\n if (!isCompositeKvsIndexACompositeCompositeKvsIndex<T>(compositeKvsIndex)) {\n return {\n partitionKey: kvsKey<T>(compositeKvsIndex, 'string'),\n };\n }\n\n return {\n partitionKey: convertCompositeKvsKeyToKvsKey<T>(compositeKvsIndex.partitionKey),\n sortKey: compositeKvsIndex.sortKey ? convertCompositeKvsKeyToKvsKey<T>(compositeKvsIndex.sortKey) : undefined,\n };\n};\n\n/**\n * Change data capture on a store: the table gets a stream (NEW_AND_OLD_IMAGES) and\n * `runtime` is invoked with the changes.\n *\n * Records arrive in order PER PARTITION KEY, and different partition keys are processed\n * concurrently. A stream handler therefore gets one-writer-per-item serialisation for\n * free, which is what makes a stream the natural place to maintain a projection of a table\n * you only ever append to — no queue, no extra write on the append path, and no trigger to\n * lose, because the record exists precisely because the write happened.\n *\n * Mirrors defineStorageDrive's `onEvent`.\n */\nexport type KvsStreamSettings = {\n runtime: QpqFunctionRuntime;\n\n /**\n * Collapse each delivered batch down to ONE record per partition key, keeping the latest.\n *\n * Off by default: a generic consumer (audit trail, change notifications) needs to see\n * every change, and the framework should never silently drop records.\n *\n * On for a PROJECTION, where the payload that matters is \"this key changed\" and the\n * handler re-derives from source anyway. Without it, the batch is fanned back out into\n * one story run per record and the batching bought nothing: 500 appends to one document\n * would mean 500 re-derivations, each reading a log that grows as it goes. With it, that\n * batch is a single re-derivation.\n */\n coalesceByPartitionKey?: boolean;\n\n /** Records per invocation. DynamoDB streams allow up to 1000; the mapping default is 100. */\n batchSize?: number;\n\n /**\n * How long to wait accumulating records before invoking, 0 to 300 seconds. Trades\n * projection latency for far fewer invocations, and gives coalescing more to collapse.\n */\n maximumBatchingWindowInSeconds?: number;\n};\n\nexport interface QPQConfigAdvancedKeyValueStoreSettings<T extends object = any> extends QPQConfigAdvancedSettings {\n indexes?: CompositeKvsIndex<T>[];\n\n global?: boolean;\n\n owner?: CrossModuleOwner;\n\n ttlAttribute?: string;\n\n // Point-in-time recovery (35-day continuous backups) is on by default; set this to opt out.\n disablePointInTimeRecovery?: boolean;\n\n // Encrypt the table with the named defineCryptoKey instead of the provider's own managed\n // encryption, which always applies. The key must be declared in the same config, owned or\n // foreign; a foreign key's owning service must be deployed first.\n cryptoKeyName?: string;\n\n // Every action on this store must carry a scope; an unscoped call is refused rather\n // than hitting the unpartitioned rows. askKeyValueStoreScanAllScopes is exempt.\n scoped?: boolean;\n\n // Turn on change data capture — see KvsStreamSettings. Absent means no stream is\n // created at all.\n onStream?: KvsStreamSettings;\n}\n\nexport interface KeyValueStoreQPQConfigSetting<T extends object = any> extends QPQConfigSetting {\n keyValueStoreName: string;\n\n partitionKey: KvsKey<T>;\n sortKeys: KvsKey<T>[];\n\n indexes: KvsIndex<T>[];\n\n global: boolean;\n\n ttlAttribute?: string;\n\n disablePointInTimeRecovery: boolean;\n\n cryptoKeyName?: string;\n scoped: boolean;\n\n onStream?: KvsStreamSettings;\n}\n\nexport const defineKeyValueStore = <T extends object = any>(\n keyValueStoreName: string,\n\n partitionKey: CompositeKvsKey<T>,\n sortKeys: CompositeKvsKey<T>[] = [],\n\n options?: QPQConfigAdvancedKeyValueStoreSettings<T>,\n): KeyValueStoreQPQConfigSetting<T> => ({\n configSettingType: QPQCoreConfigSettingType.keyValueStore,\n uniqueKey: keyValueStoreName,\n\n keyValueStoreName,\n\n partitionKey: convertCompositeKvsKeyToKvsKey<T>(partitionKey),\n sortKeys: sortKeys.map(convertCompositeKvsKeyToKvsKey<T>),\n\n indexes: (options?.indexes ?? []).map(convertCompositeKvsIndexToKvsIndex<T>),\n\n global: options?.global ?? false,\n\n owner: options?.owner,\n\n ttlAttribute: options?.ttlAttribute,\n\n disablePointInTimeRecovery: options?.disablePointInTimeRecovery ?? false,\n\n cryptoKeyName: options?.cryptoKeyName,\n scoped: options?.scoped ?? false,\n\n onStream: options?.onStream,\n});\n"]}
|
|
1
|
+
{"version":3,"file":"keyValueStore.js","sourceRoot":"","sources":["../../../../src/config/settings/keyValueStore.ts"],"names":[],"mappings":";;;AACA,4CAAqG;AAqB9F,MAAM,MAAM,GAAG,CAAyB,GAAa,EAAE,OAAmB,QAAQ,EAAa,EAAE,CAAC,CAAC;IACxG,GAAG;IACH,IAAI;CACL,CAAC,CAAC;AAHU,QAAA,MAAM,UAGhB;AAaH,MAAM,8BAA8B,GAAG,CAAyB,eAAmC,EAAa,EAAE;IAChH,oBAAoB;IACpB,IAAI,OAAO,eAAe,KAAK,QAAQ,EAAE,CAAC;QACxC,OAAO,IAAA,cAAM,EAAI,eAA2B,EAAE,QAAQ,CAAC,CAAC;IAC1D,CAAC;IAED,sBAAsB;IACtB,OAAO,eAA4B,CAAC;AACtC,CAAC,CAAC;AAEF,MAAM,8CAA8C,GAAG,CACrD,iBAAuC,EACa,EAAE;IACtD,OAAO,OAAO,iBAAiB,KAAK,QAAQ,CAAC;AAC/C,CAAC,CAAC;AAEF,MAAM,kCAAkC,GAAG,CAAyB,iBAAuC,EAAe,EAAE;;IAC1H,IAAI,CAAC,8CAA8C,CAAI,iBAAiB,CAAC,EAAE,CAAC;QAC1E,OAAO;YACL,IAAI,EAAE,iBAAiB;YACvB,YAAY,EAAE,IAAA,cAAM,EAAI,iBAAiB,EAAE,QAAQ,CAAC;SACrD,CAAC;IACJ,CAAC;IAED,MAAM,YAAY,GAAG,8BAA8B,CAAI,iBAAiB,CAAC,YAAY,CAAC,CAAC;IAEvF,OAAO;QACL,IAAI,EAAE,MAAA,iBAAiB,CAAC,IAAI,mCAAI,YAAY,CAAC,GAAG;QAChD,YAAY;QACZ,OAAO,EAAE,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC,8BAA8B,CAAI,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS;KAC9G,CAAC;AACJ,CAAC,CAAC;AAuFK,MAAM,mBAAmB,GAAG,CACjC,iBAAyB,EAEzB,YAAgC,EAChC,WAAiC,EAAE,EAEnC,OAAmD,EACjB,EAAE;;IACpC,MAAM,iBAAiB,GAAG,8BAA8B,CAAI,YAAY,CAAC,CAAC;IAC1E,MAAM,OAAO,GAAG,CAAC,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,OAAO,mCAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAA,kCAAqC,CAAA,CAAC,CAAC;IAEpF,MAAM,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,CAAC,KAAK,QAAQ,CAAC,CAAC;IACnI,IAAI,kBAAkB,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,oBAAoB,iBAAiB,iCAAiC,kBAAkB,CAAC,IAAI,8BAA8B,CAAC,CAAC;IAC/I,CAAC;IAED,iFAAiF;IACjF,mDAAmD;IACnD,IAAI,CAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,MAAM,KAAI,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,YAAY,CAAC,GAAG,KAAK,iBAAiB,CAAC,GAAG,CAAC,EAAE,CAAC;QACzI,MAAM,IAAI,KAAK,CAAC,oBAAoB,iBAAiB,qEAAqE,CAAC,CAAC;IAC9H,CAAC;IAED,OAAO;QACL,iBAAiB,EAAE,oCAAwB,CAAC,aAAa;QACzD,SAAS,EAAE,iBAAiB;QAE5B,iBAAiB;QAEjB,YAAY,EAAE,iBAAiB;QAC/B,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAA,8BAAiC,CAAA,CAAC;QAEzD,OAAO;QAEP,MAAM,EAAE,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,MAAM,mCAAI,KAAK;QAEhC,KAAK,EAAE,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,KAAK;QAErB,YAAY,EAAE,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,YAAY;QAEnC,0BAA0B,EAAE,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,0BAA0B,mCAAI,KAAK;QAExE,aAAa,EAAE,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,aAAa;QACrC,MAAM,EAAE,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,MAAM,mCAAI,KAAK;QAEhC,QAAQ,EAAE,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,QAAQ;KAC5B,CAAC;AACJ,CAAC,CAAC;AA9CW,QAAA,mBAAmB,uBA8C9B","sourcesContent":["import { CrossModuleOwner, KeyOf, QpqFunctionRuntime } from '../../types';\nimport { QPQConfigAdvancedSettings, QPQConfigSetting, QPQCoreConfigSettingType } from '../QPQConfig';\n\n// TODO: When we put validation on the QPQConfig, we need to make sure\n// Key Length and Data Type: DynamoDB has limitations on key length and data type.\n// Your KvsKeyType only supports 'string', 'number', and 'binary' types. Make sure\n// that you're validating these in convertKvsKeyToDynamodbAttribute function and\n// also ensure that key length is within DynamoDB's specified limits.\n\nexport type KvsKeyType = 'string' | 'number' | 'binary';\nexport type KvsKey<T extends object = any> = {\n key: KeyOf<T>;\n type: KvsKeyType;\n};\n\nexport type KvsIndex<T extends object = any> = {\n // What the index is queried by (askKeyValueStoreQuery's `indexName` option) and deployed as.\n name: string;\n partitionKey: KvsKey<T>;\n sortKey?: KvsKey<T>;\n};\n\nexport const kvsKey = <T extends object = any>(key: KeyOf<T>, type: KvsKeyType = 'string'): KvsKey<T> => ({\n key,\n type,\n});\n\ntype CompositeKvsKey<T extends object = any> = KvsKey<T> | KeyOf<T>;\n\ntype CompositeCompositeKvsIndex<T extends object = any> = {\n // Defaults to the partition key attribute. Name an index when two share a partition key.\n name?: string;\n partitionKey: CompositeKvsKey<T>;\n sortKey?: CompositeKvsKey<T>;\n};\n\nexport type CompositeKvsIndex<T extends object = any> = KeyOf<T> | CompositeCompositeKvsIndex<T>;\n\nconst convertCompositeKvsKeyToKvsKey = <T extends object = any>(compositeKvsKey: CompositeKvsKey<T>): KvsKey<T> => {\n // Must be a keyof T\n if (typeof compositeKvsKey === 'string') {\n return kvsKey<T>(compositeKvsKey as KeyOf<T>, 'string');\n }\n\n // must be a KvsKey<T>\n return compositeKvsKey as KvsKey<T>;\n};\n\nconst isCompositeKvsIndexACompositeCompositeKvsIndex = <T extends object = any>(\n compositeKvsIndex: CompositeKvsIndex<T>,\n): compositeKvsIndex is CompositeCompositeKvsIndex<T> => {\n return typeof compositeKvsIndex !== 'string';\n};\n\nconst convertCompositeKvsIndexToKvsIndex = <T extends object = any>(compositeKvsIndex: CompositeKvsIndex<T>): KvsIndex<T> => {\n if (!isCompositeKvsIndexACompositeCompositeKvsIndex<T>(compositeKvsIndex)) {\n return {\n name: compositeKvsIndex,\n partitionKey: kvsKey<T>(compositeKvsIndex, 'string'),\n };\n }\n\n const partitionKey = convertCompositeKvsKeyToKvsKey<T>(compositeKvsIndex.partitionKey);\n\n return {\n name: compositeKvsIndex.name ?? partitionKey.key,\n partitionKey,\n sortKey: compositeKvsIndex.sortKey ? convertCompositeKvsKeyToKvsKey<T>(compositeKvsIndex.sortKey) : undefined,\n };\n};\n\n/**\n * Change data capture on a store: the table gets a stream (NEW_AND_OLD_IMAGES) and\n * `runtime` is invoked with the changes.\n *\n * Records arrive in order PER PARTITION KEY, and different partition keys are processed\n * concurrently. A stream handler therefore gets one-writer-per-item serialisation for\n * free, which is what makes a stream the natural place to maintain a projection of a table\n * you only ever append to — no queue, no extra write on the append path, and no trigger to\n * lose, because the record exists precisely because the write happened.\n *\n * Mirrors defineStorageDrive's `onEvent`.\n */\nexport type KvsStreamSettings = {\n runtime: QpqFunctionRuntime;\n\n /**\n * Collapse each delivered batch down to ONE record per partition key, keeping the latest.\n *\n * Off by default: a generic consumer (audit trail, change notifications) needs to see\n * every change, and the framework should never silently drop records.\n *\n * On for a PROJECTION, where the payload that matters is \"this key changed\" and the\n * handler re-derives from source anyway. Without it, the batch is fanned back out into\n * one story run per record and the batching bought nothing: 500 appends to one document\n * would mean 500 re-derivations, each reading a log that grows as it goes. With it, that\n * batch is a single re-derivation.\n */\n coalesceByPartitionKey?: boolean;\n\n /** Records per invocation. DynamoDB streams allow up to 1000; the mapping default is 100. */\n batchSize?: number;\n\n /**\n * How long to wait accumulating records before invoking, 0 to 300 seconds. Trades\n * projection latency for far fewer invocations, and gives coalescing more to collapse.\n */\n maximumBatchingWindowInSeconds?: number;\n};\n\nexport interface QPQConfigAdvancedKeyValueStoreSettings<T extends object = any> extends QPQConfigAdvancedSettings {\n indexes?: CompositeKvsIndex<T>[];\n\n global?: boolean;\n\n owner?: CrossModuleOwner;\n\n ttlAttribute?: string;\n\n // Point-in-time recovery (35-day continuous backups) is on by default; set this to opt out.\n disablePointInTimeRecovery?: boolean;\n\n // Encrypt the table with the named defineCryptoKey instead of the provider's own managed\n // encryption, which always applies. The key must be declared in the same config, owned or\n // foreign; a foreign key's owning service must be deployed first.\n cryptoKeyName?: string;\n\n // Every action on this store must carry a scope; an unscoped call is refused rather\n // than hitting the unpartitioned rows. askKeyValueStoreScanAllScopes is exempt.\n scoped?: boolean;\n\n // Turn on change data capture — see KvsStreamSettings. Absent means no stream is\n // created at all.\n onStream?: KvsStreamSettings;\n}\n\nexport interface KeyValueStoreQPQConfigSetting<T extends object = any> extends QPQConfigSetting {\n keyValueStoreName: string;\n\n partitionKey: KvsKey<T>;\n sortKeys: KvsKey<T>[];\n\n indexes: KvsIndex<T>[];\n\n global: boolean;\n\n ttlAttribute?: string;\n\n disablePointInTimeRecovery: boolean;\n\n cryptoKeyName?: string;\n scoped: boolean;\n\n onStream?: KvsStreamSettings;\n}\n\nexport const defineKeyValueStore = <T extends object = any>(\n keyValueStoreName: string,\n\n partitionKey: CompositeKvsKey<T>,\n sortKeys: CompositeKvsKey<T>[] = [],\n\n options?: QPQConfigAdvancedKeyValueStoreSettings<T>,\n): KeyValueStoreQPQConfigSetting<T> => {\n const tablePartitionKey = convertCompositeKvsKeyToKvsKey<T>(partitionKey);\n const indexes = (options?.indexes ?? []).map(convertCompositeKvsIndexToKvsIndex<T>);\n\n const duplicateIndexName = indexes.find((index, position) => indexes.findIndex((other) => other.name === index.name) !== position);\n if (duplicateIndexName) {\n throw new Error(`Key value store '${keyValueStoreName}' declares two indexes named '${duplicateIndexName.name}'; give one an explicit name`);\n }\n\n // A scoped store's indexes are partitioned per scope, which every backend can do\n // for a string or number key but not a binary one.\n if (options?.scoped && indexes.some((index) => index.partitionKey.type === 'binary' && index.partitionKey.key !== tablePartitionKey.key)) {\n throw new Error(`Key value store '${keyValueStoreName}' is scoped, so its index partition keys must be strings or numbers`);\n }\n\n return {\n configSettingType: QPQCoreConfigSettingType.keyValueStore,\n uniqueKey: keyValueStoreName,\n\n keyValueStoreName,\n\n partitionKey: tablePartitionKey,\n sortKeys: sortKeys.map(convertCompositeKvsKeyToKvsKey<T>),\n\n indexes,\n\n global: options?.global ?? false,\n\n owner: options?.owner,\n\n ttlAttribute: options?.ttlAttribute,\n\n disablePointInTimeRecovery: options?.disablePointInTimeRecovery ?? false,\n\n cryptoKeyName: options?.cryptoKeyName,\n scoped: options?.scoped ?? false,\n\n onStream: options?.onStream,\n };\n};\n"]}
|
|
@@ -18,6 +18,7 @@ __exportStar(require("./actionValidators"), exports);
|
|
|
18
18
|
__exportStar(require("./context"), exports);
|
|
19
19
|
__exportStar(require("./decomposedString"), exports);
|
|
20
20
|
__exportStar(require("./error"), exports);
|
|
21
|
+
__exportStar(require("./keyValueStore"), exports);
|
|
21
22
|
__exportStar(require("./logHistory"), exports);
|
|
22
23
|
__exportStar(require("./lookup"), exports);
|
|
23
24
|
__exportStar(require("./scope"), exports);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/logic/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,qDAAmC;AACnC,4CAA0B;AAC1B,qDAAmC;AACnC,0CAAwB;AACxB,+CAA6B;AAC7B,2CAAyB;AACzB,0CAAwB;AACxB,iDAA+B;AAC/B,2CAAyB;AACzB,wDAAsC","sourcesContent":["export * from './actionValidators';\nexport * from './context';\nexport * from './decomposedString';\nexport * from './error';\nexport * from './logHistory';\nexport * from './lookup';\nexport * from './scope';\nexport * from './stateEffects';\nexport * from './stream';\nexport * from './transientErrorNames';\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/logic/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,qDAAmC;AACnC,4CAA0B;AAC1B,qDAAmC;AACnC,0CAAwB;AACxB,kDAAgC;AAChC,+CAA6B;AAC7B,2CAAyB;AACzB,0CAAwB;AACxB,iDAA+B;AAC/B,2CAAyB;AACzB,wDAAsC","sourcesContent":["export * from './actionValidators';\nexport * from './context';\nexport * from './decomposedString';\nexport * from './error';\nexport * from './keyValueStore';\nexport * from './logHistory';\nexport * from './lookup';\nexport * from './scope';\nexport * from './stateEffects';\nexport * from './stream';\nexport * from './transientErrorNames';\n"]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** A query named an index its store doesn't declare. Query processors map it to the action's IndexNotFound. */
|
|
2
|
+
export declare class KvsIndexNotFoundError extends Error {
|
|
3
|
+
readonly code = "KvsIndexNotFoundError";
|
|
4
|
+
constructor(keyValueStoreName: string, indexName: string);
|
|
5
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.KvsIndexNotFoundError = void 0;
|
|
4
|
+
/** A query named an index its store doesn't declare. Query processors map it to the action's IndexNotFound. */
|
|
5
|
+
class KvsIndexNotFoundError extends Error {
|
|
6
|
+
constructor(keyValueStoreName, indexName) {
|
|
7
|
+
super(`Key value store '${keyValueStoreName}' has no index named '${indexName}'`);
|
|
8
|
+
this.code = 'KvsIndexNotFoundError';
|
|
9
|
+
this.name = 'KvsIndexNotFoundError';
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
exports.KvsIndexNotFoundError = KvsIndexNotFoundError;
|
|
13
|
+
//# sourceMappingURL=KvsIndexNotFoundError.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"KvsIndexNotFoundError.js","sourceRoot":"","sources":["../../../../src/logic/keyValueStore/KvsIndexNotFoundError.ts"],"names":[],"mappings":";;;AAAA,+GAA+G;AAC/G,MAAa,qBAAsB,SAAQ,KAAK;IAG9C,YAAY,iBAAyB,EAAE,SAAiB;QACtD,KAAK,CAAC,oBAAoB,iBAAiB,yBAAyB,SAAS,GAAG,CAAC,CAAC;QAH3E,SAAI,GAAG,uBAAuB,CAAC;QAItC,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;IACtC,CAAC;CACF;AAPD,sDAOC","sourcesContent":["/** A query named an index its store doesn't declare. Query processors map it to the action's IndexNotFound. */\nexport class KvsIndexNotFoundError extends Error {\n readonly code = 'KvsIndexNotFoundError';\n\n constructor(keyValueStoreName: string, indexName: string) {\n super(`Key value store '${keyValueStoreName}' has no index named '${indexName}'`);\n this.name = 'KvsIndexNotFoundError';\n }\n}\n"]}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { KvsQueryCondition, KvsQueryOperation } from '../../actions/keyValueStore/types';
|
|
2
|
+
/** Flatten a query tree into its leaf conditions, in traversal order. Malformed nodes are dropped. */
|
|
3
|
+
export declare const flattenKvsQueryConditions: (operation: KvsQueryOperation) => KvsQueryCondition[];
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.flattenKvsQueryConditions = void 0;
|
|
4
|
+
/** Flatten a query tree into its leaf conditions, in traversal order. Malformed nodes are dropped. */
|
|
5
|
+
const flattenKvsQueryConditions = (operation) => {
|
|
6
|
+
if ('key' in operation && 'operation' in operation) {
|
|
7
|
+
return [operation];
|
|
8
|
+
}
|
|
9
|
+
if ('conditions' in operation && 'operation' in operation) {
|
|
10
|
+
return operation.conditions.flatMap(exports.flattenKvsQueryConditions);
|
|
11
|
+
}
|
|
12
|
+
return [];
|
|
13
|
+
};
|
|
14
|
+
exports.flattenKvsQueryConditions = flattenKvsQueryConditions;
|
|
15
|
+
//# sourceMappingURL=flattenKvsQueryConditions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flattenKvsQueryConditions.js","sourceRoot":"","sources":["../../../../src/logic/keyValueStore/flattenKvsQueryConditions.ts"],"names":[],"mappings":";;;AAEA,sGAAsG;AAC/F,MAAM,yBAAyB,GAAG,CAAC,SAA4B,EAAuB,EAAE;IAC7F,IAAI,KAAK,IAAI,SAAS,IAAI,WAAW,IAAI,SAAS,EAAE,CAAC;QACnD,OAAO,CAAC,SAAS,CAAC,CAAC;IACrB,CAAC;IAED,IAAI,YAAY,IAAI,SAAS,IAAI,WAAW,IAAI,SAAS,EAAE,CAAC;QAC1D,OAAO,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,iCAAyB,CAAC,CAAC;IACjE,CAAC;IAED,OAAO,EAAE,CAAC;AACZ,CAAC,CAAC;AAVW,QAAA,yBAAyB,6BAUpC","sourcesContent":["import { KvsQueryCondition, KvsQueryOperation } from '../../actions/keyValueStore/types';\n\n/** Flatten a query tree into its leaf conditions, in traversal order. Malformed nodes are dropped. */\nexport const flattenKvsQueryConditions = (operation: KvsQueryOperation): KvsQueryCondition[] => {\n if ('key' in operation && 'operation' in operation) {\n return [operation];\n }\n\n if ('conditions' in operation && 'operation' in operation) {\n return operation.conditions.flatMap(flattenKvsQueryConditions);\n }\n\n return [];\n};\n"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./flattenKvsQueryConditions"), exports);
|
|
18
|
+
__exportStar(require("./KvsIndexNotFoundError"), exports);
|
|
19
|
+
__exportStar(require("./resolveKvsQueryIndex"), exports);
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/logic/keyValueStore/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,8DAA4C;AAC5C,0DAAwC;AACxC,yDAAuC","sourcesContent":["export * from './flattenKvsQueryConditions';\nexport * from './KvsIndexNotFoundError';\nexport * from './resolveKvsQueryIndex';\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { KvsQueryOperation } from '../../actions/keyValueStore/types';
|
|
2
|
+
import { KeyValueStoreQPQConfigSetting, KvsIndex } from '../../config/settings/keyValueStore';
|
|
3
|
+
import { Nullable } from '../../types/Nullable';
|
|
4
|
+
/**
|
|
5
|
+
* The index a query runs against, or null for the table itself. `name` forces the declared index with
|
|
6
|
+
* that name; an undeclared name throws KvsIndexNotFoundError. Otherwise the first of the table, then each
|
|
7
|
+
* index in declaration order, whose keys cover every attribute the key condition names; the table wins
|
|
8
|
+
* ties (it can serve consistent reads). Null when nothing covers it, so the table refuses the query.
|
|
9
|
+
*/
|
|
10
|
+
export declare const resolveKvsQueryIndex: (storeConfig: KeyValueStoreQPQConfigSetting, keyCondition: KvsQueryOperation, name?: string) => Nullable<KvsIndex>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveKvsQueryIndex = void 0;
|
|
4
|
+
const flattenKvsQueryConditions_1 = require("./flattenKvsQueryConditions");
|
|
5
|
+
const KvsIndexNotFoundError_1 = require("./KvsIndexNotFoundError");
|
|
6
|
+
// A key condition may only name the partition key and sort key of whatever it runs against, and must
|
|
7
|
+
// name the partition key.
|
|
8
|
+
const keySchemaServes = (queriedKeys, partitionKey, sortKey) => queriedKeys.includes(partitionKey.key) && queriedKeys.every((key) => key === partitionKey.key || key === (sortKey === null || sortKey === void 0 ? void 0 : sortKey.key));
|
|
9
|
+
/**
|
|
10
|
+
* The index a query runs against, or null for the table itself. `name` forces the declared index with
|
|
11
|
+
* that name; an undeclared name throws KvsIndexNotFoundError. Otherwise the first of the table, then each
|
|
12
|
+
* index in declaration order, whose keys cover every attribute the key condition names; the table wins
|
|
13
|
+
* ties (it can serve consistent reads). Null when nothing covers it, so the table refuses the query.
|
|
14
|
+
*/
|
|
15
|
+
const resolveKvsQueryIndex = (storeConfig, keyCondition, name) => {
|
|
16
|
+
var _a;
|
|
17
|
+
if (name !== undefined) {
|
|
18
|
+
const namedIndex = storeConfig.indexes.find((index) => index.name === name);
|
|
19
|
+
if (!namedIndex) {
|
|
20
|
+
throw new KvsIndexNotFoundError_1.KvsIndexNotFoundError(storeConfig.keyValueStoreName, name);
|
|
21
|
+
}
|
|
22
|
+
return namedIndex;
|
|
23
|
+
}
|
|
24
|
+
const queriedKeys = (0, flattenKvsQueryConditions_1.flattenKvsQueryConditions)(keyCondition).map((condition) => condition.key);
|
|
25
|
+
if (keySchemaServes(queriedKeys, storeConfig.partitionKey, storeConfig.sortKeys[0])) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
return (_a = storeConfig.indexes.find((index) => keySchemaServes(queriedKeys, index.partitionKey, index.sortKey))) !== null && _a !== void 0 ? _a : null;
|
|
29
|
+
};
|
|
30
|
+
exports.resolveKvsQueryIndex = resolveKvsQueryIndex;
|
|
31
|
+
//# sourceMappingURL=resolveKvsQueryIndex.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolveKvsQueryIndex.js","sourceRoot":"","sources":["../../../../src/logic/keyValueStore/resolveKvsQueryIndex.ts"],"names":[],"mappings":";;;AAGA,2EAAwE;AACxE,mEAAgE;AAEhE,qGAAqG;AACrG,0BAA0B;AAC1B,MAAM,eAAe,GAAG,CAAC,WAAqB,EAAE,YAAoB,EAAE,OAAgB,EAAW,EAAE,CACjG,WAAW,CAAC,QAAQ,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,WAAW,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,KAAK,YAAY,CAAC,GAAG,IAAI,GAAG,MAAK,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,GAAG,CAAA,CAAC,CAAC;AAEzH;;;;;GAKG;AACI,MAAM,oBAAoB,GAAG,CAClC,WAA0C,EAC1C,YAA+B,EAC/B,IAAa,EACO,EAAE;;IACtB,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,MAAM,UAAU,GAAG,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;QAC5E,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,MAAM,IAAI,6CAAqB,CAAC,WAAW,CAAC,iBAAiB,EAAE,IAAI,CAAC,CAAC;QACvE,CAAC;QAED,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,MAAM,WAAW,GAAG,IAAA,qDAAyB,EAAC,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAC9F,IAAI,eAAe,CAAC,WAAW,EAAE,WAAW,CAAC,YAAY,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACpF,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,MAAA,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,eAAe,CAAC,WAAW,EAAE,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,mCAAI,IAAI,CAAC;AACtH,CAAC,CAAC;AApBW,QAAA,oBAAoB,wBAoB/B","sourcesContent":["import { KvsQueryOperation } from '../../actions/keyValueStore/types';\nimport { KeyValueStoreQPQConfigSetting, KvsIndex, KvsKey } from '../../config/settings/keyValueStore';\nimport { Nullable } from '../../types/Nullable';\nimport { flattenKvsQueryConditions } from './flattenKvsQueryConditions';\nimport { KvsIndexNotFoundError } from './KvsIndexNotFoundError';\n\n// A key condition may only name the partition key and sort key of whatever it runs against, and must\n// name the partition key.\nconst keySchemaServes = (queriedKeys: string[], partitionKey: KvsKey, sortKey?: KvsKey): boolean =>\n queriedKeys.includes(partitionKey.key) && queriedKeys.every((key) => key === partitionKey.key || key === sortKey?.key);\n\n/**\n * The index a query runs against, or null for the table itself. `name` forces the declared index with\n * that name; an undeclared name throws KvsIndexNotFoundError. Otherwise the first of the table, then each\n * index in declaration order, whose keys cover every attribute the key condition names; the table wins\n * ties (it can serve consistent reads). Null when nothing covers it, so the table refuses the query.\n */\nexport const resolveKvsQueryIndex = (\n storeConfig: KeyValueStoreQPQConfigSetting,\n keyCondition: KvsQueryOperation,\n name?: string,\n): Nullable<KvsIndex> => {\n if (name !== undefined) {\n const namedIndex = storeConfig.indexes.find((index) => index.name === name);\n if (!namedIndex) {\n throw new KvsIndexNotFoundError(storeConfig.keyValueStoreName, name);\n }\n\n return namedIndex;\n }\n\n const queriedKeys = flattenKvsQueryConditions(keyCondition).map((condition) => condition.key);\n if (keySchemaServes(queriedKeys, storeConfig.partitionKey, storeConfig.sortKeys[0])) {\n return null;\n }\n\n return storeConfig.indexes.find((index) => keySchemaServes(queriedKeys, index.partitionKey, index.sortKey)) ?? null;\n};\n"]}
|
|
@@ -6,7 +6,11 @@ export declare enum InvalidScopeErrorCode {
|
|
|
6
6
|
queryMissingPartitionKey = "queryMissingPartitionKey",
|
|
7
7
|
reservedDelimiter = "reservedDelimiter",
|
|
8
8
|
scopeRequired = "scopeRequired",
|
|
9
|
-
notScoped = "notScoped"
|
|
9
|
+
notScoped = "notScoped",
|
|
10
|
+
reservedAttribute = "reservedAttribute",
|
|
11
|
+
indexKeyType = "indexKeyType",
|
|
12
|
+
unsupportedOperation = "unsupportedOperation",
|
|
13
|
+
pageKeyOutOfScope = "pageKeyOutOfScope"
|
|
10
14
|
}
|
|
11
15
|
export declare class InvalidScopeError extends Error {
|
|
12
16
|
readonly code: InvalidScopeErrorCode;
|
|
@@ -31,6 +31,20 @@ var InvalidScopeErrorCode;
|
|
|
31
31
|
// config: the data would land under a prefix nothing else on that resource
|
|
32
32
|
// expects, invisible to every unscoped reader.
|
|
33
33
|
InvalidScopeErrorCode["notScoped"] = "notScoped";
|
|
34
|
+
// An attribute name on a scoped store carrying the reserved marker. Those
|
|
35
|
+
// attributes belong to the backend (its own index bookkeeping); a caller-set
|
|
36
|
+
// one could file the row under another scope's index partition.
|
|
37
|
+
InvalidScopeErrorCode["reservedAttribute"] = "reservedAttribute";
|
|
38
|
+
// A scoped store's index partition key value that doesn't match the key's
|
|
39
|
+
// declared type.
|
|
40
|
+
InvalidScopeErrorCode["indexKeyType"] = "indexKeyType";
|
|
41
|
+
// Something a scoped store's index partition key can't support: a non-equality
|
|
42
|
+
// key condition on it, or an update whose result isn't known up front
|
|
43
|
+
// (Increment, Add, Delete, a nested path).
|
|
44
|
+
InvalidScopeErrorCode["unsupportedOperation"] = "unsupportedOperation";
|
|
45
|
+
// A page key issued under another scope. A page key only continues the
|
|
46
|
+
// listing that issued it; one edited to point elsewhere is refused.
|
|
47
|
+
InvalidScopeErrorCode["pageKeyOutOfScope"] = "pageKeyOutOfScope";
|
|
34
48
|
})(InvalidScopeErrorCode || (exports.InvalidScopeErrorCode = InvalidScopeErrorCode = {}));
|
|
35
49
|
class InvalidScopeError extends Error {
|
|
36
50
|
constructor(code, message) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InvalidScopeError.js","sourceRoot":"","sources":["../../../../src/logic/scope/InvalidScopeError.ts"],"names":[],"mappings":";;;AAAA,8EAA8E;AAC9E,4EAA4E;AAC5E,uEAAuE;AACvE,6EAA6E;AAC7E,mBAAmB;AACnB,IAAY,
|
|
1
|
+
{"version":3,"file":"InvalidScopeError.js","sourceRoot":"","sources":["../../../../src/logic/scope/InvalidScopeError.ts"],"names":[],"mappings":";;;AAAA,8EAA8E;AAC9E,4EAA4E;AAC5E,uEAAuE;AACvE,6EAA6E;AAC7E,mBAAmB;AACnB,IAAY,qBAsCX;AAtCD,WAAY,qBAAqB;IAC/B,kCAAkC;IAClC,wCAAe,CAAA;IACf,mDAAmD;IACnD,8DAAqC,CAAA;IACrC,kEAAkE;IAClE,4CAAmB,CAAA;IACnB,uEAAuE;IACvE,yCAAyC;IACzC,kDAAyB,CAAA;IACzB,0EAA0E;IAC1E,0EAA0E;IAC1E,8EAAqD,CAAA;IACrD,6EAA6E;IAC7E,qEAAqE;IACrE,gEAAuC,CAAA;IACvC,6EAA6E;IAC7E,2EAA2E;IAC3E,uDAAuD;IACvD,wDAA+B,CAAA;IAC/B,wEAAwE;IACxE,2EAA2E;IAC3E,+CAA+C;IAC/C,gDAAuB,CAAA;IACvB,0EAA0E;IAC1E,6EAA6E;IAC7E,gEAAgE;IAChE,gEAAuC,CAAA;IACvC,0EAA0E;IAC1E,iBAAiB;IACjB,sDAA6B,CAAA;IAC7B,+EAA+E;IAC/E,sEAAsE;IACtE,2CAA2C;IAC3C,sEAA6C,CAAA;IAC7C,uEAAuE;IACvE,oEAAoE;IACpE,gEAAuC,CAAA;AACzC,CAAC,EAtCW,qBAAqB,qCAArB,qBAAqB,QAsChC;AAED,MAAa,iBAAkB,SAAQ,KAAK;IAC1C,YACkB,IAA2B,EAC3C,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAC;QAHC,SAAI,GAAJ,IAAI,CAAuB;QAI3C,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF;AARD,8CAQC","sourcesContent":["// Raised when a scope segment fails validation. Scope is an opaque identifier\n// (supplied by a higher-level data-partitioning feature) that gets embedded\n// into file paths and kvs partition keys, so a malformed one is always\n// rejected outright - never normalized - to make escaping a scope impossible\n// by construction.\nexport enum InvalidScopeErrorCode {\n // Empty or whitespace-only scope.\n empty = 'empty',\n // Contains a path separator, '..', or a null byte.\n unsafeCharacters = 'unsafeCharacters',\n // Longer than the allowed maximum (scopes are ids, not payloads).\n tooLong = 'tooLong',\n // A filepath composed under a scope could traverse out of it (absolute\n // path, a '..' segment, or a null byte).\n unsafePath = 'unsafePath',\n // A scoped query whose key condition never constrains the partition key -\n // on value-composed backends (dynamo) it would silently span every scope.\n queryMissingPartitionKey = 'queryMissingPartitionKey',\n // A raw partition-key value containing the scope delimiter: storing it would\n // make the row indistinguishable from another scope's composed data.\n reservedDelimiter = 'reservedDelimiter',\n // The resource is declared `scoped` in config but the call carried no scope.\n // On a drive that would land the object beside every tenant's prefix; on a\n // store it would read or write the unpartitioned rows.\n scopeRequired = 'scopeRequired',\n // The call carried a scope but the resource is not declared `scoped` in\n // config: the data would land under a prefix nothing else on that resource\n // expects, invisible to every unscoped reader.\n notScoped = 'notScoped',\n // An attribute name on a scoped store carrying the reserved marker. Those\n // attributes belong to the backend (its own index bookkeeping); a caller-set\n // one could file the row under another scope's index partition.\n reservedAttribute = 'reservedAttribute',\n // A scoped store's index partition key value that doesn't match the key's\n // declared type.\n indexKeyType = 'indexKeyType',\n // Something a scoped store's index partition key can't support: a non-equality\n // key condition on it, or an update whose result isn't known up front\n // (Increment, Add, Delete, a nested path).\n unsupportedOperation = 'unsupportedOperation',\n // A page key issued under another scope. A page key only continues the\n // listing that issued it; one edited to point elsewhere is refused.\n pageKeyOutOfScope = 'pageKeyOutOfScope',\n}\n\nexport class InvalidScopeError extends Error {\n constructor(\n public readonly code: InvalidScopeErrorCode,\n message: string,\n ) {\n super(message);\n this.name = 'InvalidScopeError';\n }\n}\n"]}
|
|
@@ -2,10 +2,8 @@ export * from './composeScopedFilePath';
|
|
|
2
2
|
export * from './fileScopeGate';
|
|
3
3
|
export * from './InvalidScopeError';
|
|
4
4
|
export * from './kvsScopeGate';
|
|
5
|
+
export * from './kvsScopeRules';
|
|
5
6
|
export * from './KvsStoreNotFoundError';
|
|
6
|
-
export * from './scopedKvsQueryOperation';
|
|
7
|
-
export * from './scopedKvsTranslator';
|
|
8
|
-
export * from './scopedKvsValue';
|
|
9
7
|
export * from './splitScopedFilePath';
|
|
10
8
|
export * from './storageScopeContext';
|
|
11
9
|
export * from './stripScopedFilePath';
|
|
@@ -18,10 +18,8 @@ __exportStar(require("./composeScopedFilePath"), exports);
|
|
|
18
18
|
__exportStar(require("./fileScopeGate"), exports);
|
|
19
19
|
__exportStar(require("./InvalidScopeError"), exports);
|
|
20
20
|
__exportStar(require("./kvsScopeGate"), exports);
|
|
21
|
+
__exportStar(require("./kvsScopeRules"), exports);
|
|
21
22
|
__exportStar(require("./KvsStoreNotFoundError"), exports);
|
|
22
|
-
__exportStar(require("./scopedKvsQueryOperation"), exports);
|
|
23
|
-
__exportStar(require("./scopedKvsTranslator"), exports);
|
|
24
|
-
__exportStar(require("./scopedKvsValue"), exports);
|
|
25
23
|
__exportStar(require("./splitScopedFilePath"), exports);
|
|
26
24
|
__exportStar(require("./storageScopeContext"), exports);
|
|
27
25
|
__exportStar(require("./stripScopedFilePath"), exports);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/logic/scope/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0DAAwC;AACxC,kDAAgC;AAChC,sDAAoC;AACpC,iDAA+B;AAC/B,0DAAwC;AACxC,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/logic/scope/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0DAAwC;AACxC,kDAAgC;AAChC,sDAAoC;AACpC,iDAA+B;AAC/B,kDAAgC;AAChC,0DAAwC;AACxC,wDAAsC;AACtC,wDAAsC;AACtC,wDAAsC;AACtC,yDAAuC","sourcesContent":["export * from './composeScopedFilePath';\nexport * from './fileScopeGate';\nexport * from './InvalidScopeError';\nexport * from './kvsScopeGate';\nexport * from './kvsScopeRules';\nexport * from './KvsStoreNotFoundError';\nexport * from './splitScopedFilePath';\nexport * from './storageScopeContext';\nexport * from './stripScopedFilePath';\nexport * from './validateScopeSegment';\n"]}
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
import { KvsCoreDataType, KvsQueryOperation } from '../../actions/keyValueStore/types';
|
|
1
|
+
import { KvsCoreDataType, KvsQueryOperation, KvsUpdate } from '../../actions/keyValueStore/types';
|
|
2
2
|
import { KeyValueStoreQPQConfigSetting, QPQConfig } from '../../config';
|
|
3
|
-
import { ScopedKvsTranslator } from './scopedKvsTranslator';
|
|
4
3
|
export declare const resolveKvsStoreConfigOrThrow: (qpqConfig: QPQConfig, keyValueStoreName: string) => KeyValueStoreQPQConfigSetting;
|
|
5
4
|
export declare const assertKvsScopeRequirementOrThrow: (qpqConfig: QPQConfig, keyValueStoreName: string, scope: string | undefined) => void;
|
|
6
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Store lookup plus every store-level scope rule: the call's scope matches the
|
|
7
|
+
* store's `scoped` flag, and a scope is a valid segment on a string-pk store.
|
|
8
|
+
* Backends call it once per request before touching data.
|
|
9
|
+
*/
|
|
10
|
+
export declare const resolveScopedKvsStoreOrThrow: (qpqConfig: QPQConfig, keyValueStoreName: string, scope: string | undefined) => KeyValueStoreQPQConfigSetting;
|
|
7
11
|
export declare const resolveScopedPkAttributeOrThrow: (qpqConfig: QPQConfig, keyValueStoreName: string, scope: string) => string;
|
|
8
12
|
export declare const validateScopedKvsKeyOrThrow: (qpqConfig: QPQConfig, keyValueStoreName: string, scope: string | undefined, key: KvsCoreDataType) => void;
|
|
9
13
|
export declare const validateScopedKvsItemOrThrow: (qpqConfig: QPQConfig, keyValueStoreName: string, scope: string | undefined, item: Record<string, any>) => void;
|
|
14
|
+
export declare const validateScopedKvsUpdatesOrThrow: (qpqConfig: QPQConfig, keyValueStoreName: string, scope: string | undefined, updates: KvsUpdate) => void;
|
|
10
15
|
export declare const validateScopedKvsKeyConditionOrThrow: (qpqConfig: QPQConfig, keyValueStoreName: string, scope: string | undefined, keyCondition: KvsQueryOperation) => void;
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.validateScopedKvsKeyConditionOrThrow = exports.validateScopedKvsItemOrThrow = exports.validateScopedKvsKeyOrThrow = exports.resolveScopedPkAttributeOrThrow = exports.
|
|
3
|
+
exports.validateScopedKvsKeyConditionOrThrow = exports.validateScopedKvsUpdatesOrThrow = exports.validateScopedKvsItemOrThrow = exports.validateScopedKvsKeyOrThrow = exports.resolveScopedPkAttributeOrThrow = exports.resolveScopedKvsStoreOrThrow = exports.assertKvsScopeRequirementOrThrow = exports.resolveKvsStoreConfigOrThrow = void 0;
|
|
4
4
|
const qpqCoreUtils_1 = require("../../qpqCoreUtils");
|
|
5
5
|
const InvalidScopeError_1 = require("./InvalidScopeError");
|
|
6
|
+
const kvsScopeRules_1 = require("./kvsScopeRules");
|
|
6
7
|
const KvsStoreNotFoundError_1 = require("./KvsStoreNotFoundError");
|
|
7
|
-
const scopedKvsTranslator_1 = require("./scopedKvsTranslator");
|
|
8
|
-
const scopedKvsValue_1 = require("./scopedKvsValue");
|
|
9
8
|
const validateScopeSegment_1 = require("./validateScopeSegment");
|
|
10
|
-
// THE shared scope gate for every kvs backend (dynamo, dev-server
|
|
11
|
-
// resolve the store's config
|
|
12
|
-
//
|
|
13
|
-
//
|
|
9
|
+
// THE shared scope gate for every kvs backend (dynamo, dev-server sqlite, ...):
|
|
10
|
+
// resolve the store's config and validate the call's scope against it. How a
|
|
11
|
+
// backend stores the scope is its own business; the rules they all enforce are
|
|
12
|
+
// in kvsScopeRules, so backends can never drift apart on validation.
|
|
14
13
|
// Store lookup with the typed misconfiguration error (never a bare throw).
|
|
15
14
|
const resolveKvsStoreConfigOrThrow = (qpqConfig, keyValueStoreName) => {
|
|
16
15
|
const storeConfig = (0, qpqCoreUtils_1.getKeyValueStoreByName)(qpqConfig, keyValueStoreName);
|
|
@@ -34,51 +33,49 @@ const assertKvsScopeRequirementOrThrow = (qpqConfig, keyValueStoreName, scope) =
|
|
|
34
33
|
}
|
|
35
34
|
};
|
|
36
35
|
exports.assertKvsScopeRequirementOrThrow = assertKvsScopeRequirementOrThrow;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const getScopedKvsTranslatorOrThrow = (qpqConfig, keyValueStoreName, scope) => {
|
|
36
|
+
/**
|
|
37
|
+
* Store lookup plus every store-level scope rule: the call's scope matches the
|
|
38
|
+
* store's `scoped` flag, and a scope is a valid segment on a string-pk store.
|
|
39
|
+
* Backends call it once per request before touching data.
|
|
40
|
+
*/
|
|
41
|
+
const resolveScopedKvsStoreOrThrow = (qpqConfig, keyValueStoreName, scope) => {
|
|
44
42
|
const storeConfig = (0, exports.resolveKvsStoreConfigOrThrow)(qpqConfig, keyValueStoreName);
|
|
45
43
|
(0, exports.assertKvsScopeRequirementOrThrow)(qpqConfig, keyValueStoreName, scope);
|
|
46
|
-
if (scope
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const stringPkAttribute = storeConfig.partitionKey.type === 'string' ? storeConfig.partitionKey.key : '';
|
|
50
|
-
return (0, scopedKvsTranslator_1.createScopedKvsTranslator)(undefined, stringPkAttribute);
|
|
44
|
+
if (scope !== undefined) {
|
|
45
|
+
(0, validateScopeSegment_1.validateScopeSegment)(scope);
|
|
46
|
+
(0, kvsScopeRules_1.validateScopeSupportedForPartitionKeyType)(storeConfig.partitionKey.type);
|
|
51
47
|
}
|
|
52
|
-
|
|
53
|
-
(0, scopedKvsValue_1.validateScopeSupportedForPartitionKeyType)(storeConfig.partitionKey.type);
|
|
54
|
-
return (0, scopedKvsTranslator_1.createScopedKvsTranslator)(scope, storeConfig.partitionKey.key);
|
|
48
|
+
return storeConfig;
|
|
55
49
|
};
|
|
56
|
-
exports.
|
|
57
|
-
//
|
|
58
|
-
//
|
|
59
|
-
//
|
|
50
|
+
exports.resolveScopedKvsStoreOrThrow = resolveScopedKvsStoreOrThrow;
|
|
51
|
+
// Row-partitioned backends (dev-server sqlite): the scope is a column, so the
|
|
52
|
+
// same validations apply, but all the backend needs back is the real partition
|
|
53
|
+
// key attribute name.
|
|
60
54
|
const resolveScopedPkAttributeOrThrow = (qpqConfig, keyValueStoreName, scope) => {
|
|
61
55
|
const storeConfig = (0, exports.resolveKvsStoreConfigOrThrow)(qpqConfig, keyValueStoreName);
|
|
62
56
|
(0, validateScopeSegment_1.validateScopeSegment)(scope);
|
|
63
|
-
(0,
|
|
57
|
+
(0, kvsScopeRules_1.validateScopeSupportedForPartitionKeyType)(storeConfig.partitionKey.type);
|
|
64
58
|
return storeConfig.partitionKey.key;
|
|
65
59
|
};
|
|
66
60
|
exports.resolveScopedPkAttributeOrThrow = resolveScopedPkAttributeOrThrow;
|
|
67
|
-
//
|
|
68
|
-
// and items raw
|
|
69
|
-
//
|
|
70
|
-
//
|
|
71
|
-
// deployed behavior. The composed results are discarded.
|
|
61
|
+
// Request-level checks for backends that keep the scope out of stored values
|
|
62
|
+
// (dev-server sqlite stores keys and items raw; the scope just picks the rows).
|
|
63
|
+
// They run the same rules a composing backend runs, so a call that fails
|
|
64
|
+
// deployed fails locally too.
|
|
72
65
|
const validateScopedKvsKeyOrThrow = (qpqConfig, keyValueStoreName, scope, key) => {
|
|
73
|
-
(0, exports.
|
|
66
|
+
(0, kvsScopeRules_1.validateKvsPkValueForScopeOrThrow)((0, exports.resolveScopedKvsStoreOrThrow)(qpqConfig, keyValueStoreName, scope), scope, key);
|
|
74
67
|
};
|
|
75
68
|
exports.validateScopedKvsKeyOrThrow = validateScopedKvsKeyOrThrow;
|
|
76
69
|
const validateScopedKvsItemOrThrow = (qpqConfig, keyValueStoreName, scope, item) => {
|
|
77
|
-
(0, exports.
|
|
70
|
+
(0, kvsScopeRules_1.validateKvsItemForScopeOrThrow)((0, exports.resolveScopedKvsStoreOrThrow)(qpqConfig, keyValueStoreName, scope), scope, item !== null && item !== void 0 ? item : {});
|
|
78
71
|
};
|
|
79
72
|
exports.validateScopedKvsItemOrThrow = validateScopedKvsItemOrThrow;
|
|
73
|
+
const validateScopedKvsUpdatesOrThrow = (qpqConfig, keyValueStoreName, scope, updates) => {
|
|
74
|
+
(0, kvsScopeRules_1.validateKvsUpdatesForScopeOrThrow)((0, exports.resolveScopedKvsStoreOrThrow)(qpqConfig, keyValueStoreName, scope), scope, updates);
|
|
75
|
+
};
|
|
76
|
+
exports.validateScopedKvsUpdatesOrThrow = validateScopedKvsUpdatesOrThrow;
|
|
80
77
|
const validateScopedKvsKeyConditionOrThrow = (qpqConfig, keyValueStoreName, scope, keyCondition) => {
|
|
81
|
-
(0, exports.
|
|
78
|
+
(0, kvsScopeRules_1.validateKvsKeyConditionForScopeOrThrow)((0, exports.resolveScopedKvsStoreOrThrow)(qpqConfig, keyValueStoreName, scope), scope, keyCondition);
|
|
82
79
|
};
|
|
83
80
|
exports.validateScopedKvsKeyConditionOrThrow = validateScopedKvsKeyConditionOrThrow;
|
|
84
81
|
//# sourceMappingURL=kvsScopeGate.js.map
|