@form-engine-ts/storage-azure-table 5.1.0 → 6.1.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 +90 -2
- package/dist/index.d.cts +36 -2
- package/dist/index.d.ts +36 -2
- package/dist/index.js +88 -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,88 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
createAzureTableStorage: () => createAzureTableStorage,
|
|
24
|
+
createLegacyArrayAzureTableCodec: () => createLegacyArrayAzureTableCodec,
|
|
25
|
+
createLegacyAzureTableCodec: () => createLegacyAzureTableCodec,
|
|
24
26
|
defaultAzureTableSubmissionCodec: () => defaultAzureTableSubmissionCodec,
|
|
25
27
|
metadataFiltersToOData: () => metadataFiltersToOData,
|
|
26
28
|
submissionFilterToOData: () => submissionFilterToOData
|
|
27
29
|
});
|
|
28
30
|
module.exports = __toCommonJS(index_exports);
|
|
29
31
|
var import_core = require("@form-engine-ts/core");
|
|
32
|
+
function createLegacyArrayAzureTableCodec(options = {}) {
|
|
33
|
+
const defaultLocale = options.defaultLocale ?? "ja";
|
|
34
|
+
if (defaultLocale.trim().length === 0) throw new TypeError("defaultLocale must not be empty.");
|
|
35
|
+
return {
|
|
36
|
+
encode: (submission) => ({
|
|
37
|
+
PartitionKey: submission.formId,
|
|
38
|
+
RowKey: submission.id,
|
|
39
|
+
answers: JSON.stringify(Object.entries(submission.values).map(([questionId, value]) => ({ questionId, value }))),
|
|
40
|
+
answeredAt: submission.submittedAt,
|
|
41
|
+
surveyVersion: submission.formVersion,
|
|
42
|
+
locale: submission.locale,
|
|
43
|
+
...submission.metadata
|
|
44
|
+
}),
|
|
45
|
+
decode: (entity) => {
|
|
46
|
+
const raw = entity;
|
|
47
|
+
if (typeof raw.PartitionKey !== "string" || typeof raw.RowKey !== "string") {
|
|
48
|
+
throw new Error("Azure Table legacy array submission is missing PartitionKey or RowKey.");
|
|
49
|
+
}
|
|
50
|
+
const submittedAt = typeof raw.answeredAt === "string" ? raw.answeredAt : entity.Timestamp;
|
|
51
|
+
if (typeof submittedAt !== "string" || submittedAt.trim().length === 0) {
|
|
52
|
+
throw new Error("Azure Table legacy array submission is missing answeredAt or Timestamp.");
|
|
53
|
+
}
|
|
54
|
+
let values = {};
|
|
55
|
+
if (typeof raw.answers === "string") {
|
|
56
|
+
const parsed = parseJson(raw.answers, "legacy array answers");
|
|
57
|
+
if (Array.isArray(parsed)) {
|
|
58
|
+
values = Object.fromEntries(
|
|
59
|
+
parsed.flatMap((item) => {
|
|
60
|
+
if (!isRecord(item) || typeof item.questionId !== "string") return [];
|
|
61
|
+
return [[item.questionId, item.value]];
|
|
62
|
+
})
|
|
63
|
+
);
|
|
64
|
+
} else if (isRecord(parsed)) {
|
|
65
|
+
values = parsed;
|
|
66
|
+
} else {
|
|
67
|
+
throw new Error("Azure Table legacy array answers payload must be an array or object.");
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const formVersion = Number(raw.surveyVersion);
|
|
71
|
+
return {
|
|
72
|
+
id: raw.RowKey,
|
|
73
|
+
formId: raw.PartitionKey,
|
|
74
|
+
formVersion: Number.isSafeInteger(formVersion) && formVersion > 0 ? formVersion : 1,
|
|
75
|
+
values,
|
|
76
|
+
locale: typeof raw.locale === "string" && raw.locale.trim().length > 0 ? raw.locale : defaultLocale,
|
|
77
|
+
metadata: options.metadataExtractor?.(entity) ?? {},
|
|
78
|
+
submittedAt
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
var createLegacyAzureTableCodec = (options = {}) => {
|
|
84
|
+
const createPartitionKey = options.partitionKeyGenerator ?? ((formId) => formId);
|
|
85
|
+
const createRowKey = options.rowKeyGenerator ?? ((submittedAt, submissionId) => `${submittedAt}_${submissionId}`);
|
|
86
|
+
return {
|
|
87
|
+
decode: (entity) => {
|
|
88
|
+
const values = entity.answers === void 0 ? {} : parseLegacyJsonObject(entity.answers, "answers");
|
|
89
|
+
const submittedAt = entity.answeredAt ?? entity.Timestamp;
|
|
90
|
+
if (submittedAt === void 0 || submittedAt.trim().length === 0) {
|
|
91
|
+
throw new Error("Azure Table legacy submission is missing answeredAt or Timestamp.");
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
id: entity.RowKey,
|
|
95
|
+
formId: entity.PartitionKey,
|
|
96
|
+
formVersion: entity.surveyVersion ?? 1,
|
|
97
|
+
values,
|
|
98
|
+
metadata: {},
|
|
99
|
+
submittedAt
|
|
100
|
+
};
|
|
101
|
+
},
|
|
102
|
+
createPartitionKey: (formId, submissionId) => createPartitionKey(formId, submissionId),
|
|
103
|
+
createRowKey: (submittedAt, submissionId) => createRowKey(submittedAt, submissionId)
|
|
104
|
+
};
|
|
105
|
+
};
|
|
30
106
|
var BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
31
107
|
function encodeBase64(bytes) {
|
|
32
108
|
let result = "";
|
|
@@ -135,6 +211,11 @@ function parseJson(value, location) {
|
|
|
135
211
|
throw new Error(`Azure Table ${location} payload is invalid.`, { cause });
|
|
136
212
|
}
|
|
137
213
|
}
|
|
214
|
+
function parseLegacyJsonObject(value, property) {
|
|
215
|
+
const parsed = parseJson(value, `legacy ${property}`);
|
|
216
|
+
if (!isRecord(parsed)) throw new Error(`Azure Table legacy ${property} payload must be an object.`);
|
|
217
|
+
return parsed;
|
|
218
|
+
}
|
|
138
219
|
function parseSubmission(value, location) {
|
|
139
220
|
const parsed = typeof value === "string" ? parseJson(value, location) : value;
|
|
140
221
|
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 +592,11 @@ function createAzureTableStorage(options = {}) {
|
|
|
511
592
|
continue;
|
|
512
593
|
}
|
|
513
594
|
const answers = submissionTextAnswers(submission, fieldIds);
|
|
595
|
+
const metadata = submission.metadata === void 0 ? void 0 : Object.fromEntries(
|
|
596
|
+
Object.entries(submission.metadata).filter(
|
|
597
|
+
(entry) => entry[1] !== void 0
|
|
598
|
+
)
|
|
599
|
+
);
|
|
514
600
|
for (let fieldIndex = entityIndex === entityStartIndex ? fieldStartIndex : 0; fieldIndex < answers.length; fieldIndex += 1) {
|
|
515
601
|
const answer = answers[fieldIndex];
|
|
516
602
|
if (answer === void 0) continue;
|
|
@@ -520,9 +606,9 @@ function createAzureTableStorage(options = {}) {
|
|
|
520
606
|
formVersion: submission.formVersion,
|
|
521
607
|
fieldId: answer.fieldId,
|
|
522
608
|
text: answer.text,
|
|
523
|
-
locale: submission.locale,
|
|
609
|
+
...submission.locale === void 0 ? {} : { locale: submission.locale },
|
|
524
610
|
submittedAt: submission.submittedAt,
|
|
525
|
-
...
|
|
611
|
+
...metadata === void 0 ? {} : { metadata }
|
|
526
612
|
});
|
|
527
613
|
if (items.length < pageSize) continue;
|
|
528
614
|
const nextFieldIndex = fieldIndex + 1;
|
|
@@ -614,6 +700,8 @@ function createAzureTableStorage(options = {}) {
|
|
|
614
700
|
// Annotate the CommonJS export names for ESM import in node:
|
|
615
701
|
0 && (module.exports = {
|
|
616
702
|
createAzureTableStorage,
|
|
703
|
+
createLegacyArrayAzureTableCodec,
|
|
704
|
+
createLegacyAzureTableCodec,
|
|
617
705
|
defaultAzureTableSubmissionCodec,
|
|
618
706
|
metadataFiltersToOData,
|
|
619
707
|
submissionFilterToOData
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FormSubmission, SubmissionPageQueryOptions, PagedSubmissionStorageAdapter, SubmissionFilter } from '@form-engine-ts/core';
|
|
1
|
+
import { FormSubmission, SubmissionPageQueryOptions, BaseSubmissionMetadata, StrictFormSubmission, PagedSubmissionStorageAdapter, SubmissionFilter } from '@form-engine-ts/core';
|
|
2
2
|
|
|
3
3
|
interface AzureTableListOptions {
|
|
4
4
|
readonly queryOptions?: {
|
|
@@ -30,6 +30,40 @@ 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
|
+
interface LegacyAnswerArrayEntity extends Record<string, unknown> {
|
|
48
|
+
readonly PartitionKey: string;
|
|
49
|
+
readonly RowKey: string;
|
|
50
|
+
readonly answers: string;
|
|
51
|
+
readonly answeredAt: string;
|
|
52
|
+
readonly surveyVersion: number;
|
|
53
|
+
readonly locale?: string;
|
|
54
|
+
}
|
|
55
|
+
interface LegacyArrayAzureTableCodec<TMeta extends BaseSubmissionMetadata = BaseSubmissionMetadata> {
|
|
56
|
+
readonly encode: (submission: StrictFormSubmission<TMeta>) => Record<string, unknown>;
|
|
57
|
+
readonly decode: (entity: Record<string, unknown>) => StrictFormSubmission<TMeta>;
|
|
58
|
+
}
|
|
59
|
+
declare function createLegacyArrayAzureTableCodec<TMeta extends BaseSubmissionMetadata = BaseSubmissionMetadata>(options?: {
|
|
60
|
+
readonly defaultLocale?: string;
|
|
61
|
+
readonly metadataExtractor?: (entity: Record<string, unknown>) => TMeta;
|
|
62
|
+
}): LegacyArrayAzureTableCodec<TMeta>;
|
|
63
|
+
declare const createLegacyAzureTableCodec: (options?: {
|
|
64
|
+
readonly partitionKeyGenerator?: (formId: string, submissionId: string) => string;
|
|
65
|
+
readonly rowKeyGenerator?: (submittedAt: string, submissionId: string) => string;
|
|
66
|
+
}) => AzureTableLegacyCodec;
|
|
33
67
|
interface AzureTableSubmissionCodec<T = FormSubmission> {
|
|
34
68
|
readonly createEntity: (value: T) => Record<string, unknown>;
|
|
35
69
|
readonly deserialize: (entity: Record<string, unknown>) => T;
|
|
@@ -86,4 +120,4 @@ declare function metadataFiltersToOData(options: SubmissionPageQueryOptions, map
|
|
|
86
120
|
declare function submissionFilterToOData(filter: SubmissionFilter, mapping?: AzureTableFieldMapping): string | undefined;
|
|
87
121
|
declare function createAzureTableStorage(options?: AzureTableStorageOptions): PagedSubmissionStorageAdapter;
|
|
88
122
|
|
|
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 };
|
|
123
|
+
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, type LegacyAnswerArrayEntity, type LegacyArrayAzureTableCodec, createAzureTableStorage, createLegacyArrayAzureTableCodec, createLegacyAzureTableCodec, defaultAzureTableSubmissionCodec, metadataFiltersToOData, submissionFilterToOData };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FormSubmission, SubmissionPageQueryOptions, PagedSubmissionStorageAdapter, SubmissionFilter } from '@form-engine-ts/core';
|
|
1
|
+
import { FormSubmission, SubmissionPageQueryOptions, BaseSubmissionMetadata, StrictFormSubmission, PagedSubmissionStorageAdapter, SubmissionFilter } from '@form-engine-ts/core';
|
|
2
2
|
|
|
3
3
|
interface AzureTableListOptions {
|
|
4
4
|
readonly queryOptions?: {
|
|
@@ -30,6 +30,40 @@ 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
|
+
interface LegacyAnswerArrayEntity extends Record<string, unknown> {
|
|
48
|
+
readonly PartitionKey: string;
|
|
49
|
+
readonly RowKey: string;
|
|
50
|
+
readonly answers: string;
|
|
51
|
+
readonly answeredAt: string;
|
|
52
|
+
readonly surveyVersion: number;
|
|
53
|
+
readonly locale?: string;
|
|
54
|
+
}
|
|
55
|
+
interface LegacyArrayAzureTableCodec<TMeta extends BaseSubmissionMetadata = BaseSubmissionMetadata> {
|
|
56
|
+
readonly encode: (submission: StrictFormSubmission<TMeta>) => Record<string, unknown>;
|
|
57
|
+
readonly decode: (entity: Record<string, unknown>) => StrictFormSubmission<TMeta>;
|
|
58
|
+
}
|
|
59
|
+
declare function createLegacyArrayAzureTableCodec<TMeta extends BaseSubmissionMetadata = BaseSubmissionMetadata>(options?: {
|
|
60
|
+
readonly defaultLocale?: string;
|
|
61
|
+
readonly metadataExtractor?: (entity: Record<string, unknown>) => TMeta;
|
|
62
|
+
}): LegacyArrayAzureTableCodec<TMeta>;
|
|
63
|
+
declare const createLegacyAzureTableCodec: (options?: {
|
|
64
|
+
readonly partitionKeyGenerator?: (formId: string, submissionId: string) => string;
|
|
65
|
+
readonly rowKeyGenerator?: (submittedAt: string, submissionId: string) => string;
|
|
66
|
+
}) => AzureTableLegacyCodec;
|
|
33
67
|
interface AzureTableSubmissionCodec<T = FormSubmission> {
|
|
34
68
|
readonly createEntity: (value: T) => Record<string, unknown>;
|
|
35
69
|
readonly deserialize: (entity: Record<string, unknown>) => T;
|
|
@@ -86,4 +120,4 @@ declare function metadataFiltersToOData(options: SubmissionPageQueryOptions, map
|
|
|
86
120
|
declare function submissionFilterToOData(filter: SubmissionFilter, mapping?: AzureTableFieldMapping): string | undefined;
|
|
87
121
|
declare function createAzureTableStorage(options?: AzureTableStorageOptions): PagedSubmissionStorageAdapter;
|
|
88
122
|
|
|
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 };
|
|
123
|
+
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, type LegacyAnswerArrayEntity, type LegacyArrayAzureTableCodec, createAzureTableStorage, createLegacyArrayAzureTableCodec, createLegacyAzureTableCodec, defaultAzureTableSubmissionCodec, metadataFiltersToOData, submissionFilterToOData };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,79 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
import { assertValidFormSchema, matchesSubmissionPageFilters, normalizeSubmissionPageSize } from "@form-engine-ts/core";
|
|
3
|
+
function createLegacyArrayAzureTableCodec(options = {}) {
|
|
4
|
+
const defaultLocale = options.defaultLocale ?? "ja";
|
|
5
|
+
if (defaultLocale.trim().length === 0) throw new TypeError("defaultLocale must not be empty.");
|
|
6
|
+
return {
|
|
7
|
+
encode: (submission) => ({
|
|
8
|
+
PartitionKey: submission.formId,
|
|
9
|
+
RowKey: submission.id,
|
|
10
|
+
answers: JSON.stringify(Object.entries(submission.values).map(([questionId, value]) => ({ questionId, value }))),
|
|
11
|
+
answeredAt: submission.submittedAt,
|
|
12
|
+
surveyVersion: submission.formVersion,
|
|
13
|
+
locale: submission.locale,
|
|
14
|
+
...submission.metadata
|
|
15
|
+
}),
|
|
16
|
+
decode: (entity) => {
|
|
17
|
+
const raw = entity;
|
|
18
|
+
if (typeof raw.PartitionKey !== "string" || typeof raw.RowKey !== "string") {
|
|
19
|
+
throw new Error("Azure Table legacy array submission is missing PartitionKey or RowKey.");
|
|
20
|
+
}
|
|
21
|
+
const submittedAt = typeof raw.answeredAt === "string" ? raw.answeredAt : entity.Timestamp;
|
|
22
|
+
if (typeof submittedAt !== "string" || submittedAt.trim().length === 0) {
|
|
23
|
+
throw new Error("Azure Table legacy array submission is missing answeredAt or Timestamp.");
|
|
24
|
+
}
|
|
25
|
+
let values = {};
|
|
26
|
+
if (typeof raw.answers === "string") {
|
|
27
|
+
const parsed = parseJson(raw.answers, "legacy array answers");
|
|
28
|
+
if (Array.isArray(parsed)) {
|
|
29
|
+
values = Object.fromEntries(
|
|
30
|
+
parsed.flatMap((item) => {
|
|
31
|
+
if (!isRecord(item) || typeof item.questionId !== "string") return [];
|
|
32
|
+
return [[item.questionId, item.value]];
|
|
33
|
+
})
|
|
34
|
+
);
|
|
35
|
+
} else if (isRecord(parsed)) {
|
|
36
|
+
values = parsed;
|
|
37
|
+
} else {
|
|
38
|
+
throw new Error("Azure Table legacy array answers payload must be an array or object.");
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const formVersion = Number(raw.surveyVersion);
|
|
42
|
+
return {
|
|
43
|
+
id: raw.RowKey,
|
|
44
|
+
formId: raw.PartitionKey,
|
|
45
|
+
formVersion: Number.isSafeInteger(formVersion) && formVersion > 0 ? formVersion : 1,
|
|
46
|
+
values,
|
|
47
|
+
locale: typeof raw.locale === "string" && raw.locale.trim().length > 0 ? raw.locale : defaultLocale,
|
|
48
|
+
metadata: options.metadataExtractor?.(entity) ?? {},
|
|
49
|
+
submittedAt
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
var createLegacyAzureTableCodec = (options = {}) => {
|
|
55
|
+
const createPartitionKey = options.partitionKeyGenerator ?? ((formId) => formId);
|
|
56
|
+
const createRowKey = options.rowKeyGenerator ?? ((submittedAt, submissionId) => `${submittedAt}_${submissionId}`);
|
|
57
|
+
return {
|
|
58
|
+
decode: (entity) => {
|
|
59
|
+
const values = entity.answers === void 0 ? {} : parseLegacyJsonObject(entity.answers, "answers");
|
|
60
|
+
const submittedAt = entity.answeredAt ?? entity.Timestamp;
|
|
61
|
+
if (submittedAt === void 0 || submittedAt.trim().length === 0) {
|
|
62
|
+
throw new Error("Azure Table legacy submission is missing answeredAt or Timestamp.");
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
id: entity.RowKey,
|
|
66
|
+
formId: entity.PartitionKey,
|
|
67
|
+
formVersion: entity.surveyVersion ?? 1,
|
|
68
|
+
values,
|
|
69
|
+
metadata: {},
|
|
70
|
+
submittedAt
|
|
71
|
+
};
|
|
72
|
+
},
|
|
73
|
+
createPartitionKey: (formId, submissionId) => createPartitionKey(formId, submissionId),
|
|
74
|
+
createRowKey: (submittedAt, submissionId) => createRowKey(submittedAt, submissionId)
|
|
75
|
+
};
|
|
76
|
+
};
|
|
3
77
|
var BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
4
78
|
function encodeBase64(bytes) {
|
|
5
79
|
let result = "";
|
|
@@ -108,6 +182,11 @@ function parseJson(value, location) {
|
|
|
108
182
|
throw new Error(`Azure Table ${location} payload is invalid.`, { cause });
|
|
109
183
|
}
|
|
110
184
|
}
|
|
185
|
+
function parseLegacyJsonObject(value, property) {
|
|
186
|
+
const parsed = parseJson(value, `legacy ${property}`);
|
|
187
|
+
if (!isRecord(parsed)) throw new Error(`Azure Table legacy ${property} payload must be an object.`);
|
|
188
|
+
return parsed;
|
|
189
|
+
}
|
|
111
190
|
function parseSubmission(value, location) {
|
|
112
191
|
const parsed = typeof value === "string" ? parseJson(value, location) : value;
|
|
113
192
|
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 +563,11 @@ function createAzureTableStorage(options = {}) {
|
|
|
484
563
|
continue;
|
|
485
564
|
}
|
|
486
565
|
const answers = submissionTextAnswers(submission, fieldIds);
|
|
566
|
+
const metadata = submission.metadata === void 0 ? void 0 : Object.fromEntries(
|
|
567
|
+
Object.entries(submission.metadata).filter(
|
|
568
|
+
(entry) => entry[1] !== void 0
|
|
569
|
+
)
|
|
570
|
+
);
|
|
487
571
|
for (let fieldIndex = entityIndex === entityStartIndex ? fieldStartIndex : 0; fieldIndex < answers.length; fieldIndex += 1) {
|
|
488
572
|
const answer = answers[fieldIndex];
|
|
489
573
|
if (answer === void 0) continue;
|
|
@@ -493,9 +577,9 @@ function createAzureTableStorage(options = {}) {
|
|
|
493
577
|
formVersion: submission.formVersion,
|
|
494
578
|
fieldId: answer.fieldId,
|
|
495
579
|
text: answer.text,
|
|
496
|
-
locale: submission.locale,
|
|
580
|
+
...submission.locale === void 0 ? {} : { locale: submission.locale },
|
|
497
581
|
submittedAt: submission.submittedAt,
|
|
498
|
-
...
|
|
582
|
+
...metadata === void 0 ? {} : { metadata }
|
|
499
583
|
});
|
|
500
584
|
if (items.length < pageSize) continue;
|
|
501
585
|
const nextFieldIndex = fieldIndex + 1;
|
|
@@ -586,6 +670,8 @@ function createAzureTableStorage(options = {}) {
|
|
|
586
670
|
}
|
|
587
671
|
export {
|
|
588
672
|
createAzureTableStorage,
|
|
673
|
+
createLegacyArrayAzureTableCodec,
|
|
674
|
+
createLegacyAzureTableCodec,
|
|
589
675
|
defaultAzureTableSubmissionCodec,
|
|
590
676
|
metadataFiltersToOData,
|
|
591
677
|
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.1.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.1.0"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
45
45
|
"@azure/data-tables": "^13.3.2"
|