@form-engine-ts/storage-mongodb 2.3.0 → 2.5.1

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 CHANGED
@@ -26,3 +26,7 @@ const submissions = await storage.listSubmissions(schema.id, schema.version, {
26
26
  ```
27
27
 
28
28
  The caller owns the MongoDB connection lifecycle. Collection names can be customized in the factory options. `createIndexes()` creates named indexes for form/timestamp range scans and locale queries. Range boundaries are inclusive, and MongoDB sorts by submission time and then ID. `clearResponses(formId)` preserves schemas and other forms; `clear()` removes documents only from the configured collections and does not drop collections or indexes.
29
+
30
+ `listSubmissionPage(formId, { version, pageSize, cursor, since, until, locale })` performs bounded reads using the
31
+ compound `submittedAt`/response-ID cursor. Run `createIndexes()` after upgrading to create the matching compound index.
32
+ `metadataFilters` and custom `filter` predicates are applied before page sizing.
package/dist/index.cjs CHANGED
@@ -118,6 +118,38 @@ function createMongoDbStorage(options) {
118
118
  }).sort({ submittedAt: 1, _id: 1 }).toArray();
119
119
  return documents.map(parseSubmissionDocument);
120
120
  },
121
+ async listSubmissionPage(formId, options2 = {}) {
122
+ const pageSize = (0, import_core.normalizeSubmissionPageSize)(options2.pageSize);
123
+ const cursor = options2.cursor === void 0 ? void 0 : (0, import_core.decodeSubmissionCursor)(options2.cursor);
124
+ const submittedAt = options2.since === void 0 && options2.until === void 0 ? void 0 : {
125
+ ...options2.since === void 0 ? {} : { $gte: options2.since },
126
+ ...options2.until === void 0 ? {} : { $lte: options2.until }
127
+ };
128
+ const filter = {
129
+ formId,
130
+ ...options2.version === void 0 ? {} : { formVersion: options2.version },
131
+ ...options2.locale === void 0 ? {} : { "submission.locale": options2.locale },
132
+ ...submittedAt === void 0 ? {} : { submittedAt },
133
+ ...cursor === void 0 ? {} : {
134
+ $or: [
135
+ { submittedAt: { $gt: cursor.submittedAt } },
136
+ { submittedAt: cursor.submittedAt, _id: { $gt: cursor.responseId } }
137
+ ]
138
+ }
139
+ };
140
+ const sorted = submissions.find(filter).sort({ submittedAt: 1, _id: 1 });
141
+ const requiresClientFiltering = options2.filter !== void 0 || options2.metadataFilters !== void 0;
142
+ const documents = requiresClientFiltering ? await sorted.toArray() : await sorted.limit(pageSize + 1).toArray();
143
+ const candidates = documents.map(parseSubmissionDocument).filter((item) => (0, import_core.matchesSubmissionPageFilters)(item, options2));
144
+ const hasMore = candidates.length > pageSize;
145
+ const items = candidates.slice(0, pageSize);
146
+ const last = items.at(-1);
147
+ return {
148
+ items,
149
+ hasMore,
150
+ ...hasMore && last !== void 0 ? { nextCursor: (0, import_core.encodeSubmissionCursor)({ submittedAt: last.submittedAt, responseId: last.id }) } : {}
151
+ };
152
+ },
121
153
  async deleteSubmission(submissionId) {
122
154
  await submissions.deleteOne({ _id: submissionId });
123
155
  },
@@ -129,7 +161,7 @@ function createMongoDbStorage(options) {
129
161
  },
130
162
  async createIndexes() {
131
163
  await submissions.createIndexes([
132
- { key: { formId: 1, submittedAt: 1 }, name: "form_responses_form_submitted_at" },
164
+ { key: { formId: 1, submittedAt: 1, _id: 1 }, name: "form_responses_form_submitted_at_id" },
133
165
  { key: { "submission.locale": 1 }, name: "form_responses_locale" }
134
166
  ]);
135
167
  }
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { FormStorageAdapter } from '@form-engine-ts/core';
1
+ import { PagedSubmissionStorageAdapter } from '@form-engine-ts/core';
2
2
  import { Db } from 'mongodb';
3
3
 
4
4
  interface MongoDbStorageOptions {
@@ -6,7 +6,7 @@ interface MongoDbStorageOptions {
6
6
  readonly schemasCollectionName?: string;
7
7
  readonly responsesCollectionName?: string;
8
8
  }
9
- interface MongoDbStorageAdapter extends FormStorageAdapter {
9
+ interface MongoDbStorageAdapter extends PagedSubmissionStorageAdapter {
10
10
  createIndexes(): Promise<void>;
11
11
  }
12
12
  declare function createMongoDbStorage(options: MongoDbStorageOptions): MongoDbStorageAdapter;
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { FormStorageAdapter } from '@form-engine-ts/core';
1
+ import { PagedSubmissionStorageAdapter } from '@form-engine-ts/core';
2
2
  import { Db } from 'mongodb';
3
3
 
4
4
  interface MongoDbStorageOptions {
@@ -6,7 +6,7 @@ interface MongoDbStorageOptions {
6
6
  readonly schemasCollectionName?: string;
7
7
  readonly responsesCollectionName?: string;
8
8
  }
9
- interface MongoDbStorageAdapter extends FormStorageAdapter {
9
+ interface MongoDbStorageAdapter extends PagedSubmissionStorageAdapter {
10
10
  createIndexes(): Promise<void>;
11
11
  }
12
12
  declare function createMongoDbStorage(options: MongoDbStorageOptions): MongoDbStorageAdapter;
package/dist/index.js CHANGED
@@ -1,5 +1,11 @@
1
1
  // src/index.ts
2
- import { assertValidFormSchema } from "@form-engine-ts/core";
2
+ import {
3
+ assertValidFormSchema,
4
+ decodeSubmissionCursor,
5
+ encodeSubmissionCursor,
6
+ matchesSubmissionPageFilters,
7
+ normalizeSubmissionPageSize
8
+ } from "@form-engine-ts/core";
3
9
  function cloneJson(value) {
4
10
  return JSON.parse(JSON.stringify(value));
5
11
  }
@@ -94,6 +100,38 @@ function createMongoDbStorage(options) {
94
100
  }).sort({ submittedAt: 1, _id: 1 }).toArray();
95
101
  return documents.map(parseSubmissionDocument);
96
102
  },
103
+ async listSubmissionPage(formId, options2 = {}) {
104
+ const pageSize = normalizeSubmissionPageSize(options2.pageSize);
105
+ const cursor = options2.cursor === void 0 ? void 0 : decodeSubmissionCursor(options2.cursor);
106
+ const submittedAt = options2.since === void 0 && options2.until === void 0 ? void 0 : {
107
+ ...options2.since === void 0 ? {} : { $gte: options2.since },
108
+ ...options2.until === void 0 ? {} : { $lte: options2.until }
109
+ };
110
+ const filter = {
111
+ formId,
112
+ ...options2.version === void 0 ? {} : { formVersion: options2.version },
113
+ ...options2.locale === void 0 ? {} : { "submission.locale": options2.locale },
114
+ ...submittedAt === void 0 ? {} : { submittedAt },
115
+ ...cursor === void 0 ? {} : {
116
+ $or: [
117
+ { submittedAt: { $gt: cursor.submittedAt } },
118
+ { submittedAt: cursor.submittedAt, _id: { $gt: cursor.responseId } }
119
+ ]
120
+ }
121
+ };
122
+ const sorted = submissions.find(filter).sort({ submittedAt: 1, _id: 1 });
123
+ const requiresClientFiltering = options2.filter !== void 0 || options2.metadataFilters !== void 0;
124
+ const documents = requiresClientFiltering ? await sorted.toArray() : await sorted.limit(pageSize + 1).toArray();
125
+ const candidates = documents.map(parseSubmissionDocument).filter((item) => matchesSubmissionPageFilters(item, options2));
126
+ const hasMore = candidates.length > pageSize;
127
+ const items = candidates.slice(0, pageSize);
128
+ const last = items.at(-1);
129
+ return {
130
+ items,
131
+ hasMore,
132
+ ...hasMore && last !== void 0 ? { nextCursor: encodeSubmissionCursor({ submittedAt: last.submittedAt, responseId: last.id }) } : {}
133
+ };
134
+ },
97
135
  async deleteSubmission(submissionId) {
98
136
  await submissions.deleteOne({ _id: submissionId });
99
137
  },
@@ -105,7 +143,7 @@ function createMongoDbStorage(options) {
105
143
  },
106
144
  async createIndexes() {
107
145
  await submissions.createIndexes([
108
- { key: { formId: 1, submittedAt: 1 }, name: "form_responses_form_submitted_at" },
146
+ { key: { formId: 1, submittedAt: 1, _id: 1 }, name: "form_responses_form_submitted_at_id" },
109
147
  { key: { "submission.locale": 1 }, name: "form_responses_locale" }
110
148
  ]);
111
149
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@form-engine-ts/storage-mongodb",
3
- "version": "2.3.0",
3
+ "version": "2.5.1",
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": "2.3.0"
42
+ "@form-engine-ts/core": "2.5.1"
43
43
  },
44
44
  "peerDependencies": {
45
45
  "mongodb": "^6.0.0"