@sfxcode/nuxt-ui-mongocamp 1.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.
Files changed (67) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +308 -0
  3. package/dist/module.d.mts +8 -0
  4. package/dist/module.json +12 -0
  5. package/dist/module.mjs +35 -0
  6. package/dist/runtime/components/MongocampAccount.d.vue.ts +3 -0
  7. package/dist/runtime/components/MongocampAccount.vue +197 -0
  8. package/dist/runtime/components/MongocampAccount.vue.d.ts +3 -0
  9. package/dist/runtime/components/MongocampCollectionData.d.vue.ts +6 -0
  10. package/dist/runtime/components/MongocampCollectionData.vue +511 -0
  11. package/dist/runtime/components/MongocampCollectionData.vue.d.ts +6 -0
  12. package/dist/runtime/components/MongocampCollectionInfos.d.vue.ts +9 -0
  13. package/dist/runtime/components/MongocampCollectionInfos.vue +393 -0
  14. package/dist/runtime/components/MongocampCollectionInfos.vue.d.ts +9 -0
  15. package/dist/runtime/components/MongocampCollections.d.vue.ts +7 -0
  16. package/dist/runtime/components/MongocampCollections.vue +231 -0
  17. package/dist/runtime/components/MongocampCollections.vue.d.ts +7 -0
  18. package/dist/runtime/components/MongocampDatabases.d.vue.ts +3 -0
  19. package/dist/runtime/components/MongocampDatabases.vue +112 -0
  20. package/dist/runtime/components/MongocampDatabases.vue.d.ts +3 -0
  21. package/dist/runtime/components/MongocampJobs.d.vue.ts +3 -0
  22. package/dist/runtime/components/MongocampJobs.vue +354 -0
  23. package/dist/runtime/components/MongocampJobs.vue.d.ts +3 -0
  24. package/dist/runtime/components/MongocampLogin.d.vue.ts +3 -0
  25. package/dist/runtime/components/MongocampLogin.vue +63 -0
  26. package/dist/runtime/components/MongocampLogin.vue.d.ts +3 -0
  27. package/dist/runtime/components/MongocampRoleGrants.d.vue.ts +6 -0
  28. package/dist/runtime/components/MongocampRoleGrants.vue +276 -0
  29. package/dist/runtime/components/MongocampRoleGrants.vue.d.ts +6 -0
  30. package/dist/runtime/components/MongocampRoles.d.vue.ts +6 -0
  31. package/dist/runtime/components/MongocampRoles.vue +272 -0
  32. package/dist/runtime/components/MongocampRoles.vue.d.ts +6 -0
  33. package/dist/runtime/components/MongocampUsers.d.vue.ts +3 -0
  34. package/dist/runtime/components/MongocampUsers.vue +320 -0
  35. package/dist/runtime/components/MongocampUsers.vue.d.ts +3 -0
  36. package/dist/runtime/components/MongocampVersion.d.vue.ts +3 -0
  37. package/dist/runtime/components/MongocampVersion.vue +25 -0
  38. package/dist/runtime/components/MongocampVersion.vue.d.ts +3 -0
  39. package/dist/runtime/composables/useMongocampAccount.d.ts +7 -0
  40. package/dist/runtime/composables/useMongocampAccount.js +28 -0
  41. package/dist/runtime/composables/useMongocampAdmin.d.ts +14 -0
  42. package/dist/runtime/composables/useMongocampAdmin.js +48 -0
  43. package/dist/runtime/composables/useMongocampBucket.d.ts +15 -0
  44. package/dist/runtime/composables/useMongocampBucket.js +109 -0
  45. package/dist/runtime/composables/useMongocampCollection.d.ts +17 -0
  46. package/dist/runtime/composables/useMongocampCollection.js +12 -0
  47. package/dist/runtime/composables/useMongocampDocument.d.ts +13 -0
  48. package/dist/runtime/composables/useMongocampDocument.js +18 -0
  49. package/dist/runtime/composables/useMongocampDynamicForm.d.ts +14 -0
  50. package/dist/runtime/composables/useMongocampDynamicForm.js +231 -0
  51. package/dist/runtime/composables/useMongocampIndex.d.ts +9 -0
  52. package/dist/runtime/composables/useMongocampIndex.js +23 -0
  53. package/dist/runtime/composables/useMongocampJobs.d.ts +9 -0
  54. package/dist/runtime/composables/useMongocampJobs.js +25 -0
  55. package/dist/runtime/composables/useMongocampQuery.d.ts +99 -0
  56. package/dist/runtime/composables/useMongocampQuery.js +108 -0
  57. package/dist/runtime/composables/useMongocampQueryBuilder.d.ts +30 -0
  58. package/dist/runtime/composables/useMongocampQueryBuilder.js +112 -0
  59. package/dist/runtime/composables/useMongocampSchema.d.ts +14 -0
  60. package/dist/runtime/composables/useMongocampSchema.js +142 -0
  61. package/dist/runtime/composables/useMongocampSystem.d.ts +12 -0
  62. package/dist/runtime/composables/useMongocampSystem.js +21 -0
  63. package/dist/runtime/plugin.d.ts +6 -0
  64. package/dist/runtime/plugin.js +23 -0
  65. package/dist/runtime/server/tsconfig.json +3 -0
  66. package/dist/types.d.mts +3 -0
  67. package/package.json +99 -0
@@ -0,0 +1,231 @@
1
+ import { parseAbsoluteToLocal } from "@internationalized/date";
2
+ const SCALAR_FORMKIT_TYPES = {
3
+ "string": "nuxtUIInput",
4
+ "number": "nuxtUIInputNumber",
5
+ "boolean": "nuxtUISwitch",
6
+ "date-time": "nuxtUIInputDate"
7
+ };
8
+ function scalarNode(column, formkitType) {
9
+ const node = {
10
+ $formkit: formkitType,
11
+ name: column.columnKey,
12
+ label: column.columnName
13
+ };
14
+ if (column.required) {
15
+ node.validation = "required";
16
+ }
17
+ return node;
18
+ }
19
+ function groupNode(column) {
20
+ return {
21
+ $formkit: "group",
22
+ name: column.columnKey,
23
+ label: column.columnName,
24
+ children: columnsToFormKitSchema(column.children ?? [])
25
+ };
26
+ }
27
+ function wrapGroup(node) {
28
+ return {
29
+ $el: "div",
30
+ attrs: { class: "pt-4 flex flex-col gap-3" },
31
+ children: [node]
32
+ };
33
+ }
34
+ function scalarArrayNode(column) {
35
+ const node = {
36
+ $formkit: "nuxtUIInputTags",
37
+ name: column.columnKey,
38
+ label: column.columnName
39
+ };
40
+ if (column.required) {
41
+ node.validation = "required";
42
+ }
43
+ return node;
44
+ }
45
+ function defaultScalarValue(formkitType) {
46
+ if (formkitType === "nuxtUIInputNumber") return 0;
47
+ if (formkitType === "nuxtUISwitch") return false;
48
+ return "";
49
+ }
50
+ function defaultValueForColumn(column) {
51
+ if (column.columnType === "object") return defaultObjectValue(column.children ?? []);
52
+ if (column.columnType === "array") return [];
53
+ const formkitType = SCALAR_FORMKIT_TYPES[column.columnType];
54
+ return formkitType ? defaultScalarValue(formkitType) : "";
55
+ }
56
+ function defaultObjectValue(children) {
57
+ const value = {};
58
+ children.forEach((child) => {
59
+ value[child.columnKey] = defaultValueForColumn(child);
60
+ });
61
+ return value;
62
+ }
63
+ const REPEATER_BUTTON_PROPS = {
64
+ alwaysDisplayInsertButton: true,
65
+ displayAddButton: true,
66
+ displayCloneButton: true,
67
+ displayDeleteButton: true
68
+ };
69
+ const REPEATER_LAYOUT_PROPS = {
70
+ listClass: "flex flex-col gap-3",
71
+ listItemClass: "flex flex-wrap items-end gap-3 p-3 border border-gray-100 dark:border-gray-800 rounded-lg shadow-sm",
72
+ buttonGroupClass: "flex items-center gap-1 ml-auto",
73
+ displayDragHandle: true,
74
+ draggable: true,
75
+ hideMoveButtons: true,
76
+ dragHandleClass: "cursor-grab active:cursor-grabbing text-dimmed"
77
+ };
78
+ function repeaterArrayNode(column, itemFormkitType) {
79
+ const node = {
80
+ $formkit: "nuxtUIRepeater",
81
+ name: column.columnKey,
82
+ label: column.columnName,
83
+ newItem: { value: defaultScalarValue(itemFormkitType) },
84
+ ...REPEATER_BUTTON_PROPS,
85
+ ...REPEATER_LAYOUT_PROPS,
86
+ children: [
87
+ { $formkit: itemFormkitType, name: "value", label: "Value" }
88
+ ]
89
+ };
90
+ if (column.required) {
91
+ node.validation = "required";
92
+ }
93
+ return node;
94
+ }
95
+ function objectArrayNode(column) {
96
+ const node = {
97
+ $formkit: "nuxtUIRepeater",
98
+ name: column.columnKey,
99
+ label: column.columnName,
100
+ newItem: defaultObjectValue(column.children ?? []),
101
+ ...REPEATER_BUTTON_PROPS,
102
+ ...REPEATER_LAYOUT_PROPS,
103
+ children: columnsToFormKitSchema(column.children ?? [])
104
+ };
105
+ if (column.required) {
106
+ node.validation = "required";
107
+ }
108
+ return node;
109
+ }
110
+ function arrayNode(column) {
111
+ if (column.arrayItemType === "object") {
112
+ return objectArrayNode(column);
113
+ }
114
+ if (column.arrayItemType === "string" || column.arrayItemType === "unknown") {
115
+ return scalarArrayNode(column);
116
+ }
117
+ const itemFormkitType = column.arrayItemType ? SCALAR_FORMKIT_TYPES[column.arrayItemType] : void 0;
118
+ if (itemFormkitType) {
119
+ return repeaterArrayNode(column, itemFormkitType);
120
+ }
121
+ return void 0;
122
+ }
123
+ export function columnsToFormKitSchema(columns) {
124
+ const schema = [];
125
+ columns.forEach((column) => {
126
+ if (column.columnType === "object") {
127
+ schema.push(wrapGroup(groupNode(column)));
128
+ return;
129
+ }
130
+ if (column.columnType === "array") {
131
+ const node = arrayNode(column);
132
+ if (node) schema.push(node);
133
+ return;
134
+ }
135
+ const formkitType = SCALAR_FORMKIT_TYPES[column.columnType];
136
+ if (formkitType) {
137
+ schema.push(scalarNode(column, formkitType));
138
+ }
139
+ });
140
+ return schema;
141
+ }
142
+ function isPlainObject(value) {
143
+ return typeof value === "object" && value !== null && !Array.isArray(value);
144
+ }
145
+ function unwrapOid(raw) {
146
+ if (isPlainObject(raw) && typeof raw.$oid === "string") return raw.$oid;
147
+ return raw;
148
+ }
149
+ const NUMBER_WRAPPER_KEYS = ["$numberInt", "$numberLong", "$numberDouble", "$numberDecimal"];
150
+ function unwrapNumber(raw) {
151
+ if (!isPlainObject(raw)) return raw;
152
+ for (const key of NUMBER_WRAPPER_KEYS) {
153
+ const wrapped = raw[key];
154
+ if (typeof wrapped === "string" || typeof wrapped === "number") {
155
+ const parsed = Number(wrapped);
156
+ if (!Number.isNaN(parsed)) return parsed;
157
+ }
158
+ }
159
+ return raw;
160
+ }
161
+ function unwrapDateTime(raw) {
162
+ if (!isPlainObject(raw) || !("$date" in raw)) return raw;
163
+ const inner = raw.$date;
164
+ if (typeof inner === "string" || typeof inner === "number") {
165
+ return new Date(inner).toISOString();
166
+ }
167
+ if (isPlainObject(inner) && typeof inner.$numberLong === "string") {
168
+ return new Date(Number(inner.$numberLong)).toISOString();
169
+ }
170
+ return raw;
171
+ }
172
+ function toZonedDateTime(value) {
173
+ if (typeof value !== "string") return value;
174
+ try {
175
+ return parseAbsoluteToLocal(value);
176
+ } catch {
177
+ return value;
178
+ }
179
+ }
180
+ function isZonedDateTimeLike(value) {
181
+ return typeof value === "object" && value !== null && typeof value.toAbsoluteString === "function";
182
+ }
183
+ export function documentToFormData(doc, columns) {
184
+ const formData = {};
185
+ columns.forEach((column) => {
186
+ if (!(column.columnKey in doc)) return;
187
+ const raw = doc[column.columnKey];
188
+ if (column.columnType === "object") {
189
+ if (isPlainObject(raw)) {
190
+ formData[column.columnKey] = documentToFormData(raw, column.children ?? []);
191
+ }
192
+ return;
193
+ }
194
+ if (column.columnType === "array") {
195
+ if (!Array.isArray(raw)) return;
196
+ formData[column.columnKey] = column.arrayItemType === "object" ? raw.map((item) => isPlainObject(item) ? documentToFormData(item, column.children ?? []) : item) : raw;
197
+ return;
198
+ }
199
+ if (column.columnType === "date-time") {
200
+ formData[column.columnKey] = toZonedDateTime(unwrapDateTime(raw));
201
+ } else if (column.columnType === "string") {
202
+ formData[column.columnKey] = unwrapOid(raw);
203
+ } else if (column.columnType === "number") {
204
+ formData[column.columnKey] = unwrapNumber(raw);
205
+ } else {
206
+ formData[column.columnKey] = raw;
207
+ }
208
+ });
209
+ return formData;
210
+ }
211
+ function wasOriginallyOid(originalValue) {
212
+ return isPlainObject(originalValue) && typeof originalValue.$oid === "string";
213
+ }
214
+ export function formDataToDocument(formData, columns, originalDoc) {
215
+ const result = originalDoc ? { ...originalDoc } : {};
216
+ columns.forEach((column) => {
217
+ if (!(column.columnKey in formData)) return;
218
+ const value = formData[column.columnKey];
219
+ if (column.columnType === "date-time" && isZonedDateTimeLike(value)) {
220
+ result[column.columnKey] = { $date: value.toAbsoluteString() };
221
+ } else if (column.columnType === "date-time" && typeof value === "string") {
222
+ result[column.columnKey] = { $date: value };
223
+ } else if (column.columnType === "string" && wasOriginallyOid(originalDoc?.[column.columnKey])) {
224
+ result[column.columnKey] = { $oid: value };
225
+ } else {
226
+ result[column.columnKey] = value;
227
+ }
228
+ });
229
+ delete result._id;
230
+ return result;
231
+ }
@@ -0,0 +1,9 @@
1
+ import type { IndexCreateResponse, IndexDropResponse, IndexOptionsRequest, MongoIndex } from '@sfxcode/nuxt-mongocamp-server';
2
+ export declare function useMongocampIndex(): {
3
+ listIndexes: (collectionName: string) => Promise<MongoIndex[]>;
4
+ createIndex: (collectionName: string, keys: Record<string, number>, options?: IndexOptionsRequest) => Promise<IndexCreateResponse>;
5
+ createUniqueIndex: (collectionName: string, fieldName: string, sortAscending?: boolean) => Promise<IndexCreateResponse>;
6
+ createTextIndex: (collectionName: string, fieldName: string) => Promise<IndexCreateResponse>;
7
+ createExpiringIndex: (collectionName: string, fieldName: string, duration: string) => Promise<IndexCreateResponse>;
8
+ deleteIndex: (collectionName: string, indexName: string) => Promise<IndexDropResponse>;
9
+ };
@@ -0,0 +1,23 @@
1
+ import { useMongocampApi } from "#imports";
2
+ export function useMongocampIndex() {
3
+ const { indexApi } = useMongocampApi();
4
+ async function listIndexes(collectionName) {
5
+ return indexApi.listIndices({ collectionName });
6
+ }
7
+ async function createIndex(collectionName, keys, options) {
8
+ return indexApi.createIndex({ collectionName, indexCreateRequest: { keys, indexOptionsRequest: options } });
9
+ }
10
+ async function createUniqueIndex(collectionName, fieldName, sortAscending) {
11
+ return indexApi.createUniqueIndex({ collectionName, fieldName, sortAscending });
12
+ }
13
+ async function createTextIndex(collectionName, fieldName) {
14
+ return indexApi.createTextIndex({ collectionName, fieldName });
15
+ }
16
+ async function createExpiringIndex(collectionName, fieldName, duration) {
17
+ return indexApi.createExpiringIndex({ collectionName, fieldName, duration });
18
+ }
19
+ async function deleteIndex(collectionName, indexName) {
20
+ return indexApi.deleteIndex({ collectionName, indexName });
21
+ }
22
+ return { listIndexes, createIndex, createUniqueIndex, createTextIndex, createExpiringIndex, deleteIndex };
23
+ }
@@ -0,0 +1,9 @@
1
+ import type { JobConfig, JobInformation } from '@sfxcode/nuxt-mongocamp-server';
2
+ export declare function useMongocampJobs(): {
3
+ listJobs: () => Promise<JobInformation[]>;
4
+ listPossibleJobs: () => Promise<string[]>;
5
+ registerJob: (jobConfig: JobConfig) => Promise<JobInformation>;
6
+ updateJob: (jobGroup: string, jobName: string, jobConfig: JobConfig) => Promise<JobInformation>;
7
+ executeJob: (jobGroup: string, jobName: string) => Promise<boolean>;
8
+ deleteJob: (jobGroup: string, jobName: string) => Promise<boolean>;
9
+ };
@@ -0,0 +1,25 @@
1
+ import { useMongocampApi } from "#imports";
2
+ export function useMongocampJobs() {
3
+ const { jobApi } = useMongocampApi();
4
+ async function listJobs() {
5
+ return jobApi.jobsList();
6
+ }
7
+ async function listPossibleJobs() {
8
+ return jobApi.possibleJobsList();
9
+ }
10
+ async function registerJob(jobConfig) {
11
+ return jobApi.registerJob({ jobConfig });
12
+ }
13
+ async function updateJob(jobGroup, jobName, jobConfig) {
14
+ return jobApi.updateJob({ jobGroup, jobName, jobConfig });
15
+ }
16
+ async function executeJob(jobGroup, jobName) {
17
+ const result = await jobApi.executeJob({ jobGroup, jobName });
18
+ return result.value;
19
+ }
20
+ async function deleteJob(jobGroup, jobName) {
21
+ const result = await jobApi.deleteJob({ jobGroup, jobName });
22
+ return result.value;
23
+ }
24
+ return { listJobs, listPossibleJobs, registerJob, updateJob, executeJob, deleteJob };
25
+ }
@@ -0,0 +1,99 @@
1
+ /** Scalar value accepted by all query helpers. `null` and `undefined` produce an empty (no-op) expression. */
2
+ export type QueryValue = string | number | boolean | null | undefined;
3
+ export interface MongocampQueryHelper {
4
+ /** `_exists_:fieldName` — matches documents where the field exists. */
5
+ exists: (fieldName: string) => string;
6
+ /** `-_exists_:fieldName` — matches documents where the field is absent. */
7
+ notExists: (fieldName: string) => string;
8
+ /** Alias for `notExists`. */
9
+ isEmpty: (fieldName: string) => string;
10
+ /** Alias for `exists`. */
11
+ isNotEmpty: (fieldName: string) => string;
12
+ /**
13
+ * `field:"value"` — exact match.
14
+ * Returns `''` when value is `null`, `undefined`, or an empty string.
15
+ */
16
+ equals: (fieldName: string, value: QueryValue) => string;
17
+ /**
18
+ * `-field:"value"` — excluded match.
19
+ * Returns `''` when value is `null`, `undefined`, or an empty string.
20
+ */
21
+ notEquals: (fieldName: string, value: QueryValue) => string;
22
+ /**
23
+ * `field:[from TO to]` — inclusive range.
24
+ * Pass `null` for an open-ended bound: `null` lower → `[* TO to]`, `null` upper → `[from TO *]`.
25
+ */
26
+ inRange: (fieldName: string, from: QueryValue, to: QueryValue) => string;
27
+ /**
28
+ * `-field:[from TO to]` — excluded range.
29
+ * Pass `null` for an open-ended bound (same semantics as `inRange`).
30
+ */
31
+ notInRange: (fieldName: string, from: QueryValue, to: QueryValue) => string;
32
+ /** Alias for `inRange`. */
33
+ between: (fieldName: string, from: QueryValue, to: QueryValue) => string;
34
+ /**
35
+ * `field:*value*` — contains substring (leading and trailing wildcard).
36
+ * Falls back to `field:*` when value is `null` or empty.
37
+ */
38
+ like: (fieldName: string, value: QueryValue) => string;
39
+ /** `-field:*value*` — does not contain substring. */
40
+ notLike: (fieldName: string, value: QueryValue) => string;
41
+ /**
42
+ * `field:value*` — prefix match.
43
+ * Falls back to `field:*` when value is `null` or empty.
44
+ */
45
+ startsWith: (fieldName: string, value: QueryValue) => string;
46
+ /** `-field:value*` — not a prefix match. */
47
+ notStartsWith: (fieldName: string, value: QueryValue) => string;
48
+ /**
49
+ * `field:*value` — suffix match (leading wildcard).
50
+ * Falls back to `field:*` when value is `null` or empty.
51
+ */
52
+ endsWith: (fieldName: string, value: QueryValue) => string;
53
+ /** `-field:*value` — not a suffix match. */
54
+ notEndsWith: (fieldName: string, value: QueryValue) => string;
55
+ /**
56
+ * `field:("v1" OR "v2" ...)` — matches any one of the values (OR semantics).
57
+ * Numbers are left unquoted; strings are quoted and escaped.
58
+ * Returns `''` for an empty array.
59
+ */
60
+ inClause: (fieldName: string, parameter: QueryValue[]) => string;
61
+ /**
62
+ * `-field:"v1" AND -field:"v2" ...` — excludes all listed values (AND of negations).
63
+ * Returns `''` for an empty array.
64
+ */
65
+ notInClause: (fieldName: string, parameter: QueryValue[]) => string;
66
+ /**
67
+ * `(field:"v1" AND field:"v2" ...)` — all values must match (AND semantics).
68
+ * Returns `''` for an empty array.
69
+ */
70
+ containsAll: (fieldName: string, parameter: QueryValue[]) => string;
71
+ /**
72
+ * Joins non-empty parts with `AND`, wrapping the result in `()`.
73
+ * Filters out `null`, `undefined`, and empty-string parts automatically.
74
+ * A single surviving part is returned unwrapped (no outer parens).
75
+ */
76
+ and: (...queryParts: (string | null | undefined)[]) => string;
77
+ /**
78
+ * Joins non-empty parts with `OR`, wrapping the result in `()`.
79
+ * Filters out `null`, `undefined`, and empty-string parts automatically.
80
+ * A single surviving part is returned unwrapped (no outer parens).
81
+ */
82
+ or: (...queryParts: (string | null | undefined)[]) => string;
83
+ }
84
+ /**
85
+ * High-level Lucene query helpers for MongoCamp collection filters.
86
+ *
87
+ * All helpers return a Lucene expression string. A return value of `''` means "no filter"
88
+ * and is safe to pass directly to `and`/`or` — they filter it out automatically.
89
+ *
90
+ * @example
91
+ * const h = useMongocampQuery()
92
+ * h.and(
93
+ * h.or(h.like('name', 'alice'), h.like('email', 'alice')),
94
+ * h.inClause('role', ['admin', 'user']),
95
+ * h.between('createdAt', '2024-01-01', null),
96
+ * )
97
+ * // => '((name:*alice* OR email:*alice*) AND role:("admin" OR "user") AND createdAt:[2024-01-01 TO *])'
98
+ */
99
+ export declare function useMongocampQuery(): MongocampQueryHelper;
@@ -0,0 +1,108 @@
1
+ import { useMongocampQueryBuilder } from "./useMongocampQueryBuilder.js";
2
+ export function useMongocampQuery() {
3
+ const { q } = useMongocampQueryBuilder();
4
+ function exists(fieldName) {
5
+ return q.field("_exists_", q.phrase(fieldName));
6
+ }
7
+ function notExists(fieldName) {
8
+ return `-${exists(fieldName)}`;
9
+ }
10
+ function isEmpty(fieldName) {
11
+ return notExists(fieldName);
12
+ }
13
+ function isNotEmpty(fieldName) {
14
+ return exists(fieldName);
15
+ }
16
+ function equals(fieldName, value) {
17
+ if (value == null || value.toString().length === 0) return "";
18
+ return q.field(fieldName, q.terms(value.toString()));
19
+ }
20
+ function notEquals(fieldName, value) {
21
+ const expr = equals(fieldName, value);
22
+ return expr ? `-${expr}` : "";
23
+ }
24
+ function inRange(fieldName, from, to) {
25
+ const fromStr = from != null ? from.toString() : "*";
26
+ const toStr = to != null ? to.toString() : "*";
27
+ return q.field(fieldName, q.range(fromStr, toStr));
28
+ }
29
+ function notInRange(fieldName, from, to) {
30
+ return `-${inRange(fieldName, from, to)}`;
31
+ }
32
+ function between(fieldName, from, to) {
33
+ return inRange(fieldName, from, to);
34
+ }
35
+ function like(fieldName, value) {
36
+ const term = value != null && value.toString().length !== 0 ? q.phrase(`*${value}*`) : "*";
37
+ return q.field(fieldName, term);
38
+ }
39
+ function notLike(fieldName, value) {
40
+ return `-${like(fieldName, value)}`;
41
+ }
42
+ function startsWith(fieldName, value) {
43
+ const term = value != null && value.toString().length !== 0 ? q.phrase(`${value}*`) : "*";
44
+ return q.field(fieldName, term);
45
+ }
46
+ function notStartsWith(fieldName, value) {
47
+ return `-${startsWith(fieldName, value)}`;
48
+ }
49
+ function endsWith(fieldName, value) {
50
+ const term = value != null && value.toString().length !== 0 ? q.phrase(`*${value}`) : "*";
51
+ return q.field(fieldName, term);
52
+ }
53
+ function notEndsWith(fieldName, value) {
54
+ return `-${endsWith(fieldName, value)}`;
55
+ }
56
+ function toTerms(value) {
57
+ if (typeof value === "number") return String(value);
58
+ return q.terms(String(value ?? ""));
59
+ }
60
+ function inClause(fieldName, parameter) {
61
+ if (parameter.length === 0) return "";
62
+ const fields = parameter.map(toTerms);
63
+ const inner = fields.length === 1 ? fields[0] : `(${fields.join(" OR ")})`;
64
+ return q.field(fieldName, inner);
65
+ }
66
+ function notInClause(fieldName, parameter) {
67
+ if (parameter.length === 0) return "";
68
+ return and(...parameter.map((v) => notEquals(fieldName, v)));
69
+ }
70
+ function containsAll(fieldName, parameter) {
71
+ if (parameter.length === 0) return "";
72
+ return and(...parameter.map((v) => equals(fieldName, v)));
73
+ }
74
+ function logicalOperators(operator, queryParts) {
75
+ const parts = queryParts.filter((x) => x != null && x.length > 0 && x !== "()");
76
+ if (parts.length === 0) return "";
77
+ if (parts.length === 1) return parts[0];
78
+ return "(" + parts.map((x) => x.startsWith("-") ? `(${x})` : x).join(` ${operator} `) + ")";
79
+ }
80
+ function and(...queryParts) {
81
+ return logicalOperators("AND", queryParts);
82
+ }
83
+ function or(...queryParts) {
84
+ return logicalOperators("OR", queryParts);
85
+ }
86
+ return {
87
+ exists,
88
+ notExists,
89
+ isEmpty,
90
+ isNotEmpty,
91
+ equals,
92
+ notEquals,
93
+ inRange,
94
+ notInRange,
95
+ between,
96
+ like,
97
+ notLike,
98
+ startsWith,
99
+ notStartsWith,
100
+ endsWith,
101
+ notEndsWith,
102
+ inClause,
103
+ notInClause,
104
+ containsAll,
105
+ and,
106
+ or
107
+ };
108
+ }
@@ -0,0 +1,30 @@
1
+ declare class QueryBuilder {
2
+ private parts;
3
+ constructor(...initial: string[]);
4
+ field(name: string, value: string): this;
5
+ /** No args: insert AND connector. With args: join expressions with AND. */
6
+ and(...exprs: string[]): this;
7
+ /** No args: insert OR connector. With args: join expressions with OR. */
8
+ or(...exprs: string[]): this;
9
+ not(expr: string): this;
10
+ group(inner: string | QueryBuilder): this;
11
+ raw(expr: string): this;
12
+ build(): string;
13
+ toString(): string;
14
+ }
15
+ export declare function useMongocampQueryBuilder(): {
16
+ q: {
17
+ terms: (value: string) => string;
18
+ phrase: (value: string) => string;
19
+ wildcard: (pattern: string) => string;
20
+ fuzzy: (term: string, similarity?: number) => string;
21
+ proximity: (first: string, second: string, distance: number) => string;
22
+ range: (from: string, to: string, includeLeft?: boolean, includeRight?: boolean) => string;
23
+ boost: (term: string, factor: number) => string;
24
+ required: (term: string) => string;
25
+ not: (term: string) => string;
26
+ field: (name: string, value: string) => string;
27
+ };
28
+ Q: (...initial: string[]) => QueryBuilder;
29
+ };
30
+ export {};
@@ -0,0 +1,112 @@
1
+ const SPECIAL_CHARS = /* @__PURE__ */ new Set([
2
+ "+",
3
+ "-",
4
+ "&",
5
+ "|",
6
+ "!",
7
+ "(",
8
+ ")",
9
+ "{",
10
+ "}",
11
+ "[",
12
+ "]",
13
+ "^",
14
+ '"',
15
+ "~",
16
+ ":",
17
+ "\\",
18
+ "/",
19
+ " "
20
+ ]);
21
+ function escape(value, wildcards = false) {
22
+ return [...value].map((char) => {
23
+ if (SPECIAL_CHARS.has(char)) return `\\${char}`;
24
+ if (!wildcards && (char === "*" || char === "?")) return `\\${char}`;
25
+ return char;
26
+ }).join("");
27
+ }
28
+ class QueryBuilder {
29
+ parts;
30
+ constructor(...initial) {
31
+ this.parts = initial.filter(Boolean);
32
+ }
33
+ field(name, value) {
34
+ this.parts.push(`${name}:${value}`);
35
+ return this;
36
+ }
37
+ /** No args: insert AND connector. With args: join expressions with AND. */
38
+ and(...exprs) {
39
+ if (exprs.length === 0) {
40
+ this.parts.push("AND");
41
+ } else {
42
+ this.parts.push(exprs.join(" AND "));
43
+ }
44
+ return this;
45
+ }
46
+ /** No args: insert OR connector. With args: join expressions with OR. */
47
+ or(...exprs) {
48
+ if (exprs.length === 0) {
49
+ this.parts.push("OR");
50
+ } else {
51
+ this.parts.push(exprs.join(" OR "));
52
+ }
53
+ return this;
54
+ }
55
+ not(expr) {
56
+ this.parts.push(`NOT ${expr}`);
57
+ return this;
58
+ }
59
+ group(inner) {
60
+ const str = typeof inner === "string" ? inner : inner.build();
61
+ this.parts.push(`(${str})`);
62
+ return this;
63
+ }
64
+ raw(expr) {
65
+ this.parts.push(expr);
66
+ return this;
67
+ }
68
+ build() {
69
+ return this.parts.join(" ");
70
+ }
71
+ toString() {
72
+ return this.build();
73
+ }
74
+ }
75
+ export function useMongocampQueryBuilder() {
76
+ function terms(value) {
77
+ if (/^-\d+$/.test(value)) return `"${value}"`;
78
+ return `"${escape(value)}"`;
79
+ }
80
+ function phrase(value) {
81
+ return escape(value, true);
82
+ }
83
+ function wildcard(pattern) {
84
+ return escape(pattern, true);
85
+ }
86
+ function fuzzy(term, similarity) {
87
+ return similarity !== void 0 ? `${term}~${similarity}` : `${term}~`;
88
+ }
89
+ function proximity(first, second, distance) {
90
+ return `"${first} ${second}"~${distance}`;
91
+ }
92
+ function range(from, to, includeLeft = true, includeRight = true) {
93
+ return `${includeLeft ? "[" : "{"}${from} TO ${to}${includeRight ? "]" : "}"}`;
94
+ }
95
+ function boost(term, factor) {
96
+ return `${term}^${factor}`;
97
+ }
98
+ function required(term) {
99
+ return `+${term}`;
100
+ }
101
+ function not(term) {
102
+ return `NOT ${term}`;
103
+ }
104
+ function field(name, value) {
105
+ return `${name}:${value}`;
106
+ }
107
+ const q = { terms, phrase, wildcard, fuzzy, proximity, range, boost, required, not, field };
108
+ function Q(...initial) {
109
+ return new QueryBuilder(...initial);
110
+ }
111
+ return { q, Q };
112
+ }
@@ -0,0 +1,14 @@
1
+ export interface ColumnDefinition {
2
+ columnName: string;
3
+ columnKey: string;
4
+ columnType: string;
5
+ required: boolean;
6
+ /** For columnType === 'array': the inferred type of the array elements */
7
+ arrayItemType?: string;
8
+ /** For columnType === 'object', or 'array' with arrayItemType === 'object': the inferred nested fields */
9
+ children?: ColumnDefinition[];
10
+ }
11
+ export declare function useMongocampSchema(): {
12
+ schemaFromSamples: (records: Array<Record<string, unknown>>) => ColumnDefinition[];
13
+ schemaToTsInterface: (columns: ColumnDefinition[], interfaceName: string) => string;
14
+ };