mongolite-ts 0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 YOUR_NAME
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,256 @@
1
+ # MongoLite-TS
2
+
3
+ [![CI](https://github.com/YOUR_USERNAME/mongolite-ts/actions/workflows/ci.yml/badge.svg)](https://github.com/YOUR_USERNAME/mongolite-ts/actions/workflows/ci.yml)
4
+ [![NPM version](https://img.shields.io/npm/v/mongolite-ts.svg)](https://www.npmjs.com/package/mongolite-ts)
5
+ [![Coverage Status](https://coveralls.io/repos/github/YOUR_USERNAME/mongolite-ts/badge.svg?branch=main)](https://coveralls.io/github/YOUR_USERNAME/mongolite-ts?branch=main)
6
+
7
+ A MongoDB-like client that uses SQLite as its underlying persistent store. Written in TypeScript, this package provides a familiar API for developers accustomed to MongoDB, while leveraging the simplicity and file-based nature of SQLite. It supports basic CRUD operations and JSON querying capabilities.
8
+
9
+ ## Features
10
+
11
+ * MongoDB-like API (`insertOne`, `findOne`, `updateOne`, `deleteOne`, etc.)
12
+ * SQLite backend for persistence.
13
+ * Automatic `_id` (UUID) generation and indexing.
14
+ * Support for querying JSON fields.
15
+ * Written in TypeScript with strong typing.
16
+ * 100% test coverage (aiming for).
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ npm install mongolite-ts sqlite3
22
+ # or
23
+ yarn add mongolite-ts sqlite3
24
+ ```
25
+
26
+ **Note:** `sqlite3` is a peer dependency and needs to be installed separately.
27
+
28
+ ## Usage
29
+
30
+ ```typescript
31
+ import { MongoLite } from 'mongolite-ts';
32
+ import path from 'path';
33
+
34
+ interface User {
35
+ _id?: string;
36
+ name: string;
37
+ age: number;
38
+ email: string;
39
+ address?: {
40
+ street: string;
41
+ city: string;
42
+ };
43
+ hobbies?: string[];
44
+ }
45
+
46
+ async function main() {
47
+ // Initialize the client.
48
+ // You can use ':memory:' for an in-memory database, or provide a file path.
49
+ const dbPath = path.join(__dirname, 'mydatabase.sqlite');
50
+ const client = new MongoLite(dbPath);
51
+
52
+ try {
53
+ // Connect to the database (optional, operations will auto-connect)
54
+ await client.connect();
55
+ console.log('Connected to SQLite database.');
56
+
57
+ // Get a collection (equivalent to a table)
58
+ const usersCollection = client.collection<User>('users');
59
+
60
+ // Insert a document
61
+ const insertResult = await usersCollection.insertOne({
62
+ name: 'Alice Wonderland',
63
+ age: 30,
64
+ email: 'alice@example.com',
65
+ address: { street: '123 Main St', city: 'Anytown' },
66
+ hobbies: ['reading', 'coding']
67
+ });
68
+ console.log('Inserted user:', insertResult);
69
+ const userId = insertResult.insertedId;
70
+
71
+ // Find a document
72
+ const foundUser = await usersCollection.findOne({ _id: userId });
73
+ console.log('Found user by ID:', foundUser);
74
+
75
+ const foundUserByEmail = await usersCollection.findOne({ email: 'alice@example.com' });
76
+ console.log('Found user by email:', foundUserByEmail);
77
+
78
+ // Find with nested query
79
+ const foundUserByCity = await usersCollection.findOne({ 'address.city': 'Anytown' });
80
+ console.log('Found user by city:', foundUserByCity);
81
+
82
+ // Find with operator ($gt)
83
+ const olderUsers = await usersCollection.find({ age: { $gt: 25 } }).toArray();
84
+ console.log('Users older than 25:', olderUsers);
85
+
86
+
87
+ // Update a document
88
+ const updateResult = await usersCollection.updateOne(
89
+ { _id: userId },
90
+ { $set: { age: 31, 'address.street': '456 New St' }, $push: { hobbies: 'gardening' } }
91
+ );
92
+ console.log('Update result:', updateResult);
93
+
94
+ const updatedUser = await usersCollection.findOne({ _id: userId });
95
+ console.log('Updated user:', updatedUser);
96
+
97
+ // Delete a document
98
+ const deleteResult = await usersCollection.deleteOne({ _id: userId });
99
+ console.log('Delete result:', deleteResult);
100
+
101
+ const notFoundUser = await usersCollection.findOne({ _id: userId });
102
+ console.log('User after deletion (should be null):', notFoundUser);
103
+
104
+ } catch (error) {
105
+ console.error('An error occurred:', error);
106
+ } finally {
107
+ // Close the database connection when done
108
+ await client.close();
109
+ console.log('Database connection closed.');
110
+ }
111
+ }
112
+
113
+ main();
114
+ ```
115
+
116
+ ## API
117
+
118
+ ### `MongoLite`
119
+
120
+ #### `constructor(dbPathOrOptions: string | MongoLiteOptions)`
121
+
122
+ Creates a new `MongoLite` client instance.
123
+
124
+ * `dbPathOrOptions`: Either a string path to the SQLite database file (e.g., `'./mydb.sqlite'`, `':memory:'`) or an options object.
125
+ * `MongoLiteOptions`:
126
+ * `filePath`: string - Path to the SQLite database file.
127
+ * `verbose?`: boolean - (Optional) Enable verbose logging from the `sqlite3` driver.
128
+
129
+ #### `async connect(): Promise<void>`
130
+
131
+ Explicitly opens the database connection. Operations will automatically connect if the DB is not already open.
132
+
133
+ #### `async close(): Promise<void>`
134
+
135
+ Closes the database connection.
136
+
137
+ #### `collection<T extends DocumentWithId = DocumentWithId>(name: string): MongoLiteCollection<T>`
138
+
139
+ Gets a reference to a collection (table).
140
+
141
+ * `name`: The name of the collection.
142
+ * Returns a `MongoLiteCollection` instance.
143
+
144
+ ### `MongoLiteCollection<T extends DocumentWithId>`
145
+
146
+ Represents a collection and provides methods to interact with its documents. `T` is a generic type for your document structure, which must extend `DocumentWithId` (i.e., have an optional `_id: string` field).
147
+
148
+ #### `async insertOne(doc: Omit<T, '_id'> & { _id?: string }): Promise<InsertOneResult>`
149
+
150
+ Inserts a single document into the collection. If `_id` is not provided, a UUID will be generated.
151
+
152
+ * `doc`: The document to insert.
153
+ * Returns `InsertOneResult`: `{ acknowledged: boolean; insertedId: string; }`.
154
+
155
+ #### `async findOne(filter: Filter<T>): Promise<T | null>`
156
+
157
+ Finds a single document matching the filter.
158
+
159
+ * `filter`: The query criteria. Supports direct field matching (e.g., `{ name: 'Alice' }`) and nested field matching using dot notation (e.g., `{ 'address.city': 'Anytown' }`). Also supports operators like `$eq`, `$ne`, `$gt`, `$gte`, `$lt`, `$lte`, `$in`, `$nin`.
160
+ * Returns the found document or `null`.
161
+
162
+ #### `find(filter: Filter<T>): FindCursor<T>`
163
+
164
+ Finds multiple documents matching the filter and returns a cursor.
165
+
166
+ * `filter`: The query criteria.
167
+ * Returns a `FindCursor` instance.
168
+
169
+ #### `async updateOne(filter: Filter<T>, update: UpdateFilter<T>): Promise<UpdateResult>`
170
+
171
+ Updates a single document matching the filter.
172
+
173
+ * `filter`: The query criteria to select the document.
174
+ * `update`: The update operations to apply. Supports operators like `$set`, `$unset`, `$inc`, `$push`, `$pull`.
175
+ * Returns `UpdateResult`: `{ acknowledged: boolean; matchedCount: number; modifiedCount: number; upsertedId: string | null; }`. (Upsert not yet implemented, `upsertedId` will be `null`).
176
+
177
+ #### `async deleteOne(filter: Filter<T>): Promise<DeleteResult>`
178
+
179
+ Deletes a single document matching the filter.
180
+
181
+ * `filter`: The query criteria to select the document.
182
+ * Returns `DeleteResult`: `{ acknowledged: boolean; deletedCount: number; }`.
183
+
184
+ ### `FindCursor<T>`
185
+
186
+ #### `async toArray(): Promise<T[]>`
187
+
188
+ Fetches all documents matching the cursor's query into an array.
189
+
190
+ #### `limit(count: number): FindCursor<T>`
191
+
192
+ Specifies the maximum number of documents the cursor will return.
193
+
194
+ #### `skip(count: number): FindCursor<T>`
195
+
196
+ Specifies the number of documents to skip.
197
+
198
+ #### `sort(sortCriteria: SortCriteria<T>): FindCursor<T>`
199
+
200
+ Specifies the sorting order.
201
+ * `sortCriteria`: An object where keys are field paths (dot notation for nested fields) and values are `1` (ascending) or `-1` (descending). Example: `{ 'age': -1, 'name': 1 }`.
202
+
203
+ ## Query Operators
204
+
205
+ The `filter` parameter in `findOne`, `find`, `updateOne`, and `deleteOne` supports the following:
206
+
207
+ ### Comparison Operators
208
+
209
+ * `{ field: value }` or `{ field: { $eq: value } }`: Matches documents where `field` equals `value`.
210
+ * `{ field: { $ne: value } }`: Matches documents where `field` does not equal `value`.
211
+ * `{ field: { $gt: value } }`: Matches documents where `field` is greater than `value`.
212
+ * `{ field: { $gte: value } }`: Matches documents where `field` is greater than or equal to `value`.
213
+ * `{ field: { $lt: value } }`: Matches documents where `field` is less than `value`.
214
+ * `{ field: { $lte: value } }`: Matches documents where `field` is less than or equal to `value`.
215
+ * `{ field: { $in: [value1, value2, ...] } }`: Matches documents where `field` is one of the specified values.
216
+ * `{ field: { $nin: [value1, value2, ...] } }`: Matches documents where `field` is not one of the specified values.
217
+
218
+ ### Logical Operators (Top-Level Only for now)
219
+
220
+ * `{ $and: [filter1, filter2, ...] }`: Joins query clauses with a logical AND.
221
+ * `{ $or: [filter1, filter2, ...] }`: Joins query clauses with a logical OR.
222
+ * `{ $nor: [filter1, filter2, ...] }`: Joins query clauses with a logical NOR.
223
+ * `{ $not: filter }`: Inverts the effect of a query expression. (Applied to a single operator expression, e.g., `{ age: { $not: { $gt: 30 } } }`)
224
+
225
+ ### Element Operators
226
+
227
+ * `{ field: { $exists: boolean } }`: Matches documents that have (or do not have) the specified field.
228
+
229
+ ## Update Operators
230
+
231
+ The `update` parameter in `updateOne` supports the following:
232
+
233
+ * `{ $set: { field1: value1, ... } }`: Sets the value of specified fields.
234
+ * `{ $unset: { field1: "", ... } }`: Removes specified fields from documents.
235
+ * `{ $inc: { field1: amount1, ... } }`: Increments the value of specified fields by a certain amount.
236
+ * `{ $push: { arrayField: valueOrModifier, ... } }`: Appends a value to an array. Can use with `$each`.
237
+ * `{ $push: { scores: 89 } }`
238
+ * `{ $push: { scores: { $each: [90, 92, 85] } } }`
239
+ * `{ $pull: { arrayField: valueOrCondition, ... } }`: Removes all instances of a value or values that match a condition from an array.
240
+ * `{ $pull: { scores: 0 } }`
241
+ * `{ $pull: { items: { id: { $in: [1, 2] } } } }` (More complex conditions for $pull might be limited initially)
242
+
243
+ ## Development
244
+
245
+ 1. Clone the repository.
246
+ 2. Install dependencies: `npm install`
247
+ 3. Build the project: `npm run build`
248
+ 4. Run tests: `npm test`
249
+
250
+ ## Contributing
251
+
252
+ Contributions are welcome! Please open an issue or submit a pull request.
253
+
254
+ ## License
255
+
256
+ MIT
@@ -0,0 +1,114 @@
1
+ import { SQLiteDB } from './db';
2
+ import { DocumentWithId, Filter, UpdateFilter, InsertOneResult, UpdateResult, DeleteResult, SortCriteria, Projection } from './types';
3
+ /**
4
+ * Represents a cursor for find operations, allowing chaining of limit, skip, and sort.
5
+ */
6
+ export declare class FindCursor<T extends DocumentWithId> {
7
+ private db;
8
+ private collectionName;
9
+ private queryParts;
10
+ private limitCount;
11
+ private skipCount;
12
+ private sortCriteria;
13
+ private projectionFields;
14
+ constructor(db: SQLiteDB, collectionName: string, initialFilter: Filter<T>);
15
+ private parseJsonPath;
16
+ private buildWhereClause;
17
+ private buildSelectQuery;
18
+ /**
19
+ * Specifies the maximum number of documents the cursor will return.
20
+ * @param count The number of documents to limit to.
21
+ * @returns The `FindCursor` instance for chaining.
22
+ */
23
+ limit(count: number): this;
24
+ /**
25
+ * Specifies the number of documents to skip.
26
+ * @param count The number of documents to skip.
27
+ * @returns The `FindCursor` instance for chaining.
28
+ */
29
+ skip(count: number): this;
30
+ /**
31
+ * Specifies the sorting order for the documents.
32
+ * @param sortCriteria An object defining sort order (e.g., `{ age: -1, name: 1 }`).
33
+ * @returns The `FindCursor` instance for chaining.
34
+ */
35
+ sort(sortCriteria: SortCriteria<T>): this;
36
+ /**
37
+ * Specifies the fields to return (projection).
38
+ * @param projection An object where keys are field names and values are 1 (include) or 0 (exclude).
39
+ * `_id` is included by default unless explicitly excluded.
40
+ * @returns The `FindCursor` instance for chaining.
41
+ */
42
+ project(projection: Projection<T>): this;
43
+ private applyProjection;
44
+ /**
45
+ * Executes the query and returns all matching documents as an array.
46
+ * @returns A promise that resolves to an array of documents.
47
+ */
48
+ toArray(): Promise<Partial<T>[]>;
49
+ }
50
+ /**
51
+ * MongoLiteCollection provides methods to interact with a specific SQLite table
52
+ * as if it were a MongoDB collection.
53
+ */
54
+ export declare class MongoLiteCollection<T extends DocumentWithId> {
55
+ private db;
56
+ readonly name: string;
57
+ constructor(db: SQLiteDB, name: string);
58
+ /**
59
+ * Ensures the SQLite table for this collection exists, creating it if necessary.
60
+ * The table will have an `_id` column (indexed) and a `data` column for JSON.
61
+ * @private
62
+ */
63
+ ensureTable(): Promise<void>;
64
+ /**
65
+ * Inserts a single document into the collection.
66
+ * If `_id` is not provided, a UUID will be generated.
67
+ * @param doc The document to insert.
68
+ * @returns {Promise<InsertOneResult>} An object containing the outcome of the insert operation.
69
+ */
70
+ insertOne(doc: Omit<T, '_id'> & {
71
+ _id?: string;
72
+ }): Promise<InsertOneResult>;
73
+ /**
74
+ * Finds a single document matching the filter.
75
+ * @param filter The query criteria.
76
+ * @param projection Optional. Specifies the fields to return.
77
+ * @returns {Promise<T | null>} The found document or `null`.
78
+ */
79
+ findOne(filter: Filter<T>, projection?: Projection<T>): Promise<Partial<T> | null>;
80
+ /**
81
+ * Finds multiple documents matching the filter and returns a cursor.
82
+ * @param filter The query criteria.
83
+ * @returns {FindCursor<T>} A `FindCursor` instance.
84
+ */
85
+ find(filter?: Filter<T>): FindCursor<T>;
86
+ /**
87
+ * Updates a single document matching the filter.
88
+ * @param filter The selection criteria for the update.
89
+ * @param update The modifications to apply.
90
+ * @returns {Promise<UpdateResult>} An object describing the outcome.
91
+ */
92
+ updateOne(filter: Filter<T>, update: UpdateFilter<T>): Promise<UpdateResult>;
93
+ private setNestedValue;
94
+ private unsetNestedValue;
95
+ private getNestedValue;
96
+ /**
97
+ * Deletes a single document matching the filter.
98
+ * @param filter The criteria to select the document to delete.
99
+ * @returns {Promise<DeleteResult>} An object describing the outcome.
100
+ */
101
+ deleteOne(filter: Filter<T>): Promise<DeleteResult>;
102
+ /**
103
+ * Deletes multiple documents matching the filter.
104
+ * @param filter The criteria to select documents to delete.
105
+ * @returns {Promise<DeleteResult>} An object describing the outcome.
106
+ */
107
+ deleteMany(filter: Filter<T>): Promise<DeleteResult>;
108
+ /**
109
+ * Counts the number of documents matching the filter.
110
+ * @param filter The criteria to select documents to count.
111
+ * @returns {Promise<number>} The count of matching documents.
112
+ */
113
+ countDocuments(filter?: Filter<T>): Promise<number>;
114
+ }