@objectql/driver-memory 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/CHANGELOG.md +65 -0
- package/LICENSE +21 -0
- package/README.md +542 -0
- package/dist/index.d.ts +132 -0
- package/dist/index.js +461 -0
- package/dist/index.js.map +1 -0
- package/jest.config.js +9 -0
- package/package.json +35 -0
- package/src/index.ts +527 -0
- package/test/index.test.ts +275 -0
- package/tsconfig.json +9 -0
- package/tsconfig.tsbuildinfo +1 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to the Memory Driver for ObjectQL will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.1.0] - 2026-01-15
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Initial release of Memory Driver
|
|
12
|
+
- Full implementation of ObjectQL Driver interface
|
|
13
|
+
- Zero external dependencies
|
|
14
|
+
- In-memory storage using JavaScript Maps
|
|
15
|
+
- Complete query support (filters, sorting, pagination)
|
|
16
|
+
- Bulk operations (createMany, updateMany, deleteMany)
|
|
17
|
+
- Distinct value queries
|
|
18
|
+
- Initial data loading
|
|
19
|
+
- Strict mode for error handling
|
|
20
|
+
- Comprehensive test suite (22 tests)
|
|
21
|
+
- Full documentation and README
|
|
22
|
+
- Support for all ObjectQL query operators:
|
|
23
|
+
- Comparison: =, !=, >, >=, <, <=
|
|
24
|
+
- Set: in, nin
|
|
25
|
+
- String: contains, startswith, endswith
|
|
26
|
+
- Range: between
|
|
27
|
+
- Logical: and, or
|
|
28
|
+
- Utility methods (clear, getSize)
|
|
29
|
+
- TypeScript type definitions
|
|
30
|
+
|
|
31
|
+
### Features
|
|
32
|
+
- ✅ Production-ready for non-persistent use cases
|
|
33
|
+
- ✅ Perfect for testing and development
|
|
34
|
+
- ✅ Works in all JavaScript environments (Node.js, Browser, Edge)
|
|
35
|
+
- ✅ High performance with O(1) CRUD operations
|
|
36
|
+
- ✅ Thread-safe operations
|
|
37
|
+
- ✅ Atomic updates and deletes
|
|
38
|
+
|
|
39
|
+
### Use Cases
|
|
40
|
+
- Unit testing without database setup
|
|
41
|
+
- Development and prototyping
|
|
42
|
+
- Edge/Worker environments (Cloudflare Workers, Deno Deploy)
|
|
43
|
+
- Client-side state management
|
|
44
|
+
- Temporary data caching
|
|
45
|
+
- CI/CD pipelines
|
|
46
|
+
|
|
47
|
+
### Performance
|
|
48
|
+
- Create: O(1)
|
|
49
|
+
- Read by ID: O(1)
|
|
50
|
+
- Update: O(1)
|
|
51
|
+
- Delete: O(1)
|
|
52
|
+
- Find/Query: O(n)
|
|
53
|
+
- Count: O(n)
|
|
54
|
+
- Sort: O(n log n)
|
|
55
|
+
|
|
56
|
+
### Documentation
|
|
57
|
+
- Comprehensive README with examples
|
|
58
|
+
- API reference
|
|
59
|
+
- Configuration guide
|
|
60
|
+
- Testing guide
|
|
61
|
+
- Performance tips
|
|
62
|
+
- Migration guide
|
|
63
|
+
- Troubleshooting section
|
|
64
|
+
|
|
65
|
+
[0.1.0]: https://github.com/objectstack-ai/objectql/releases/tag/%40objectql/driver-memory%400.1.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ObjectQL Contributors (https://github.com/objectql)
|
|
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,542 @@
|
|
|
1
|
+
# Memory Driver for ObjectQL
|
|
2
|
+
|
|
3
|
+
> ✅ **Production-Ready** - A high-performance in-memory driver for testing, development, and edge environments.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The Memory Driver is a zero-dependency, production-ready implementation of the ObjectQL Driver interface that stores data in JavaScript Maps. It provides full query support with high performance, making it ideal for scenarios where persistence is not required.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- ✅ **Zero Dependencies** - No external packages required
|
|
12
|
+
- ✅ **Full Query Support** - Filters, sorting, pagination, field projection
|
|
13
|
+
- ✅ **High Performance** - No I/O overhead, all operations in-memory
|
|
14
|
+
- ✅ **Bulk Operations** - createMany, updateMany, deleteMany
|
|
15
|
+
- ✅ **Thread-Safe** - Safe for concurrent operations
|
|
16
|
+
- ✅ **Strict Mode** - Optional error throwing for missing records
|
|
17
|
+
- ✅ **Initial Data** - Pre-populate on initialization
|
|
18
|
+
- ✅ **TypeScript** - Full type safety and IntelliSense support
|
|
19
|
+
|
|
20
|
+
## Use Cases
|
|
21
|
+
|
|
22
|
+
This driver is perfect for:
|
|
23
|
+
|
|
24
|
+
1. **Unit Testing** - No database setup required, instant cleanup
|
|
25
|
+
2. **Development & Prototyping** - Quick iteration without infrastructure
|
|
26
|
+
3. **Edge Environments** - Cloudflare Workers, Deno Deploy, Vercel Edge
|
|
27
|
+
4. **Client-Side State** - Browser-based applications
|
|
28
|
+
5. **Temporary Caching** - Short-lived data storage
|
|
29
|
+
6. **CI/CD Pipelines** - Fast tests without database dependencies
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# Using pnpm (recommended)
|
|
35
|
+
pnpm add @objectql/driver-memory
|
|
36
|
+
|
|
37
|
+
# Using npm
|
|
38
|
+
npm install @objectql/driver-memory
|
|
39
|
+
|
|
40
|
+
# Using yarn
|
|
41
|
+
yarn add @objectql/driver-memory
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Or if you're using the ObjectQL monorepo:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pnpm add @objectql/driver-memory
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Basic Usage
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
import { ObjectQL } from '@objectql/core';
|
|
54
|
+
import { MemoryDriver } from '@objectql/driver-memory';
|
|
55
|
+
|
|
56
|
+
// Initialize the driver
|
|
57
|
+
const driver = new MemoryDriver();
|
|
58
|
+
|
|
59
|
+
// Create ObjectQL instance
|
|
60
|
+
const app = new ObjectQL({
|
|
61
|
+
datasources: { default: driver }
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Register your schema
|
|
65
|
+
app.registerObject({
|
|
66
|
+
name: 'users',
|
|
67
|
+
fields: {
|
|
68
|
+
name: { type: 'text', required: true },
|
|
69
|
+
email: { type: 'email', unique: true },
|
|
70
|
+
role: { type: 'select', options: ['admin', 'user'] }
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
await app.init();
|
|
75
|
+
|
|
76
|
+
// Use it!
|
|
77
|
+
const ctx = app.createContext({ isSystem: true });
|
|
78
|
+
const repo = ctx.object('users');
|
|
79
|
+
|
|
80
|
+
// Create
|
|
81
|
+
const user = await repo.create({
|
|
82
|
+
name: 'Alice',
|
|
83
|
+
email: 'alice@example.com',
|
|
84
|
+
role: 'admin'
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// Find
|
|
88
|
+
const users = await repo.find({
|
|
89
|
+
filters: [['role', '=', 'user']]
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// Update
|
|
93
|
+
await repo.update(user.id, { email: 'alice.new@example.com' });
|
|
94
|
+
|
|
95
|
+
// Delete
|
|
96
|
+
await repo.delete(user.id);
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Configuration Options
|
|
100
|
+
|
|
101
|
+
### Basic Configuration
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
const driver = new MemoryDriver();
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### With Initial Data
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
const driver = new MemoryDriver({
|
|
111
|
+
initialData: {
|
|
112
|
+
users: [
|
|
113
|
+
{ id: '1', name: 'Alice', email: 'alice@example.com' },
|
|
114
|
+
{ id: '2', name: 'Bob', email: 'bob@example.com' }
|
|
115
|
+
],
|
|
116
|
+
posts: [
|
|
117
|
+
{ id: '1', title: 'Hello World', author_id: '1' }
|
|
118
|
+
]
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### With Strict Mode
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
const driver = new MemoryDriver({
|
|
127
|
+
strictMode: true // Throws errors for missing records
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
// This will throw an error instead of returning null
|
|
131
|
+
await driver.update('users', 'non-existent-id', { name: 'Test' });
|
|
132
|
+
// ObjectQLError: Record with id 'non-existent-id' not found in 'users'
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## API Reference
|
|
136
|
+
|
|
137
|
+
### Core Methods
|
|
138
|
+
|
|
139
|
+
All methods implement the standard Driver interface from `@objectql/types`:
|
|
140
|
+
|
|
141
|
+
#### `find(objectName, query, options)`
|
|
142
|
+
|
|
143
|
+
Find multiple records with optional filtering, sorting, and pagination.
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
const users = await driver.find('users', {
|
|
147
|
+
filters: [
|
|
148
|
+
['role', '=', 'admin'],
|
|
149
|
+
'or',
|
|
150
|
+
['age', '>', 30]
|
|
151
|
+
],
|
|
152
|
+
sort: [['name', 'asc']],
|
|
153
|
+
skip: 0,
|
|
154
|
+
limit: 10,
|
|
155
|
+
fields: ['name', 'email']
|
|
156
|
+
});
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
#### `findOne(objectName, id, query, options)`
|
|
160
|
+
|
|
161
|
+
Find a single record by ID or query.
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
// By ID
|
|
165
|
+
const user = await driver.findOne('users', 'user-123');
|
|
166
|
+
|
|
167
|
+
// By query
|
|
168
|
+
const admin = await driver.findOne('users', null, {
|
|
169
|
+
filters: [['role', '=', 'admin']]
|
|
170
|
+
});
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
#### `create(objectName, data, options)`
|
|
174
|
+
|
|
175
|
+
Create a new record.
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
const user = await driver.create('users', {
|
|
179
|
+
name: 'Alice',
|
|
180
|
+
email: 'alice@example.com'
|
|
181
|
+
});
|
|
182
|
+
// Returns: { id: 'users-1234567890-1', name: 'Alice', ... }
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
#### `update(objectName, id, data, options)`
|
|
186
|
+
|
|
187
|
+
Update an existing record.
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
const updated = await driver.update('users', 'user-123', {
|
|
191
|
+
email: 'alice.new@example.com'
|
|
192
|
+
});
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
#### `delete(objectName, id, options)`
|
|
196
|
+
|
|
197
|
+
Delete a record.
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
const deleted = await driver.delete('users', 'user-123');
|
|
201
|
+
// Returns: true if deleted, false if not found
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
#### `count(objectName, filters, options)`
|
|
205
|
+
|
|
206
|
+
Count records matching filters.
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
const adminCount = await driver.count('users', [
|
|
210
|
+
['role', '=', 'admin']
|
|
211
|
+
]);
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Bulk Operations
|
|
215
|
+
|
|
216
|
+
#### `createMany(objectName, data, options)`
|
|
217
|
+
|
|
218
|
+
Create multiple records at once.
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
const users = await driver.createMany('users', [
|
|
222
|
+
{ name: 'Alice' },
|
|
223
|
+
{ name: 'Bob' },
|
|
224
|
+
{ name: 'Charlie' }
|
|
225
|
+
]);
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
#### `updateMany(objectName, filters, data, options)`
|
|
229
|
+
|
|
230
|
+
Update all records matching filters.
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
const result = await driver.updateMany(
|
|
234
|
+
'users',
|
|
235
|
+
[['role', '=', 'user']],
|
|
236
|
+
{ status: 'active' }
|
|
237
|
+
);
|
|
238
|
+
// Returns: { modifiedCount: 5 }
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
#### `deleteMany(objectName, filters, options)`
|
|
242
|
+
|
|
243
|
+
Delete all records matching filters.
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
const result = await driver.deleteMany('users', [
|
|
247
|
+
['status', '=', 'inactive']
|
|
248
|
+
]);
|
|
249
|
+
// Returns: { deletedCount: 3 }
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### Advanced Operations
|
|
253
|
+
|
|
254
|
+
#### `distinct(objectName, field, filters, options)`
|
|
255
|
+
|
|
256
|
+
Get unique values for a field.
|
|
257
|
+
|
|
258
|
+
```typescript
|
|
259
|
+
const roles = await driver.distinct('users', 'role');
|
|
260
|
+
// Returns: ['admin', 'user', 'moderator']
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Utility Methods
|
|
264
|
+
|
|
265
|
+
#### `clear()`
|
|
266
|
+
|
|
267
|
+
Remove all data from the store.
|
|
268
|
+
|
|
269
|
+
```typescript
|
|
270
|
+
await driver.clear();
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
#### `getSize()`
|
|
274
|
+
|
|
275
|
+
Get the total number of records in the store.
|
|
276
|
+
|
|
277
|
+
```typescript
|
|
278
|
+
const size = driver.getSize();
|
|
279
|
+
// Returns: 42
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
#### `disconnect()`
|
|
283
|
+
|
|
284
|
+
Gracefully disconnect (no-op for memory driver).
|
|
285
|
+
|
|
286
|
+
```typescript
|
|
287
|
+
await driver.disconnect();
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
## Supported Query Operators
|
|
291
|
+
|
|
292
|
+
The Memory Driver supports all standard ObjectQL query operators:
|
|
293
|
+
|
|
294
|
+
### Comparison Operators
|
|
295
|
+
|
|
296
|
+
- `=`, `==` - Equals
|
|
297
|
+
- `!=`, `<>` - Not equals
|
|
298
|
+
- `>` - Greater than
|
|
299
|
+
- `>=` - Greater than or equal
|
|
300
|
+
- `<` - Less than
|
|
301
|
+
- `<=` - Less than or equal
|
|
302
|
+
|
|
303
|
+
### Set Operators
|
|
304
|
+
|
|
305
|
+
- `in` - Value in array
|
|
306
|
+
- `nin`, `not in` - Value not in array
|
|
307
|
+
|
|
308
|
+
### String Operators
|
|
309
|
+
|
|
310
|
+
- `contains`, `like` - Contains substring (case-insensitive)
|
|
311
|
+
- `startswith`, `starts_with` - Starts with string
|
|
312
|
+
- `endswith`, `ends_with` - Ends with string
|
|
313
|
+
|
|
314
|
+
### Range Operators
|
|
315
|
+
|
|
316
|
+
- `between` - Value between two values (inclusive)
|
|
317
|
+
|
|
318
|
+
### Logical Operators
|
|
319
|
+
|
|
320
|
+
- `and` - Logical AND (default)
|
|
321
|
+
- `or` - Logical OR
|
|
322
|
+
|
|
323
|
+
## Query Examples
|
|
324
|
+
|
|
325
|
+
### Simple Filter
|
|
326
|
+
|
|
327
|
+
```typescript
|
|
328
|
+
const admins = await driver.find('users', {
|
|
329
|
+
filters: [['role', '=', 'admin']]
|
|
330
|
+
});
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### Multiple Filters (AND)
|
|
334
|
+
|
|
335
|
+
```typescript
|
|
336
|
+
const activeAdmins = await driver.find('users', {
|
|
337
|
+
filters: [
|
|
338
|
+
['role', '=', 'admin'],
|
|
339
|
+
'and',
|
|
340
|
+
['status', '=', 'active']
|
|
341
|
+
]
|
|
342
|
+
});
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
### OR Filters
|
|
346
|
+
|
|
347
|
+
```typescript
|
|
348
|
+
const results = await driver.find('users', {
|
|
349
|
+
filters: [
|
|
350
|
+
['role', '=', 'admin'],
|
|
351
|
+
'or',
|
|
352
|
+
['permissions', 'contains', 'manage_users']
|
|
353
|
+
]
|
|
354
|
+
});
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### Range Queries
|
|
358
|
+
|
|
359
|
+
```typescript
|
|
360
|
+
const middleAged = await driver.find('users', {
|
|
361
|
+
filters: [['age', 'between', [30, 50]]]
|
|
362
|
+
});
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### Sorting
|
|
366
|
+
|
|
367
|
+
```typescript
|
|
368
|
+
const sorted = await driver.find('users', {
|
|
369
|
+
sort: [
|
|
370
|
+
['role', 'asc'],
|
|
371
|
+
['created_at', 'desc']
|
|
372
|
+
]
|
|
373
|
+
});
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
### Pagination
|
|
377
|
+
|
|
378
|
+
```typescript
|
|
379
|
+
// Get page 2 with 10 items per page
|
|
380
|
+
const page2 = await driver.find('users', {
|
|
381
|
+
skip: 10,
|
|
382
|
+
limit: 10,
|
|
383
|
+
sort: [['created_at', 'desc']]
|
|
384
|
+
});
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
### Field Projection
|
|
388
|
+
|
|
389
|
+
```typescript
|
|
390
|
+
const names = await driver.find('users', {
|
|
391
|
+
fields: ['id', 'name', 'email']
|
|
392
|
+
});
|
|
393
|
+
// Returns only id, name, and email fields
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
## Testing with Memory Driver
|
|
397
|
+
|
|
398
|
+
The Memory Driver is ideal for unit tests:
|
|
399
|
+
|
|
400
|
+
```typescript
|
|
401
|
+
import { MemoryDriver } from '@objectql/driver-memory';
|
|
402
|
+
|
|
403
|
+
describe('User Service', () => {
|
|
404
|
+
let driver: MemoryDriver;
|
|
405
|
+
|
|
406
|
+
beforeEach(() => {
|
|
407
|
+
driver = new MemoryDriver({
|
|
408
|
+
initialData: {
|
|
409
|
+
users: [
|
|
410
|
+
{ id: '1', name: 'Test User', role: 'user' }
|
|
411
|
+
]
|
|
412
|
+
}
|
|
413
|
+
});
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
afterEach(async () => {
|
|
417
|
+
await driver.clear();
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
it('should find users by role', async () => {
|
|
421
|
+
const users = await driver.find('users', {
|
|
422
|
+
filters: [['role', '=', 'user']]
|
|
423
|
+
});
|
|
424
|
+
expect(users).toHaveLength(1);
|
|
425
|
+
});
|
|
426
|
+
});
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
## Performance Characteristics
|
|
430
|
+
|
|
431
|
+
- **Create**: O(1)
|
|
432
|
+
- **Read by ID**: O(1)
|
|
433
|
+
- **Update**: O(1)
|
|
434
|
+
- **Delete**: O(1)
|
|
435
|
+
- **Find/Query**: O(n) - Scans all records for the object type
|
|
436
|
+
- **Count**: O(n) - Scans all matching records
|
|
437
|
+
- **Sort**: O(n log n)
|
|
438
|
+
|
|
439
|
+
### Performance Tips
|
|
440
|
+
|
|
441
|
+
1. **Use specific filters** - More filters reduce the result set faster
|
|
442
|
+
2. **Limit results** - Use `limit` to avoid processing large result sets
|
|
443
|
+
3. **Clear regularly** - Call `clear()` to free memory in long-running processes
|
|
444
|
+
4. **Consider size** - Memory driver is best for < 10,000 records per object type
|
|
445
|
+
|
|
446
|
+
## Comparison with Other Drivers
|
|
447
|
+
|
|
448
|
+
| Feature | Memory | SQL | MongoDB | Redis |
|
|
449
|
+
|---------|--------|-----|---------|-------|
|
|
450
|
+
| **Setup Required** | ❌ None | ✅ Database | ✅ Database | ✅ Redis Server |
|
|
451
|
+
| **Persistence** | ❌ No | ✅ Yes | ✅ Yes | ✅ Yes |
|
|
452
|
+
| **Performance** | ⚡ Fastest | 🐢 Slower | 🏃 Fast | 🏃 Fast |
|
|
453
|
+
| **Query Support** | ✅ Full | ✅ Full | ✅ Full | ⚠️ Limited |
|
|
454
|
+
| **Production Ready** | ✅ Yes* | ✅ Yes | ✅ Yes | ⚠️ Example |
|
|
455
|
+
| **Dependencies** | 0 | 2-3 | 1 | 1 |
|
|
456
|
+
|
|
457
|
+
*For use cases where persistence is not required
|
|
458
|
+
|
|
459
|
+
## Limitations
|
|
460
|
+
|
|
461
|
+
1. **No Persistence** - Data is lost when the process ends
|
|
462
|
+
2. **Memory Bound** - Limited by available RAM
|
|
463
|
+
3. **Single Instance** - No distribution or clustering
|
|
464
|
+
4. **No Transactions** - Operations are individual (though atomic)
|
|
465
|
+
5. **Linear Scans** - Queries scan all records (no indexes)
|
|
466
|
+
|
|
467
|
+
## Migration Guide
|
|
468
|
+
|
|
469
|
+
### From Redis Driver to Memory Driver
|
|
470
|
+
|
|
471
|
+
```typescript
|
|
472
|
+
// Before
|
|
473
|
+
import { RedisDriver } from '@objectql/driver-redis';
|
|
474
|
+
const driver = new RedisDriver({ url: 'redis://localhost:6379' });
|
|
475
|
+
|
|
476
|
+
// After
|
|
477
|
+
import { MemoryDriver } from '@objectql/driver-memory';
|
|
478
|
+
const driver = new MemoryDriver();
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
### From SQL Driver to Memory Driver (for testing)
|
|
482
|
+
|
|
483
|
+
```typescript
|
|
484
|
+
// Production
|
|
485
|
+
const driver = new SqlDriver({
|
|
486
|
+
client: 'pg',
|
|
487
|
+
connection: process.env.DATABASE_URL
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
// Testing
|
|
491
|
+
const driver = new MemoryDriver({
|
|
492
|
+
initialData: {
|
|
493
|
+
users: [/* test data */],
|
|
494
|
+
posts: [/* test data */]
|
|
495
|
+
}
|
|
496
|
+
});
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
## Troubleshooting
|
|
500
|
+
|
|
501
|
+
### Out of Memory Errors
|
|
502
|
+
|
|
503
|
+
```typescript
|
|
504
|
+
// Problem: Too much data
|
|
505
|
+
const driver = new MemoryDriver();
|
|
506
|
+
// ... add millions of records
|
|
507
|
+
|
|
508
|
+
// Solution: Clear periodically or use a persistent driver
|
|
509
|
+
await driver.clear();
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
### Slow Queries
|
|
513
|
+
|
|
514
|
+
```typescript
|
|
515
|
+
// Problem: Scanning large datasets
|
|
516
|
+
const results = await driver.find('users', {}); // Returns 100,000 records
|
|
517
|
+
|
|
518
|
+
// Solution: Add filters and limits
|
|
519
|
+
const results = await driver.find('users', {
|
|
520
|
+
filters: [['status', '=', 'active']],
|
|
521
|
+
limit: 100
|
|
522
|
+
});
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
## Related Documentation
|
|
526
|
+
|
|
527
|
+
- [Driver Extensibility Guide](../../../docs/guide/drivers/extensibility.md)
|
|
528
|
+
- [Implementing Custom Drivers](../../../docs/guide/drivers/implementing-custom-driver.md)
|
|
529
|
+
- [Driver Interface Reference](../../foundation/types/src/driver.ts)
|
|
530
|
+
- [ObjectQL Core Documentation](../../foundation/core/README.md)
|
|
531
|
+
|
|
532
|
+
## Contributing
|
|
533
|
+
|
|
534
|
+
Found a bug or have a feature request? Please open an issue on [GitHub](https://github.com/objectstack-ai/objectql/issues).
|
|
535
|
+
|
|
536
|
+
## License
|
|
537
|
+
|
|
538
|
+
MIT - Same as ObjectQL
|
|
539
|
+
|
|
540
|
+
## Changelog
|
|
541
|
+
|
|
542
|
+
See [CHANGELOG.md](./CHANGELOG.md) for version history.
|