flongo 1.2.0 → 1.4.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.
@@ -130,7 +130,7 @@ export declare class FlongoCollection<T> {
130
130
  * @param attributes - Array of document data
131
131
  * @param clientId - Optional client ID for audit trail
132
132
  */
133
- batchCreate(attributes: T[], clientId?: string): Promise<void>;
133
+ batchCreate(attributes: T[], clientId?: string): Promise<string[]>;
134
134
  /**
135
135
  * Updates multiple documents matching the query
136
136
  * @param attributes - Fields to update
@@ -158,29 +158,33 @@ export declare class FlongoCollection<T> {
158
158
  * @param id - Document ID
159
159
  * @param key - Field name to increment
160
160
  * @param amt - Amount to increment by (defaults to 1)
161
+ * @param clientId - Optional client ID for audit trail
161
162
  */
162
- increment(id: string, key: string, amt?: number): Promise<void>;
163
+ increment(id: string, key: string, amt?: number, clientId?: string): Promise<void>;
163
164
  /**
164
165
  * Atomically decrements a numeric field
165
166
  * @param id - Document ID
166
167
  * @param key - Field name to decrement
167
168
  * @param amt - Amount to decrement by (defaults to 1)
169
+ * @param clientId - Optional client ID for audit trail
168
170
  */
169
- decrement(id: string, key: string, amt?: number): Promise<void>;
171
+ decrement(id: string, key: string, amt?: number, clientId?: string): Promise<void>;
170
172
  /**
171
173
  * Atomically appends items to an array field
172
174
  * @param id - Document ID
173
175
  * @param key - Array field name
174
176
  * @param items - Items to append to the array
177
+ * @param clientId - Optional client ID for audit trail
175
178
  */
176
- append(id: string, key: string, items: any[]): Promise<void>;
179
+ append(id: string, key: string, items: any[], clientId?: string): Promise<void>;
177
180
  /**
178
181
  * Atomically removes items from an array field
179
182
  * @param id - Document ID
180
183
  * @param key - Array field name
181
184
  * @param items - Items to remove from the array
185
+ * @param clientId - Optional client ID for audit trail
182
186
  */
183
- arrRemove(id: string, key: string, items: any[]): Promise<void>;
187
+ arrRemove(id: string, key: string, items: any[], clientId?: string): Promise<void>;
184
188
  /**
185
189
  * Logs an event to the events collection for audit trails
186
190
  * Events are only logged if event logging is enabled in options
@@ -210,6 +210,7 @@ class FlongoCollection {
210
210
  // Insert document with automatic timestamps
211
211
  const created = await this.collection.insertOne({
212
212
  ...attributes,
213
+ createdBy: clientId,
213
214
  createdAt: Date.now(),
214
215
  updatedAt: Date.now()
215
216
  });
@@ -236,22 +237,24 @@ class FlongoCollection {
236
237
  */
237
238
  async batchCreate(attributes, clientId) {
238
239
  if (attributes.length === 0)
239
- return;
240
+ return [];
240
241
  const now = Date.now();
241
242
  // Prepare entities with timestamps
242
243
  const entities = attributes.map((attribute) => ({
243
244
  ...attribute,
245
+ createdBy: clientId,
244
246
  createdAt: now,
245
247
  updatedAt: now
246
248
  }));
247
249
  // Insert all entities at once
248
- await this.collection.insertMany(entities);
250
+ const result = await this.collection.insertMany(entities);
249
251
  // Log batch creation event
250
252
  this.logEvent({
251
253
  name: types_1.EventName.BatchCreateEntities,
252
254
  identity: clientId,
253
255
  value: { collectionType: this.name, count: await this.count() }
254
256
  });
257
+ return Object.values(result.insertedIds).map((id) => id.toString());
255
258
  }
256
259
  // ===========================================
257
260
  // UPDATE OPERATIONS
@@ -268,6 +271,7 @@ class FlongoCollection {
268
271
  await this.collection.updateMany(mongodbQuery, {
269
272
  $set: {
270
273
  updatedAt: Date.now(),
274
+ updatedBy: clientId,
271
275
  ...attributes
272
276
  }
273
277
  });
@@ -294,6 +298,7 @@ class FlongoCollection {
294
298
  await this.collection.updateOne({ _id: new mongodb_1.ObjectId(id) }, {
295
299
  $set: {
296
300
  updatedAt: Date.now(),
301
+ updatedBy: clientId,
297
302
  ...attributes
298
303
  }
299
304
  });
@@ -321,6 +326,7 @@ class FlongoCollection {
321
326
  const update = {
322
327
  $set: {
323
328
  updatedAt: Date.now(),
329
+ updatedBy: clientId,
324
330
  ...attributes
325
331
  }
326
332
  };
@@ -340,29 +346,38 @@ class FlongoCollection {
340
346
  * @param id - Document ID
341
347
  * @param key - Field name to increment
342
348
  * @param amt - Amount to increment by (defaults to 1)
349
+ * @param clientId - Optional client ID for audit trail
343
350
  */
344
- async increment(id, key, amt) {
345
- const inc = { $inc: { [key]: amt || 1 } };
346
- await this.collection.updateOne({ _id: new mongodb_1.ObjectId(id) }, inc);
351
+ async increment(id, key, amt, clientId) {
352
+ await this.collection.updateOne({ _id: new mongodb_1.ObjectId(id) }, {
353
+ $inc: { [key]: amt || 1 },
354
+ $set: { updatedAt: Date.now(), updatedBy: clientId }
355
+ });
347
356
  }
348
357
  /**
349
358
  * Atomically decrements a numeric field
350
359
  * @param id - Document ID
351
360
  * @param key - Field name to decrement
352
361
  * @param amt - Amount to decrement by (defaults to 1)
362
+ * @param clientId - Optional client ID for audit trail
353
363
  */
354
- async decrement(id, key, amt) {
355
- await this.collection.updateOne({ _id: new mongodb_1.ObjectId(id) }, { $inc: { [key]: -(amt ?? 1) } });
364
+ async decrement(id, key, amt, clientId) {
365
+ await this.collection.updateOne({ _id: new mongodb_1.ObjectId(id) }, {
366
+ $inc: { [key]: -(amt ?? 1) },
367
+ $set: { updatedAt: Date.now(), updatedBy: clientId }
368
+ });
356
369
  }
357
370
  /**
358
371
  * Atomically appends items to an array field
359
372
  * @param id - Document ID
360
373
  * @param key - Array field name
361
374
  * @param items - Items to append to the array
375
+ * @param clientId - Optional client ID for audit trail
362
376
  */
363
- async append(id, key, items) {
377
+ async append(id, key, items, clientId) {
364
378
  await this.collection.updateOne({ _id: new mongodb_1.ObjectId(id) }, {
365
- $push: { [key]: { $each: items } }
379
+ $push: { [key]: { $each: items } },
380
+ $set: { updatedAt: Date.now(), updatedBy: clientId }
366
381
  });
367
382
  }
368
383
  /**
@@ -370,9 +385,13 @@ class FlongoCollection {
370
385
  * @param id - Document ID
371
386
  * @param key - Array field name
372
387
  * @param items - Items to remove from the array
388
+ * @param clientId - Optional client ID for audit trail
373
389
  */
374
- async arrRemove(id, key, items) {
375
- await this.collection.updateOne({ _id: new mongodb_1.ObjectId(id) }, { $pull: { [key]: { $in: items } } });
390
+ async arrRemove(id, key, items, clientId) {
391
+ await this.collection.updateOne({ _id: new mongodb_1.ObjectId(id) }, {
392
+ $pull: { [key]: { $in: items } },
393
+ $set: { updatedAt: Date.now(), updatedBy: clientId }
394
+ });
376
395
  }
377
396
  // ===========================================
378
397
  // EVENT LOGGING
@@ -0,0 +1,9 @@
1
+ import { Db, MongoClient } from "mongodb";
2
+ export declare let mongoClient: MongoClient;
3
+ export declare let mongoDb: Db;
4
+ export interface MongoConfig {
5
+ connectionString: string;
6
+ dbName: string;
7
+ }
8
+ export declare function initializeMongo(config: MongoConfig): void;
9
+ //# sourceMappingURL=mongo.d.ts.map
package/dist/mongo.js ADDED
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.mongoDb = exports.mongoClient = void 0;
4
+ exports.initializeMongo = initializeMongo;
5
+ const mongodb_1 = require("mongodb");
6
+ function initializeMongo(config) {
7
+ exports.mongoClient = new mongodb_1.MongoClient(config.connectionString);
8
+ exports.mongoDb = exports.mongoClient.db(config.dbName);
9
+ }
10
+ //# sourceMappingURL=mongo.js.map
@@ -0,0 +1,33 @@
1
+ import { MongoCollectionQuery } from "./mongoCollectionQuery";
2
+ import { Entity, Event, EventName, Pagination, Repository } from "./types";
3
+ export interface MongoCollectionOptions {
4
+ enableEventLogging?: boolean;
5
+ eventsCollectionName?: string;
6
+ }
7
+ export declare class MongoCollection<T> {
8
+ private collection;
9
+ private events;
10
+ private name;
11
+ private options;
12
+ constructor(collectionName: Repository, options?: MongoCollectionOptions);
13
+ get(id: string): Promise<Entity & T>;
14
+ private toEntity;
15
+ getAll(query?: MongoCollectionQuery, pagination?: Pagination): Promise<(Entity & T)[]>;
16
+ getSome(query: MongoCollectionQuery, pagination: Pagination): Promise<(Entity & T)[]>;
17
+ getFirst(query: MongoCollectionQuery): Promise<Entity & T>;
18
+ count(query?: MongoCollectionQuery): Promise<number>;
19
+ delete(id: string, clientId: string): Promise<void>;
20
+ batchDelete(ids: string[], clientId: string): Promise<void>;
21
+ exists(query: MongoCollectionQuery): Promise<boolean>;
22
+ logEvent<T extends EventName>(event: Event<T>): Promise<string | null>;
23
+ create(attributes: T, clientId?: string): Promise<Entity & T>;
24
+ batchCreate(attributes: T[], clientId?: string): Promise<void>;
25
+ updateAll(attributes: any, query?: MongoCollectionQuery, clientId?: string): Promise<void>;
26
+ update(id: string, attributes: any, clientId?: string): Promise<void>;
27
+ increment(id: string, key: string, amt?: number): Promise<void>;
28
+ decrement(id: string, key: string, amt?: number): Promise<void>;
29
+ append(id: string, key: string, items: any[]): Promise<void>;
30
+ arrRemove(id: string, key: string, items: any[]): Promise<void>;
31
+ updateFirst(attributes: any, query?: MongoCollectionQuery, clientId?: string): Promise<Entity & T>;
32
+ }
33
+ //# sourceMappingURL=mongoCollection.d.ts.map
@@ -0,0 +1,221 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MongoCollection = void 0;
4
+ const mongo_1 = require("./mongo");
5
+ const mongoCollectionQuery_1 = require("./mongoCollectionQuery");
6
+ const types_1 = require("./types");
7
+ const mongodb_1 = require("mongodb");
8
+ const errors_1 = require("./errors");
9
+ class MongoCollection {
10
+ constructor(collectionName, options = {}) {
11
+ this.collection = mongo_1.mongoDb.collection(collectionName);
12
+ this.options = { enableEventLogging: true, eventsCollectionName: "events", ...options };
13
+ this.events = this.options.enableEventLogging
14
+ ? mongo_1.mongoDb.collection(this.options.eventsCollectionName)
15
+ : null;
16
+ this.name = collectionName;
17
+ }
18
+ async get(id) {
19
+ const objId = new mongodb_1.ObjectId(id);
20
+ const docWithId = await this.collection.findOne({ _id: objId });
21
+ if (docWithId) {
22
+ return this.toEntity(docWithId);
23
+ }
24
+ else {
25
+ console.error("Could not find id: " + id);
26
+ throw new errors_1.Error404();
27
+ }
28
+ }
29
+ toEntity(obj) {
30
+ return { ...obj, _id: String(obj._id) };
31
+ }
32
+ async getAll(query, pagination) {
33
+ const mongodbQuery = query?.build() ?? {};
34
+ const mongodbOptions = query?.buildOptions(pagination) ?? {};
35
+ try {
36
+ const res = await this.collection.find(mongodbQuery, mongodbOptions).toArray();
37
+ return res.map((d) => this.toEntity(d));
38
+ }
39
+ catch (err) {
40
+ console.log("getAll() Failed: Query: " +
41
+ JSON.stringify(mongodbQuery, null, 2) +
42
+ " err: " +
43
+ JSON.stringify(err, null, 2));
44
+ throw err;
45
+ }
46
+ }
47
+ async getSome(query, pagination) {
48
+ const mongodbQuery = query?.build();
49
+ const mongodbOptions = query?.buildOptions(pagination);
50
+ return (await this.collection.find(mongodbQuery, mongodbOptions).toArray()).map((d) => this.toEntity(d));
51
+ }
52
+ async getFirst(query) {
53
+ const mongodbQuery = query?.build();
54
+ const mongodbOptions = query?.buildOptions();
55
+ return this.toEntity(await this.collection.findOne(mongodbQuery, mongodbOptions));
56
+ }
57
+ async count(query) {
58
+ const mongodbQuery = query?.build() ?? {};
59
+ return this.collection.countDocuments(mongodbQuery);
60
+ }
61
+ async delete(id, clientId) {
62
+ const entity = await this.get(id);
63
+ this.logEvent({
64
+ name: types_1.EventName.DeleteEntity,
65
+ value: {
66
+ id,
67
+ collectionType: this.name,
68
+ count: await this.count(),
69
+ backup: entity,
70
+ deletedBy: clientId
71
+ }
72
+ });
73
+ await this.collection.deleteOne({ _id: new mongodb_1.ObjectId(id) });
74
+ }
75
+ async batchDelete(ids, clientId) {
76
+ const mongodbQuery = { _id: { $in: ids } };
77
+ const entities = await this.getAll(new mongoCollectionQuery_1.MongoCollectionQuery().where("_id").in(ids));
78
+ this.logEvent({
79
+ name: types_1.EventName.BatchDeleteEntities,
80
+ value: {
81
+ collectionType: this.name,
82
+ count: await this.count(),
83
+ backup: entities,
84
+ deletedBy: clientId
85
+ }
86
+ });
87
+ await this.collection.deleteMany({ mongodbQuery });
88
+ }
89
+ async exists(query) {
90
+ try {
91
+ const count = await this.collection.countDocuments(query.build());
92
+ return count > 0;
93
+ }
94
+ catch (err) {
95
+ console.log("Error getting count... " + JSON.stringify(err, null, 2));
96
+ return false;
97
+ }
98
+ }
99
+ async logEvent(event) {
100
+ if (!this.events) {
101
+ return null; // Event logging is disabled
102
+ }
103
+ const created = await this.events.insertOne({
104
+ ...event,
105
+ createdAt: Date.now(),
106
+ updatedAt: Date.now()
107
+ });
108
+ return String(created.insertedId);
109
+ }
110
+ async create(attributes, clientId) {
111
+ // implement clientId
112
+ try {
113
+ const created = await this.collection.insertOne({
114
+ ...attributes,
115
+ // _id: id,
116
+ createdAt: Date.now(),
117
+ updatedAt: Date.now()
118
+ });
119
+ const entity = this.toEntity(await this.get(created.insertedId));
120
+ this.logEvent({
121
+ name: types_1.EventName.CreateEntity,
122
+ identity: clientId,
123
+ value: { id: entity._id, collectionType: this.name, count: await this.count() }
124
+ });
125
+ return entity;
126
+ }
127
+ catch (err) {
128
+ console.error("Failed create: " + JSON.stringify(err, null, 2));
129
+ throw err;
130
+ }
131
+ }
132
+ async batchCreate(attributes, clientId) {
133
+ // implement clientId
134
+ const now = Date.now();
135
+ const entities = attributes.map((attribute) => ({
136
+ ...attribute,
137
+ //_id: uuidv4(),
138
+ createdAt: now,
139
+ updatedAt: now
140
+ }));
141
+ if (entities.length > 0) {
142
+ await this.collection.insertMany(entities);
143
+ this.logEvent({
144
+ name: types_1.EventName.BatchCreateEntities,
145
+ identity: clientId,
146
+ value: { collectionType: this.name, count: await this.count() }
147
+ });
148
+ }
149
+ }
150
+ async updateAll(attributes, query, clientId) {
151
+ // implement attributes, filters and clientId
152
+ const mongodbQuery = query?.build() ?? {};
153
+ await this.collection.updateMany(mongodbQuery, {
154
+ $set: {
155
+ updatedAt: Date.now(),
156
+ ...attributes
157
+ }
158
+ });
159
+ this.logEvent({
160
+ name: types_1.EventName.BatchUpdateEntities,
161
+ identity: clientId,
162
+ value: { collectionType: this.name }
163
+ });
164
+ }
165
+ async update(id, attributes, clientId) {
166
+ // implement attributes and clientId
167
+ if ("_id" in attributes) {
168
+ delete attributes._id;
169
+ }
170
+ try {
171
+ await this.collection.updateOne({ _id: new mongodb_1.ObjectId(id) }, {
172
+ $set: {
173
+ updatedAt: Date.now(),
174
+ ...attributes
175
+ }
176
+ });
177
+ this.logEvent({
178
+ name: types_1.EventName.UpdateEntity,
179
+ identity: clientId,
180
+ value: { collectionType: this.name, id }
181
+ });
182
+ }
183
+ catch (err) {
184
+ console.error("Failed updating: " + JSON.stringify(err, null, 2));
185
+ throw err;
186
+ }
187
+ }
188
+ async increment(id, key, amt) {
189
+ const inc = { $inc: { [key]: amt || 1 } };
190
+ await this.collection.updateOne({ _id: new mongodb_1.ObjectId(id) }, inc);
191
+ }
192
+ async decrement(id, key, amt) {
193
+ await this.collection.updateOne({ _id: new mongodb_1.ObjectId(id) }, { $inc: { [key]: amt ?? -1 } });
194
+ }
195
+ async append(id, key, items) {
196
+ await this.collection.updateOne({ _id: new mongodb_1.ObjectId(id) }, {
197
+ $push: { [key]: { $each: items } }
198
+ });
199
+ }
200
+ async arrRemove(id, key, items) {
201
+ await this.collection.updateOne({ _id: new mongodb_1.ObjectId(id) }, { $pull: { [key]: { $in: items } } });
202
+ }
203
+ async updateFirst(attributes, query, clientId) {
204
+ const mongodbQuery = query?.build() ?? {};
205
+ const update = {
206
+ $set: {
207
+ updatedAt: Date.now(),
208
+ ...attributes
209
+ }
210
+ };
211
+ const updated = await this.collection.findOneAndUpdate(mongodbQuery, update);
212
+ if (updated) {
213
+ return this.toEntity(updated);
214
+ }
215
+ else {
216
+ throw new Error("Failed to update entity");
217
+ }
218
+ }
219
+ }
220
+ exports.MongoCollection = MongoCollection;
221
+ //# sourceMappingURL=mongoCollection.js.map
@@ -0,0 +1,43 @@
1
+ import { Bounds, Coordinates, Pagination, ColExpression, ColRange, ICollectionQuery, Logic, SortDirection } from "./types";
2
+ import { Document, Filter, FindOptions } from "mongodb";
3
+ export declare class MongoCollectionQuery implements ICollectionQuery {
4
+ expressions: ColExpression[];
5
+ ranges: ColRange[];
6
+ orderField?: string;
7
+ orderDirection?: SortDirection;
8
+ orQueries: MongoCollectionQuery[];
9
+ andQueries: MongoCollectionQuery[];
10
+ private exp;
11
+ set(op?: string, val?: any): MongoCollectionQuery;
12
+ setRange(key: string, start: any, end: any, orderField: string): void;
13
+ where(key: string): MongoCollectionQuery;
14
+ and(key: string): MongoCollectionQuery;
15
+ eq(val?: any): MongoCollectionQuery;
16
+ neq(val?: any): MongoCollectionQuery;
17
+ lt(val?: any): MongoCollectionQuery;
18
+ ltEq(val?: any): MongoCollectionQuery;
19
+ gt(val?: any): MongoCollectionQuery;
20
+ gtEq(val?: any): MongoCollectionQuery;
21
+ arrContains(val?: any): MongoCollectionQuery;
22
+ arrContainsAll(val?: any): MongoCollectionQuery;
23
+ arrContainsAny(val?: any[]): MongoCollectionQuery;
24
+ startsWith(val: string): MongoCollectionQuery;
25
+ endsWith(val: string): MongoCollectionQuery;
26
+ strContains(val: string): MongoCollectionQuery;
27
+ private applyComparisonOperator;
28
+ in(val?: any[]): MongoCollectionQuery;
29
+ notIn(val?: any[]): MongoCollectionQuery;
30
+ inRange(key: string, min: any, max: any): MongoCollectionQuery;
31
+ inRadius(key: string, center: Coordinates, radius: number): MongoCollectionQuery;
32
+ geoWithin(bounds?: Bounds): MongoCollectionQuery;
33
+ orderBy(field?: string, direction?: SortDirection): MongoCollectionQuery;
34
+ andQuery(query: MongoCollectionQuery): MongoCollectionQuery;
35
+ or(query: MongoCollectionQuery): MongoCollectionQuery;
36
+ build<T>(): Filter<T>;
37
+ buildOptions<T extends Document>(pagination?: Pagination): FindOptions<T>;
38
+ }
39
+ export declare class CollectionQueryBuilder {
40
+ q: MongoCollectionQuery;
41
+ }
42
+ export { Logic };
43
+ //# sourceMappingURL=mongoCollectionQuery.d.ts.map
@@ -0,0 +1,224 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Logic = exports.CollectionQueryBuilder = exports.MongoCollectionQuery = void 0;
4
+ /* eslint-disable @typescript-eslint/no-explicit-any */
5
+ const types_1 = require("./types");
6
+ Object.defineProperty(exports, "Logic", { enumerable: true, get: function () { return types_1.Logic; } });
7
+ const geofire_common_1 = require("geofire-common");
8
+ const mongodb_1 = require("mongodb");
9
+ class MongoCollectionQuery {
10
+ constructor() {
11
+ this.expressions = [];
12
+ this.ranges = [];
13
+ this.orQueries = [];
14
+ this.andQueries = [];
15
+ }
16
+ exp() {
17
+ return this.expressions[this.expressions.length - 1];
18
+ }
19
+ set(op, val) {
20
+ if (!val) {
21
+ this.expressions.pop();
22
+ return this;
23
+ }
24
+ this.exp().op = op;
25
+ this.exp().val = val;
26
+ return this;
27
+ }
28
+ setRange(key, start, end, orderField) {
29
+ this.orderBy(orderField);
30
+ this.ranges.push({ key: key, start: start, end: end });
31
+ }
32
+ where(key) {
33
+ this.expressions.push(new types_1.ColExpression(key));
34
+ return this;
35
+ }
36
+ and(key) {
37
+ this.where(key);
38
+ return this;
39
+ }
40
+ eq(val) {
41
+ return this.set("$eq", val);
42
+ }
43
+ neq(val) {
44
+ return this.set("$ne", val);
45
+ }
46
+ lt(val) {
47
+ return this.set("$lt", val);
48
+ }
49
+ ltEq(val) {
50
+ return this.set("$lte", val);
51
+ }
52
+ gt(val) {
53
+ return this.set("$gt", val);
54
+ }
55
+ gtEq(val) {
56
+ return this.set("$gte", val);
57
+ }
58
+ arrContains(val) {
59
+ return this.set(undefined, val);
60
+ }
61
+ arrContainsAll(val) {
62
+ return this.set("$all", val);
63
+ }
64
+ arrContainsAny(val) {
65
+ if (val && val.length > 0) {
66
+ this.set("$in", val);
67
+ }
68
+ else {
69
+ this.expressions.pop();
70
+ }
71
+ return this;
72
+ }
73
+ startsWith(val) {
74
+ return this.set("$regex", "^" + val);
75
+ }
76
+ endsWith(val) {
77
+ return this.set("$regex", val + "$");
78
+ }
79
+ strContains(val) {
80
+ return this.set("$regex", val);
81
+ }
82
+ applyComparisonOperator(op, val) {
83
+ if (val) {
84
+ this.set(op, val);
85
+ }
86
+ else {
87
+ this.expressions.pop();
88
+ }
89
+ return this;
90
+ }
91
+ in(val) {
92
+ return this.applyComparisonOperator("$in", val);
93
+ }
94
+ notIn(val) {
95
+ return val?.length ?? 0 > 0 ? this.applyComparisonOperator("$nin", val) : this;
96
+ }
97
+ inRange(key, min, max) {
98
+ return this.where(key).gtEq(min).and(key).ltEq(max);
99
+ }
100
+ inRadius(key, center, radius) {
101
+ const geoBounds = (0, geofire_common_1.geohashQueryBounds)([center.latitude, center.longitude], radius);
102
+ this.orderBy(key, types_1.SortDirection.Ascending);
103
+ for (const b of geoBounds) {
104
+ this.or(new MongoCollectionQuery().inRange(key, b[0], b[1]));
105
+ }
106
+ return this;
107
+ }
108
+ geoWithin(bounds) {
109
+ if (bounds) {
110
+ this.set("$geoWithin", {
111
+ $geometry: {
112
+ type: "Polygon",
113
+ coordinates: [
114
+ [
115
+ [bounds.ne.longitude, bounds.ne.latitude],
116
+ [bounds.ne.longitude, bounds.sw.latitude],
117
+ [bounds.sw.longitude, bounds.sw.latitude],
118
+ [bounds.sw.longitude, bounds.ne.latitude],
119
+ [bounds.ne.longitude, bounds.ne.latitude]
120
+ ]
121
+ ]
122
+ }
123
+ });
124
+ }
125
+ else {
126
+ this.expressions.pop();
127
+ }
128
+ return this;
129
+ }
130
+ orderBy(field, direction) {
131
+ this.orderField = field;
132
+ this.orderDirection = direction;
133
+ return this;
134
+ }
135
+ andQuery(query) {
136
+ if (this.expressions.length > 0) {
137
+ this.andQueries.push(query);
138
+ }
139
+ return query;
140
+ }
141
+ or(query) {
142
+ this.orQueries.push(query);
143
+ return this;
144
+ }
145
+ build() {
146
+ let mongodbQuery = {};
147
+ //console.log("Building query: " + JSON.stringify(this, null, 2));
148
+ try {
149
+ if (this.expressions) {
150
+ for (const expression of this.expressions) {
151
+ //console.log("EXPRESSION: " + JSON.stringify(expression, null, 2));
152
+ if (expression.key === "_id") {
153
+ if (Array.isArray(expression.val)) {
154
+ mongodbQuery = {
155
+ _id: {
156
+ [expression.op ?? "$in"]: expression.val.map((element) => new mongodb_1.ObjectId(element))
157
+ }
158
+ };
159
+ }
160
+ else {
161
+ mongodbQuery = { _id: new mongodb_1.ObjectId(expression.val) };
162
+ }
163
+ break;
164
+ }
165
+ mongodbQuery[expression.key] = expression.op
166
+ ? expression.op === "$regex"
167
+ ? { [expression.op]: expression.val, ["$options"]: "i" }
168
+ : { [expression.op]: expression.val }
169
+ : expression.val;
170
+ }
171
+ }
172
+ if (this.orQueries.length > 0) {
173
+ //console.log("Found OR queries");
174
+ mongodbQuery["$or"] = [];
175
+ for (const query of this.orQueries) {
176
+ //console.log("OR QUERY: " + JSON.stringify(query, null, 2));
177
+ mongodbQuery["$or"].push(query.build());
178
+ }
179
+ }
180
+ if (this.andQueries.length > 0) {
181
+ mongodbQuery["$and"] = [];
182
+ for (const query of this.andQueries) {
183
+ mongodbQuery["$and"].push(query.build());
184
+ }
185
+ }
186
+ }
187
+ catch (err) {
188
+ console.log("Failed building query: " + JSON.stringify(err.message, null, 2));
189
+ throw err;
190
+ }
191
+ // if (query.ranges) {
192
+ // query.ranges.forEach((range) => {
193
+ // mongodbQuery[range.key as keyof Filter<T>] = {
194
+ // $gte: range.start,
195
+ // $lt: range.end
196
+ // };
197
+ // });
198
+ // }
199
+ //console.log("query: " + JSON.stringify(mongodbQuery, null, 2));
200
+ return mongodbQuery;
201
+ }
202
+ buildOptions(pagination) {
203
+ const mongodbOptions = {};
204
+ if (pagination) {
205
+ mongodbOptions.skip = pagination.offset;
206
+ mongodbOptions.limit = pagination.count;
207
+ }
208
+ if (this.orderField && this.orderDirection) {
209
+ mongodbOptions.sort = {
210
+ [this.orderField]: this.orderDirection === types_1.SortDirection.Ascending ? 1 : -1
211
+ };
212
+ }
213
+ //console.log(this.name + " mongo options: " + JSON.stringify(mongodbOptions, null, 2));
214
+ return mongodbOptions;
215
+ }
216
+ }
217
+ exports.MongoCollectionQuery = MongoCollectionQuery;
218
+ class CollectionQueryBuilder {
219
+ constructor() {
220
+ this.q = new MongoCollectionQuery();
221
+ }
222
+ }
223
+ exports.CollectionQueryBuilder = CollectionQueryBuilder;
224
+ //# sourceMappingURL=mongoCollectionQuery.js.map
package/dist/types.d.ts CHANGED
@@ -76,7 +76,7 @@ export type ICollection<T> = {
76
76
  batchDelete: (ids: string[], clientId?: string) => Promise<void>;
77
77
  exists: (query: ICollectionQuery) => Promise<boolean>;
78
78
  create: (attributes: T, clientId?: string) => Promise<Entity & T>;
79
- batchCreate: (attributes: T[], clientId?: string) => Promise<void>;
79
+ batchCreate: (attributes: T[], clientId?: string) => Promise<string[]>;
80
80
  updateAll: (attributes: any, filters?: any, clientId?: string) => Promise<void>;
81
81
  update: (id: string, attributes: any, clientId?: string) => Promise<void>;
82
82
  increment: (id: string, key: string, amt?: number) => Promise<void>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flongo",
3
- "version": "1.2.0",
3
+ "version": "1.4.0",
4
4
  "description": "Firestore-like fluent query API for MongoDB",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -13,7 +13,7 @@
13
13
  "test:coverage": "vitest --coverage",
14
14
  "lint": "echo 'Linting not configured yet'",
15
15
  "typecheck": "tsc --noEmit",
16
- "prepublishOnly": "npm run build && npm test",
16
+ "prepublishOnly": "npm run build && vitest --run",
17
17
  "semantic-release": "semantic-release"
18
18
  },
19
19
  "keywords": [