@form-engine-ts/storage-azure-table 5.1.0 → 6.0.0
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/README.md +4 -0
- package/dist/index.cjs +37 -2
- package/dist/index.d.cts +19 -1
- package/dist/index.d.ts +19 -1
- package/dist/index.js +36 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -42,3 +42,7 @@ and field indexes, so a page can resume inside a multi-answer entity without gap
|
|
|
42
42
|
consume the item limit, and scanning remains bounded by `maxScanPages`. Cursor format version 1 also records the form,
|
|
43
43
|
version, sorted fields, and a SHA-256 filter fingerprint. Reusing a cursor with different query context throws
|
|
44
44
|
`invalid_cursor_context`.
|
|
45
|
+
|
|
46
|
+
`createLegacyAzureTableCodec()` decodes older entities using `PartitionKey`, `RowKey`, `answers`, `answeredAt`, and
|
|
47
|
+
`surveyVersion` into the canonical `FormSubmission` shape. Custom partition- and row-key generators can be supplied
|
|
48
|
+
for migration tooling.
|
package/dist/index.cjs
CHANGED
|
@@ -21,12 +21,36 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
createAzureTableStorage: () => createAzureTableStorage,
|
|
24
|
+
createLegacyAzureTableCodec: () => createLegacyAzureTableCodec,
|
|
24
25
|
defaultAzureTableSubmissionCodec: () => defaultAzureTableSubmissionCodec,
|
|
25
26
|
metadataFiltersToOData: () => metadataFiltersToOData,
|
|
26
27
|
submissionFilterToOData: () => submissionFilterToOData
|
|
27
28
|
});
|
|
28
29
|
module.exports = __toCommonJS(index_exports);
|
|
29
30
|
var import_core = require("@form-engine-ts/core");
|
|
31
|
+
var createLegacyAzureTableCodec = (options = {}) => {
|
|
32
|
+
const createPartitionKey = options.partitionKeyGenerator ?? ((formId) => formId);
|
|
33
|
+
const createRowKey = options.rowKeyGenerator ?? ((submittedAt, submissionId) => `${submittedAt}_${submissionId}`);
|
|
34
|
+
return {
|
|
35
|
+
decode: (entity) => {
|
|
36
|
+
const values = entity.answers === void 0 ? {} : parseLegacyJsonObject(entity.answers, "answers");
|
|
37
|
+
const submittedAt = entity.answeredAt ?? entity.Timestamp;
|
|
38
|
+
if (submittedAt === void 0 || submittedAt.trim().length === 0) {
|
|
39
|
+
throw new Error("Azure Table legacy submission is missing answeredAt or Timestamp.");
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
id: entity.RowKey,
|
|
43
|
+
formId: entity.PartitionKey,
|
|
44
|
+
formVersion: entity.surveyVersion ?? 1,
|
|
45
|
+
values,
|
|
46
|
+
metadata: {},
|
|
47
|
+
submittedAt
|
|
48
|
+
};
|
|
49
|
+
},
|
|
50
|
+
createPartitionKey: (formId, submissionId) => createPartitionKey(formId, submissionId),
|
|
51
|
+
createRowKey: (submittedAt, submissionId) => createRowKey(submittedAt, submissionId)
|
|
52
|
+
};
|
|
53
|
+
};
|
|
30
54
|
var BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
31
55
|
function encodeBase64(bytes) {
|
|
32
56
|
let result = "";
|
|
@@ -135,6 +159,11 @@ function parseJson(value, location) {
|
|
|
135
159
|
throw new Error(`Azure Table ${location} payload is invalid.`, { cause });
|
|
136
160
|
}
|
|
137
161
|
}
|
|
162
|
+
function parseLegacyJsonObject(value, property) {
|
|
163
|
+
const parsed = parseJson(value, `legacy ${property}`);
|
|
164
|
+
if (!isRecord(parsed)) throw new Error(`Azure Table legacy ${property} payload must be an object.`);
|
|
165
|
+
return parsed;
|
|
166
|
+
}
|
|
138
167
|
function parseSubmission(value, location) {
|
|
139
168
|
const parsed = typeof value === "string" ? parseJson(value, location) : value;
|
|
140
169
|
if (!isRecord(parsed) || typeof parsed.id !== "string" || typeof parsed.formId !== "string" || !Number.isInteger(parsed.formVersion) || typeof parsed.locale !== "string" || typeof parsed.submittedAt !== "string" || !isRecord(parsed.values) || !Object.values(parsed.values).every(isFormValue)) {
|
|
@@ -511,6 +540,11 @@ function createAzureTableStorage(options = {}) {
|
|
|
511
540
|
continue;
|
|
512
541
|
}
|
|
513
542
|
const answers = submissionTextAnswers(submission, fieldIds);
|
|
543
|
+
const metadata = submission.metadata === void 0 ? void 0 : Object.fromEntries(
|
|
544
|
+
Object.entries(submission.metadata).filter(
|
|
545
|
+
(entry) => entry[1] !== void 0
|
|
546
|
+
)
|
|
547
|
+
);
|
|
514
548
|
for (let fieldIndex = entityIndex === entityStartIndex ? fieldStartIndex : 0; fieldIndex < answers.length; fieldIndex += 1) {
|
|
515
549
|
const answer = answers[fieldIndex];
|
|
516
550
|
if (answer === void 0) continue;
|
|
@@ -520,9 +554,9 @@ function createAzureTableStorage(options = {}) {
|
|
|
520
554
|
formVersion: submission.formVersion,
|
|
521
555
|
fieldId: answer.fieldId,
|
|
522
556
|
text: answer.text,
|
|
523
|
-
locale: submission.locale,
|
|
557
|
+
...submission.locale === void 0 ? {} : { locale: submission.locale },
|
|
524
558
|
submittedAt: submission.submittedAt,
|
|
525
|
-
...
|
|
559
|
+
...metadata === void 0 ? {} : { metadata }
|
|
526
560
|
});
|
|
527
561
|
if (items.length < pageSize) continue;
|
|
528
562
|
const nextFieldIndex = fieldIndex + 1;
|
|
@@ -614,6 +648,7 @@ function createAzureTableStorage(options = {}) {
|
|
|
614
648
|
// Annotate the CommonJS export names for ESM import in node:
|
|
615
649
|
0 && (module.exports = {
|
|
616
650
|
createAzureTableStorage,
|
|
651
|
+
createLegacyAzureTableCodec,
|
|
617
652
|
defaultAzureTableSubmissionCodec,
|
|
618
653
|
metadataFiltersToOData,
|
|
619
654
|
submissionFilterToOData
|
package/dist/index.d.cts
CHANGED
|
@@ -30,6 +30,24 @@ interface AzureTableEntityCodec<T> {
|
|
|
30
30
|
readonly serialize: (submission: T) => Record<string, unknown>;
|
|
31
31
|
readonly deserialize: (entity: Record<string, unknown>) => T;
|
|
32
32
|
}
|
|
33
|
+
interface AzureTableLegacyEntity {
|
|
34
|
+
readonly PartitionKey: string;
|
|
35
|
+
readonly RowKey: string;
|
|
36
|
+
readonly answers?: string;
|
|
37
|
+
readonly answeredAt?: string;
|
|
38
|
+
readonly surveyVersion?: number;
|
|
39
|
+
readonly Timestamp?: string;
|
|
40
|
+
readonly [key: string]: unknown;
|
|
41
|
+
}
|
|
42
|
+
interface AzureTableLegacyCodec {
|
|
43
|
+
readonly decode: (entity: AzureTableLegacyEntity) => FormSubmission;
|
|
44
|
+
readonly createPartitionKey: (formId: string, submissionId: string) => string;
|
|
45
|
+
readonly createRowKey: (submittedAt: string, submissionId: string) => string;
|
|
46
|
+
}
|
|
47
|
+
declare const createLegacyAzureTableCodec: (options?: {
|
|
48
|
+
readonly partitionKeyGenerator?: (formId: string, submissionId: string) => string;
|
|
49
|
+
readonly rowKeyGenerator?: (submittedAt: string, submissionId: string) => string;
|
|
50
|
+
}) => AzureTableLegacyCodec;
|
|
33
51
|
interface AzureTableSubmissionCodec<T = FormSubmission> {
|
|
34
52
|
readonly createEntity: (value: T) => Record<string, unknown>;
|
|
35
53
|
readonly deserialize: (entity: Record<string, unknown>) => T;
|
|
@@ -86,4 +104,4 @@ declare function metadataFiltersToOData(options: SubmissionPageQueryOptions, map
|
|
|
86
104
|
declare function submissionFilterToOData(filter: SubmissionFilter, mapping?: AzureTableFieldMapping): string | undefined;
|
|
87
105
|
declare function createAzureTableStorage(options?: AzureTableStorageOptions): PagedSubmissionStorageAdapter;
|
|
88
106
|
|
|
89
|
-
export { type AzureTableClientLike, type AzureTableEntityCodec, type AzureTableEntityIterator, type AzureTableEntityPage, type AzureTableFieldMapping, type AzureTableListOptions, type AzureTablePageSettings, type AzureTableStorageOptions, type AzureTableSubmissionCodec, type AzureTableValueCodec, type AzureTextAnswerCursorPayload, createAzureTableStorage, defaultAzureTableSubmissionCodec, metadataFiltersToOData, submissionFilterToOData };
|
|
107
|
+
export { type AzureTableClientLike, type AzureTableEntityCodec, type AzureTableEntityIterator, type AzureTableEntityPage, type AzureTableFieldMapping, type AzureTableLegacyCodec, type AzureTableLegacyEntity, type AzureTableListOptions, type AzureTablePageSettings, type AzureTableStorageOptions, type AzureTableSubmissionCodec, type AzureTableValueCodec, type AzureTextAnswerCursorPayload, createAzureTableStorage, createLegacyAzureTableCodec, defaultAzureTableSubmissionCodec, metadataFiltersToOData, submissionFilterToOData };
|
package/dist/index.d.ts
CHANGED
|
@@ -30,6 +30,24 @@ interface AzureTableEntityCodec<T> {
|
|
|
30
30
|
readonly serialize: (submission: T) => Record<string, unknown>;
|
|
31
31
|
readonly deserialize: (entity: Record<string, unknown>) => T;
|
|
32
32
|
}
|
|
33
|
+
interface AzureTableLegacyEntity {
|
|
34
|
+
readonly PartitionKey: string;
|
|
35
|
+
readonly RowKey: string;
|
|
36
|
+
readonly answers?: string;
|
|
37
|
+
readonly answeredAt?: string;
|
|
38
|
+
readonly surveyVersion?: number;
|
|
39
|
+
readonly Timestamp?: string;
|
|
40
|
+
readonly [key: string]: unknown;
|
|
41
|
+
}
|
|
42
|
+
interface AzureTableLegacyCodec {
|
|
43
|
+
readonly decode: (entity: AzureTableLegacyEntity) => FormSubmission;
|
|
44
|
+
readonly createPartitionKey: (formId: string, submissionId: string) => string;
|
|
45
|
+
readonly createRowKey: (submittedAt: string, submissionId: string) => string;
|
|
46
|
+
}
|
|
47
|
+
declare const createLegacyAzureTableCodec: (options?: {
|
|
48
|
+
readonly partitionKeyGenerator?: (formId: string, submissionId: string) => string;
|
|
49
|
+
readonly rowKeyGenerator?: (submittedAt: string, submissionId: string) => string;
|
|
50
|
+
}) => AzureTableLegacyCodec;
|
|
33
51
|
interface AzureTableSubmissionCodec<T = FormSubmission> {
|
|
34
52
|
readonly createEntity: (value: T) => Record<string, unknown>;
|
|
35
53
|
readonly deserialize: (entity: Record<string, unknown>) => T;
|
|
@@ -86,4 +104,4 @@ declare function metadataFiltersToOData(options: SubmissionPageQueryOptions, map
|
|
|
86
104
|
declare function submissionFilterToOData(filter: SubmissionFilter, mapping?: AzureTableFieldMapping): string | undefined;
|
|
87
105
|
declare function createAzureTableStorage(options?: AzureTableStorageOptions): PagedSubmissionStorageAdapter;
|
|
88
106
|
|
|
89
|
-
export { type AzureTableClientLike, type AzureTableEntityCodec, type AzureTableEntityIterator, type AzureTableEntityPage, type AzureTableFieldMapping, type AzureTableListOptions, type AzureTablePageSettings, type AzureTableStorageOptions, type AzureTableSubmissionCodec, type AzureTableValueCodec, type AzureTextAnswerCursorPayload, createAzureTableStorage, defaultAzureTableSubmissionCodec, metadataFiltersToOData, submissionFilterToOData };
|
|
107
|
+
export { type AzureTableClientLike, type AzureTableEntityCodec, type AzureTableEntityIterator, type AzureTableEntityPage, type AzureTableFieldMapping, type AzureTableLegacyCodec, type AzureTableLegacyEntity, type AzureTableListOptions, type AzureTablePageSettings, type AzureTableStorageOptions, type AzureTableSubmissionCodec, type AzureTableValueCodec, type AzureTextAnswerCursorPayload, createAzureTableStorage, createLegacyAzureTableCodec, defaultAzureTableSubmissionCodec, metadataFiltersToOData, submissionFilterToOData };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
import { assertValidFormSchema, matchesSubmissionPageFilters, normalizeSubmissionPageSize } from "@form-engine-ts/core";
|
|
3
|
+
var createLegacyAzureTableCodec = (options = {}) => {
|
|
4
|
+
const createPartitionKey = options.partitionKeyGenerator ?? ((formId) => formId);
|
|
5
|
+
const createRowKey = options.rowKeyGenerator ?? ((submittedAt, submissionId) => `${submittedAt}_${submissionId}`);
|
|
6
|
+
return {
|
|
7
|
+
decode: (entity) => {
|
|
8
|
+
const values = entity.answers === void 0 ? {} : parseLegacyJsonObject(entity.answers, "answers");
|
|
9
|
+
const submittedAt = entity.answeredAt ?? entity.Timestamp;
|
|
10
|
+
if (submittedAt === void 0 || submittedAt.trim().length === 0) {
|
|
11
|
+
throw new Error("Azure Table legacy submission is missing answeredAt or Timestamp.");
|
|
12
|
+
}
|
|
13
|
+
return {
|
|
14
|
+
id: entity.RowKey,
|
|
15
|
+
formId: entity.PartitionKey,
|
|
16
|
+
formVersion: entity.surveyVersion ?? 1,
|
|
17
|
+
values,
|
|
18
|
+
metadata: {},
|
|
19
|
+
submittedAt
|
|
20
|
+
};
|
|
21
|
+
},
|
|
22
|
+
createPartitionKey: (formId, submissionId) => createPartitionKey(formId, submissionId),
|
|
23
|
+
createRowKey: (submittedAt, submissionId) => createRowKey(submittedAt, submissionId)
|
|
24
|
+
};
|
|
25
|
+
};
|
|
3
26
|
var BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
4
27
|
function encodeBase64(bytes) {
|
|
5
28
|
let result = "";
|
|
@@ -108,6 +131,11 @@ function parseJson(value, location) {
|
|
|
108
131
|
throw new Error(`Azure Table ${location} payload is invalid.`, { cause });
|
|
109
132
|
}
|
|
110
133
|
}
|
|
134
|
+
function parseLegacyJsonObject(value, property) {
|
|
135
|
+
const parsed = parseJson(value, `legacy ${property}`);
|
|
136
|
+
if (!isRecord(parsed)) throw new Error(`Azure Table legacy ${property} payload must be an object.`);
|
|
137
|
+
return parsed;
|
|
138
|
+
}
|
|
111
139
|
function parseSubmission(value, location) {
|
|
112
140
|
const parsed = typeof value === "string" ? parseJson(value, location) : value;
|
|
113
141
|
if (!isRecord(parsed) || typeof parsed.id !== "string" || typeof parsed.formId !== "string" || !Number.isInteger(parsed.formVersion) || typeof parsed.locale !== "string" || typeof parsed.submittedAt !== "string" || !isRecord(parsed.values) || !Object.values(parsed.values).every(isFormValue)) {
|
|
@@ -484,6 +512,11 @@ function createAzureTableStorage(options = {}) {
|
|
|
484
512
|
continue;
|
|
485
513
|
}
|
|
486
514
|
const answers = submissionTextAnswers(submission, fieldIds);
|
|
515
|
+
const metadata = submission.metadata === void 0 ? void 0 : Object.fromEntries(
|
|
516
|
+
Object.entries(submission.metadata).filter(
|
|
517
|
+
(entry) => entry[1] !== void 0
|
|
518
|
+
)
|
|
519
|
+
);
|
|
487
520
|
for (let fieldIndex = entityIndex === entityStartIndex ? fieldStartIndex : 0; fieldIndex < answers.length; fieldIndex += 1) {
|
|
488
521
|
const answer = answers[fieldIndex];
|
|
489
522
|
if (answer === void 0) continue;
|
|
@@ -493,9 +526,9 @@ function createAzureTableStorage(options = {}) {
|
|
|
493
526
|
formVersion: submission.formVersion,
|
|
494
527
|
fieldId: answer.fieldId,
|
|
495
528
|
text: answer.text,
|
|
496
|
-
locale: submission.locale,
|
|
529
|
+
...submission.locale === void 0 ? {} : { locale: submission.locale },
|
|
497
530
|
submittedAt: submission.submittedAt,
|
|
498
|
-
...
|
|
531
|
+
...metadata === void 0 ? {} : { metadata }
|
|
499
532
|
});
|
|
500
533
|
if (items.length < pageSize) continue;
|
|
501
534
|
const nextFieldIndex = fieldIndex + 1;
|
|
@@ -586,6 +619,7 @@ function createAzureTableStorage(options = {}) {
|
|
|
586
619
|
}
|
|
587
620
|
export {
|
|
588
621
|
createAzureTableStorage,
|
|
622
|
+
createLegacyAzureTableCodec,
|
|
589
623
|
defaultAzureTableSubmissionCodec,
|
|
590
624
|
metadataFiltersToOData,
|
|
591
625
|
submissionFilterToOData
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@form-engine-ts/storage-azure-table",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.0",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"typescript"
|
|
40
40
|
],
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@form-engine-ts/core": "
|
|
42
|
+
"@form-engine-ts/core": "6.0.0"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
45
45
|
"@azure/data-tables": "^13.3.2"
|