bun-sqlite-for-rxdb 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.serena/project.yml +84 -0
- package/CHANGELOG.md +300 -0
- package/LICENSE +21 -0
- package/README.md +87 -0
- package/ROADMAP.md +532 -0
- package/benchmarks/benchmark.ts +145 -0
- package/benchmarks/case-insensitive-10runs.ts +156 -0
- package/benchmarks/fts5-1m-scale.ts +126 -0
- package/benchmarks/fts5-before-after.ts +104 -0
- package/benchmarks/indexed-benchmark.ts +141 -0
- package/benchmarks/new-operators-benchmark.ts +140 -0
- package/benchmarks/query-builder-benchmark.ts +88 -0
- package/benchmarks/query-builder-consistency.ts +109 -0
- package/benchmarks/raw-better-sqlite3-10m.ts +85 -0
- package/benchmarks/raw-better-sqlite3.ts +86 -0
- package/benchmarks/raw-bun-sqlite-10m.ts +85 -0
- package/benchmarks/raw-bun-sqlite.ts +86 -0
- package/benchmarks/regex-10runs-all.ts +216 -0
- package/benchmarks/regex-comparison-benchmark.ts +161 -0
- package/benchmarks/regex-real-comparison.ts +213 -0
- package/benchmarks/run-10x.sh +19 -0
- package/benchmarks/smart-regex-benchmark.ts +148 -0
- package/benchmarks/sql-vs-mingo-benchmark.ts +210 -0
- package/benchmarks/sql-vs-mingo-comparison.ts +175 -0
- package/benchmarks/text-vs-jsonb.ts +167 -0
- package/benchmarks/wal-benchmark.ts +112 -0
- package/docs/architectural-patterns.md +1336 -0
- package/docs/id1-testsuite-journey.md +839 -0
- package/docs/official-test-suite-setup.md +393 -0
- package/nul +0 -0
- package/package.json +44 -0
- package/src/changestream.test.ts +182 -0
- package/src/cleanup.test.ts +110 -0
- package/src/collection-isolation.test.ts +74 -0
- package/src/connection-pool.test.ts +102 -0
- package/src/connection-pool.ts +38 -0
- package/src/findDocumentsById.test.ts +122 -0
- package/src/index.ts +2 -0
- package/src/instance.ts +382 -0
- package/src/multi-instance-events.test.ts +204 -0
- package/src/query/and-operator.test.ts +39 -0
- package/src/query/builder.test.ts +96 -0
- package/src/query/builder.ts +154 -0
- package/src/query/elemMatch-operator.test.ts +24 -0
- package/src/query/exists-operator.test.ts +28 -0
- package/src/query/in-operators.test.ts +54 -0
- package/src/query/mod-operator.test.ts +22 -0
- package/src/query/nested-query.test.ts +198 -0
- package/src/query/not-operators.test.ts +49 -0
- package/src/query/operators.test.ts +70 -0
- package/src/query/operators.ts +185 -0
- package/src/query/or-operator.test.ts +68 -0
- package/src/query/regex-escaping-regression.test.ts +43 -0
- package/src/query/regex-operator.test.ts +44 -0
- package/src/query/schema-mapper.ts +27 -0
- package/src/query/size-operator.test.ts +22 -0
- package/src/query/smart-regex.ts +52 -0
- package/src/query/type-operator.test.ts +37 -0
- package/src/query-cache.test.ts +286 -0
- package/src/rxdb-helpers.test.ts +348 -0
- package/src/rxdb-helpers.ts +262 -0
- package/src/schema-version-isolation.test.ts +126 -0
- package/src/statement-manager.ts +69 -0
- package/src/storage.test.ts +589 -0
- package/src/storage.ts +21 -0
- package/src/types.ts +14 -0
- package/test/rxdb-test-suite.ts +27 -0
- package/tsconfig.json +31 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { describe, test, expect, afterEach } from 'bun:test';
|
|
2
|
+
import { BunSQLiteStorageInstance } from './instance';
|
|
3
|
+
import type { RxStorageInstanceCreationParams } from 'rxdb';
|
|
4
|
+
|
|
5
|
+
describe('cleanup() - TDD Red Phase', () => {
|
|
6
|
+
const instances: BunSQLiteStorageInstance<any>[] = [];
|
|
7
|
+
|
|
8
|
+
afterEach(async () => {
|
|
9
|
+
for (const instance of instances) {
|
|
10
|
+
await instance.close();
|
|
11
|
+
}
|
|
12
|
+
instances.length = 0;
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test('cleanup() should return false when documents are deleted', async () => {
|
|
16
|
+
const instance = new BunSQLiteStorageInstance({
|
|
17
|
+
databaseName: 'testdb',
|
|
18
|
+
collectionName: 'users',
|
|
19
|
+
databaseInstanceToken: 'test',
|
|
20
|
+
schema: {
|
|
21
|
+
version: 0,
|
|
22
|
+
primaryKey: 'id',
|
|
23
|
+
type: 'object',
|
|
24
|
+
properties: { id: { type: 'string' } }
|
|
25
|
+
},
|
|
26
|
+
options: {},
|
|
27
|
+
devMode: false,
|
|
28
|
+
multiInstance: false,
|
|
29
|
+
internals: {}
|
|
30
|
+
} as RxStorageInstanceCreationParams<any, any>);
|
|
31
|
+
instances.push(instance);
|
|
32
|
+
|
|
33
|
+
const doc = {
|
|
34
|
+
id: 'doc1',
|
|
35
|
+
_deleted: false,
|
|
36
|
+
_attachments: {},
|
|
37
|
+
_meta: { lwt: Date.now() },
|
|
38
|
+
_rev: '1-abc'
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
await instance.bulkWrite([{ document: doc }], 'test');
|
|
42
|
+
|
|
43
|
+
const deletedDoc = { ...doc, _deleted: true, _rev: '2-def', _meta: { lwt: Date.now() } };
|
|
44
|
+
await instance.bulkWrite([{ previous: doc, document: deletedDoc }], 'test');
|
|
45
|
+
|
|
46
|
+
const result = await instance.cleanup(Date.now() + 1000);
|
|
47
|
+
|
|
48
|
+
expect(result).toBe(false);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test('cleanup() should return true when no documents to clean', async () => {
|
|
52
|
+
const instance = new BunSQLiteStorageInstance({
|
|
53
|
+
databaseName: 'testdb',
|
|
54
|
+
collectionName: 'users',
|
|
55
|
+
databaseInstanceToken: 'test',
|
|
56
|
+
schema: {
|
|
57
|
+
version: 0,
|
|
58
|
+
primaryKey: 'id',
|
|
59
|
+
type: 'object',
|
|
60
|
+
properties: { id: { type: 'string' } }
|
|
61
|
+
},
|
|
62
|
+
options: {},
|
|
63
|
+
devMode: false,
|
|
64
|
+
multiInstance: false,
|
|
65
|
+
internals: {}
|
|
66
|
+
} as RxStorageInstanceCreationParams<any, any>);
|
|
67
|
+
instances.push(instance);
|
|
68
|
+
|
|
69
|
+
const result = await instance.cleanup(0);
|
|
70
|
+
|
|
71
|
+
expect(result).toBe(true);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test('cleanup() should actually remove deleted documents', async () => {
|
|
75
|
+
const instance = new BunSQLiteStorageInstance({
|
|
76
|
+
databaseName: 'testdb',
|
|
77
|
+
collectionName: 'users',
|
|
78
|
+
databaseInstanceToken: 'test',
|
|
79
|
+
schema: {
|
|
80
|
+
version: 0,
|
|
81
|
+
primaryKey: 'id',
|
|
82
|
+
type: 'object',
|
|
83
|
+
properties: { id: { type: 'string' } }
|
|
84
|
+
},
|
|
85
|
+
options: {},
|
|
86
|
+
devMode: false,
|
|
87
|
+
multiInstance: false,
|
|
88
|
+
internals: {}
|
|
89
|
+
} as RxStorageInstanceCreationParams<any, any>);
|
|
90
|
+
instances.push(instance);
|
|
91
|
+
|
|
92
|
+
const doc = {
|
|
93
|
+
id: 'doc1',
|
|
94
|
+
_deleted: false,
|
|
95
|
+
_attachments: {},
|
|
96
|
+
_meta: { lwt: Date.now() },
|
|
97
|
+
_rev: '1-abc'
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
await instance.bulkWrite([{ document: doc }], 'test');
|
|
101
|
+
|
|
102
|
+
const deletedDoc = { ...doc, _deleted: true, _rev: '2-def', _meta: { lwt: Date.now() } };
|
|
103
|
+
await instance.bulkWrite([{ previous: doc, document: deletedDoc }], 'test');
|
|
104
|
+
|
|
105
|
+
await instance.cleanup(Date.now() + 1000);
|
|
106
|
+
|
|
107
|
+
const found = await instance.findDocumentsById(['doc1'], true);
|
|
108
|
+
expect(found.length).toBe(0);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { describe, it, expect } from 'bun:test';
|
|
2
|
+
import { createRxDatabase, addRxPlugin } from 'rxdb';
|
|
3
|
+
import { RxDBDevModePlugin } from 'rxdb/plugins/dev-mode';
|
|
4
|
+
import { wrappedValidateAjvStorage } from 'rxdb/plugins/validate-ajv';
|
|
5
|
+
import { getRxStorageBunSQLite } from './index';
|
|
6
|
+
|
|
7
|
+
addRxPlugin(RxDBDevModePlugin);
|
|
8
|
+
|
|
9
|
+
describe('Collection Isolation', () => {
|
|
10
|
+
it('should NOT leak events across different collections in same database', async () => {
|
|
11
|
+
const dbName = 'test-collection-isolation-' + Date.now();
|
|
12
|
+
|
|
13
|
+
const db = await createRxDatabase({
|
|
14
|
+
name: dbName,
|
|
15
|
+
storage: wrappedValidateAjvStorage({ storage: getRxStorageBunSQLite() }),
|
|
16
|
+
multiInstance: true,
|
|
17
|
+
ignoreDuplicate: true
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
await db.addCollections({
|
|
21
|
+
users: {
|
|
22
|
+
schema: {
|
|
23
|
+
version: 0,
|
|
24
|
+
primaryKey: 'id',
|
|
25
|
+
type: 'object',
|
|
26
|
+
properties: {
|
|
27
|
+
id: { type: 'string', maxLength: 100 },
|
|
28
|
+
name: { type: 'string' }
|
|
29
|
+
},
|
|
30
|
+
required: ['id', 'name']
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
posts: {
|
|
34
|
+
schema: {
|
|
35
|
+
version: 0,
|
|
36
|
+
primaryKey: 'id',
|
|
37
|
+
type: 'object',
|
|
38
|
+
properties: {
|
|
39
|
+
id: { type: 'string', maxLength: 100 },
|
|
40
|
+
title: { type: 'string' }
|
|
41
|
+
},
|
|
42
|
+
required: ['id', 'title']
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
let usersChangeCount = 0;
|
|
48
|
+
let postsChangeCount = 0;
|
|
49
|
+
|
|
50
|
+
const usersSub = db.users.find().$.subscribe(() => {
|
|
51
|
+
usersChangeCount++;
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const postsSub = db.posts.find().$.subscribe(() => {
|
|
55
|
+
postsChangeCount++;
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
59
|
+
|
|
60
|
+
const initialUsersCount = usersChangeCount;
|
|
61
|
+
const initialPostsCount = postsChangeCount;
|
|
62
|
+
|
|
63
|
+
await db.posts.insert({ id: 'post1', title: 'Hello World' });
|
|
64
|
+
|
|
65
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
66
|
+
|
|
67
|
+
expect(postsChangeCount).toBeGreaterThan(initialPostsCount);
|
|
68
|
+
expect(usersChangeCount).toBe(initialUsersCount);
|
|
69
|
+
|
|
70
|
+
usersSub.unsubscribe();
|
|
71
|
+
postsSub.unsubscribe();
|
|
72
|
+
await db.remove();
|
|
73
|
+
});
|
|
74
|
+
});
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { describe, test, expect, afterEach } from 'bun:test';
|
|
2
|
+
import { getDatabase, releaseDatabase } from './connection-pool';
|
|
3
|
+
|
|
4
|
+
describe('Connection Pool', () => {
|
|
5
|
+
afterEach(() => {
|
|
6
|
+
// Clean up any leaked connections
|
|
7
|
+
const leaked = ['testdb1', 'testdb2', 'testdb3'];
|
|
8
|
+
leaked.forEach(name => {
|
|
9
|
+
try { releaseDatabase(name); } catch {}
|
|
10
|
+
});
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
test('should share Database object for same databaseName', () => {
|
|
14
|
+
const db1 = getDatabase('testdb1', ':memory:');
|
|
15
|
+
const db2 = getDatabase('testdb1', ':memory:');
|
|
16
|
+
|
|
17
|
+
expect(db1).toBe(db2); // Same object reference
|
|
18
|
+
|
|
19
|
+
releaseDatabase('testdb1');
|
|
20
|
+
releaseDatabase('testdb1');
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test('should create separate Database objects for different databaseNames', () => {
|
|
24
|
+
const db1 = getDatabase('testdb1', ':memory:');
|
|
25
|
+
const db2 = getDatabase('testdb2', ':memory:');
|
|
26
|
+
|
|
27
|
+
expect(db1).not.toBe(db2); // Different objects
|
|
28
|
+
|
|
29
|
+
releaseDatabase('testdb1');
|
|
30
|
+
releaseDatabase('testdb2');
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test('should throw error when same databaseName used with different filenames', () => {
|
|
34
|
+
getDatabase('testdb1', ':memory:');
|
|
35
|
+
|
|
36
|
+
expect(() => {
|
|
37
|
+
getDatabase('testdb1', './different.db');
|
|
38
|
+
}).toThrow("Database 'testdb1' already opened with different filename");
|
|
39
|
+
|
|
40
|
+
releaseDatabase('testdb1');
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test('should increment reference count on multiple getDatabase calls', () => {
|
|
44
|
+
const db1 = getDatabase('testdb1', ':memory:');
|
|
45
|
+
const db2 = getDatabase('testdb1', ':memory:');
|
|
46
|
+
const db3 = getDatabase('testdb1', ':memory:');
|
|
47
|
+
|
|
48
|
+
expect(db1).toBe(db2);
|
|
49
|
+
expect(db2).toBe(db3);
|
|
50
|
+
|
|
51
|
+
// Create a table to verify database stays open
|
|
52
|
+
db1.run('CREATE TABLE test (id INTEGER)');
|
|
53
|
+
|
|
54
|
+
// Release twice - should still be open
|
|
55
|
+
releaseDatabase('testdb1');
|
|
56
|
+
releaseDatabase('testdb1');
|
|
57
|
+
|
|
58
|
+
// Database should still work
|
|
59
|
+
expect(() => db1.run('INSERT INTO test VALUES (1)')).not.toThrow();
|
|
60
|
+
|
|
61
|
+
// Final release - now it closes
|
|
62
|
+
releaseDatabase('testdb1');
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test('should close database when reference count reaches zero', () => {
|
|
66
|
+
const db = getDatabase('testdb1', ':memory:');
|
|
67
|
+
db.run('CREATE TABLE test (id INTEGER)');
|
|
68
|
+
|
|
69
|
+
releaseDatabase('testdb1');
|
|
70
|
+
|
|
71
|
+
// Database should be closed now
|
|
72
|
+
expect(() => db.run('INSERT INTO test VALUES (1)')).toThrow();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test('should handle multiple databases independently', () => {
|
|
76
|
+
const db1 = getDatabase('testdb1', ':memory:');
|
|
77
|
+
const db2 = getDatabase('testdb2', ':memory:');
|
|
78
|
+
|
|
79
|
+
db1.run('CREATE TABLE test1 (id INTEGER)');
|
|
80
|
+
db2.run('CREATE TABLE test2 (id INTEGER)');
|
|
81
|
+
|
|
82
|
+
// Close db1
|
|
83
|
+
releaseDatabase('testdb1');
|
|
84
|
+
expect(() => db1.run('INSERT INTO test1 VALUES (1)')).toThrow();
|
|
85
|
+
|
|
86
|
+
// db2 should still work
|
|
87
|
+
expect(() => db2.run('INSERT INTO test2 VALUES (1)')).not.toThrow();
|
|
88
|
+
|
|
89
|
+
releaseDatabase('testdb2');
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test('should allow reusing databaseName after full release', () => {
|
|
93
|
+
const db1 = getDatabase('testdb1', ':memory:');
|
|
94
|
+
releaseDatabase('testdb1');
|
|
95
|
+
|
|
96
|
+
// Should be able to get a new database with same name
|
|
97
|
+
const db2 = getDatabase('testdb1', ':memory:');
|
|
98
|
+
expect(db2).not.toBe(db1); // Different instance (old one was closed)
|
|
99
|
+
|
|
100
|
+
releaseDatabase('testdb1');
|
|
101
|
+
});
|
|
102
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Database } from 'bun:sqlite';
|
|
2
|
+
|
|
3
|
+
type DatabaseState = {
|
|
4
|
+
db: Database;
|
|
5
|
+
filename: string;
|
|
6
|
+
openConnections: number;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const DATABASE_POOL = new Map<string, DatabaseState>();
|
|
10
|
+
|
|
11
|
+
export function getDatabase(databaseName: string, filename: string): Database {
|
|
12
|
+
let state = DATABASE_POOL.get(databaseName);
|
|
13
|
+
if (!state) {
|
|
14
|
+
state = {
|
|
15
|
+
db: new Database(filename),
|
|
16
|
+
filename,
|
|
17
|
+
openConnections: 1
|
|
18
|
+
};
|
|
19
|
+
DATABASE_POOL.set(databaseName, state);
|
|
20
|
+
} else {
|
|
21
|
+
if (state.filename !== filename) {
|
|
22
|
+
throw new Error(`Database '${databaseName}' already opened with different filename: '${state.filename}' vs '${filename}'`);
|
|
23
|
+
}
|
|
24
|
+
state.openConnections++;
|
|
25
|
+
}
|
|
26
|
+
return state.db;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function releaseDatabase(databaseName: string): void {
|
|
30
|
+
const state = DATABASE_POOL.get(databaseName);
|
|
31
|
+
if (state) {
|
|
32
|
+
state.openConnections--;
|
|
33
|
+
if (state.openConnections === 0) {
|
|
34
|
+
state.db.close();
|
|
35
|
+
DATABASE_POOL.delete(databaseName);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { describe, expect, test } from 'bun:test';
|
|
2
|
+
import { getRxStorageBunSQLite } from './storage';
|
|
3
|
+
import type { RxDocumentData, RxJsonSchema } from 'rxdb';
|
|
4
|
+
|
|
5
|
+
interface TestDoc {
|
|
6
|
+
id: string;
|
|
7
|
+
name: string;
|
|
8
|
+
age: number;
|
|
9
|
+
_deleted: boolean;
|
|
10
|
+
_attachments: {};
|
|
11
|
+
_rev: string;
|
|
12
|
+
_meta: { lwt: number };
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const testSchema: RxJsonSchema<RxDocumentData<TestDoc>> = {
|
|
16
|
+
version: 0,
|
|
17
|
+
primaryKey: 'id',
|
|
18
|
+
type: 'object',
|
|
19
|
+
properties: {
|
|
20
|
+
id: { type: 'string', maxLength: 100 },
|
|
21
|
+
name: { type: 'string' },
|
|
22
|
+
age: { type: 'number' },
|
|
23
|
+
_deleted: { type: 'boolean' },
|
|
24
|
+
_attachments: { type: 'object' },
|
|
25
|
+
_rev: { type: 'string' },
|
|
26
|
+
_meta: {
|
|
27
|
+
type: 'object',
|
|
28
|
+
properties: {
|
|
29
|
+
lwt: { type: 'number' }
|
|
30
|
+
},
|
|
31
|
+
required: ['lwt']
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
required: ['id', '_deleted', '_rev', '_meta']
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
describe('findDocumentsById - withDeleted semantics', () => {
|
|
38
|
+
test('withDeleted=false returns ONLY non-deleted docs', async () => {
|
|
39
|
+
const storage = getRxStorageBunSQLite();
|
|
40
|
+
const instance = await storage.createStorageInstance({
|
|
41
|
+
databaseName: 'test-db',
|
|
42
|
+
collectionName: 'test-collection',
|
|
43
|
+
schema: testSchema,
|
|
44
|
+
options: {},
|
|
45
|
+
multiInstance: false,
|
|
46
|
+
devMode: false,
|
|
47
|
+
databaseInstanceToken: 'test-token'
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const docs: RxDocumentData<TestDoc>[] = [
|
|
51
|
+
{ id: 'doc1', name: 'Active', age: 25, _deleted: false, _attachments: {}, _rev: '1-a', _meta: { lwt: Date.now() } },
|
|
52
|
+
{ id: 'doc2', name: 'Deleted', age: 30, _deleted: true, _attachments: {}, _rev: '1-b', _meta: { lwt: Date.now() } },
|
|
53
|
+
{ id: 'doc3', name: 'Active2', age: 35, _deleted: false, _attachments: {}, _rev: '1-c', _meta: { lwt: Date.now() } }
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
await instance.bulkWrite(docs.map(doc => ({ document: doc })), 'test');
|
|
57
|
+
|
|
58
|
+
const result = await instance.findDocumentsById(['doc1', 'doc2', 'doc3'], false);
|
|
59
|
+
|
|
60
|
+
expect(result.length).toBe(2);
|
|
61
|
+
expect(result.map(d => d.id).sort()).toEqual(['doc1', 'doc3']);
|
|
62
|
+
expect(result.every(d => d._deleted === false)).toBe(true);
|
|
63
|
+
|
|
64
|
+
await instance.remove();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test('withDeleted=true returns ALL docs (deleted + non-deleted)', async () => {
|
|
68
|
+
const storage = getRxStorageBunSQLite();
|
|
69
|
+
const instance = await storage.createStorageInstance({
|
|
70
|
+
databaseName: 'test-db',
|
|
71
|
+
collectionName: 'test-collection',
|
|
72
|
+
schema: testSchema,
|
|
73
|
+
options: {},
|
|
74
|
+
multiInstance: false,
|
|
75
|
+
devMode: false,
|
|
76
|
+
databaseInstanceToken: 'test-token'
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
const docs: RxDocumentData<TestDoc>[] = [
|
|
80
|
+
{ id: 'doc1', name: 'Active', age: 25, _deleted: false, _attachments: {}, _rev: '1-a', _meta: { lwt: Date.now() } },
|
|
81
|
+
{ id: 'doc2', name: 'Deleted', age: 30, _deleted: true, _attachments: {}, _rev: '1-b', _meta: { lwt: Date.now() } },
|
|
82
|
+
{ id: 'doc3', name: 'Active2', age: 35, _deleted: false, _attachments: {}, _rev: '1-c', _meta: { lwt: Date.now() } }
|
|
83
|
+
];
|
|
84
|
+
|
|
85
|
+
await instance.bulkWrite(docs.map(doc => ({ document: doc })), 'test');
|
|
86
|
+
|
|
87
|
+
const result = await instance.findDocumentsById(['doc1', 'doc2', 'doc3'], true);
|
|
88
|
+
|
|
89
|
+
expect(result.length).toBe(3);
|
|
90
|
+
expect(result.map(d => d.id).sort()).toEqual(['doc1', 'doc2', 'doc3']);
|
|
91
|
+
expect(result.filter(d => d._deleted).length).toBe(1);
|
|
92
|
+
expect(result.filter(d => !d._deleted).length).toBe(2);
|
|
93
|
+
|
|
94
|
+
await instance.remove();
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test('withDeleted=false with only deleted docs returns empty array', async () => {
|
|
98
|
+
const storage = getRxStorageBunSQLite();
|
|
99
|
+
const instance = await storage.createStorageInstance({
|
|
100
|
+
databaseName: 'test-db',
|
|
101
|
+
collectionName: 'test-collection',
|
|
102
|
+
schema: testSchema,
|
|
103
|
+
options: {},
|
|
104
|
+
multiInstance: false,
|
|
105
|
+
devMode: false,
|
|
106
|
+
databaseInstanceToken: 'test-token'
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
const docs: RxDocumentData<TestDoc>[] = [
|
|
110
|
+
{ id: 'doc1', name: 'Deleted1', age: 25, _deleted: true, _attachments: {}, _rev: '1-a', _meta: { lwt: Date.now() } },
|
|
111
|
+
{ id: 'doc2', name: 'Deleted2', age: 30, _deleted: true, _attachments: {}, _rev: '1-b', _meta: { lwt: Date.now() } }
|
|
112
|
+
];
|
|
113
|
+
|
|
114
|
+
await instance.bulkWrite(docs.map(doc => ({ document: doc })), 'test');
|
|
115
|
+
|
|
116
|
+
const result = await instance.findDocumentsById(['doc1', 'doc2'], false);
|
|
117
|
+
|
|
118
|
+
expect(result.length).toBe(0);
|
|
119
|
+
|
|
120
|
+
await instance.remove();
|
|
121
|
+
});
|
|
122
|
+
});
|
package/src/index.ts
ADDED