@anfenn/dync 1.0.7 → 1.0.9

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/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- export { A as AfterRemoteAddCallback, a as ApiFunctions, d as BatchFirstLoadResult, b as BatchPushPayload, c as BatchPushResult, B as BatchSync, C as ConflictResolutionStrategy, D as Dync, F as FirstLoadProgress, e as FirstLoadProgressCallback, f as MissingRemoteRecordDuringUpdateCallback, M as MissingRemoteRecordStrategy, g as MutationEvent, S as SyncAction, h as SyncOptions, i as SyncState, j as SyncedRecord, T as TableMap } from './index.shared-DsDBNWlz.cjs';
2
- export { M as MemoryAdapter, a as MemoryQueryContext, S as SQLiteAdapter, b as SqliteQueryContext, c as StorageAdapter } from './dexie-1_xyU5MV.cjs';
1
+ export { A as AfterRemoteAddCallback, a as ApiFunctions, d as BatchFirstLoadResult, b as BatchPushPayload, c as BatchPushResult, B as BatchSync, C as ConflictResolutionStrategy, D as Dync, F as FirstLoadProgress, e as FirstLoadProgressCallback, f as MissingRemoteRecordDuringUpdateCallback, M as MissingRemoteRecordStrategy, g as MutationEvent, S as SyncAction, h as SyncOptions, i as SyncState, j as SyncedRecord, T as TableMap } from './index.shared-C8JTfet7.cjs';
2
+ export { M as MemoryAdapter, a as MemoryQueryContext, S as SQLiteAdapter, b as SqliteQueryContext, c as StorageAdapter } from './dexie-BqktVP7s.cjs';
3
3
  export { S as SQLiteDatabaseDriver, b as SQLiteQueryResult, a as SQLiteRunResult } from './types-CSbIAfu2.cjs';
4
4
  import 'dexie';
5
5
 
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- export { A as AfterRemoteAddCallback, a as ApiFunctions, d as BatchFirstLoadResult, b as BatchPushPayload, c as BatchPushResult, B as BatchSync, C as ConflictResolutionStrategy, D as Dync, F as FirstLoadProgress, e as FirstLoadProgressCallback, f as MissingRemoteRecordDuringUpdateCallback, M as MissingRemoteRecordStrategy, g as MutationEvent, S as SyncAction, h as SyncOptions, i as SyncState, j as SyncedRecord, T as TableMap } from './index.shared-Byhq6TyU.js';
2
- export { M as MemoryAdapter, a as MemoryQueryContext, S as SQLiteAdapter, b as SqliteQueryContext, c as StorageAdapter } from './dexie-ChZ0o0Sz.js';
1
+ export { A as AfterRemoteAddCallback, a as ApiFunctions, d as BatchFirstLoadResult, b as BatchPushPayload, c as BatchPushResult, B as BatchSync, C as ConflictResolutionStrategy, D as Dync, F as FirstLoadProgress, e as FirstLoadProgressCallback, f as MissingRemoteRecordDuringUpdateCallback, M as MissingRemoteRecordStrategy, g as MutationEvent, S as SyncAction, h as SyncOptions, i as SyncState, j as SyncedRecord, T as TableMap } from './index.shared-DajtjVW7.js';
2
+ export { M as MemoryAdapter, a as MemoryQueryContext, S as SQLiteAdapter, b as SqliteQueryContext, c as StorageAdapter } from './dexie-DRLMKLl5.js';
3
3
  export { S as SQLiteDatabaseDriver, b as SQLiteQueryResult, a as SQLiteRunResult } from './types-CSbIAfu2.js';
4
4
  import 'dexie';
5
5
 
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  SqliteQueryContext,
7
7
  SyncAction,
8
8
  createLocalId
9
- } from "./chunk-PCA4XM2N.js";
9
+ } from "./chunk-MOYMEJP5.js";
10
10
  import "./chunk-SQB6E7V2.js";
11
11
  export {
12
12
  Dync,
@@ -1,4 +1,4 @@
1
- import { d as StorageTable, c as StorageAdapter, T as TableSchemaDefinition, D as DexieQueryContext, b as SqliteQueryContext, a as MemoryQueryContext } from './dexie-1_xyU5MV.cjs';
1
+ import { d as StorageTable, c as StorageAdapter, T as TableSchemaDefinition, D as DexieQueryContext, b as SqliteQueryContext, a as MemoryQueryContext } from './dexie-BqktVP7s.cjs';
2
2
  import { c as SQLiteVersionConfigurator } from './types-CSbIAfu2.cjs';
3
3
 
4
4
  type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'none';
@@ -1,4 +1,4 @@
1
- import { d as StorageTable, c as StorageAdapter, T as TableSchemaDefinition, D as DexieQueryContext, b as SqliteQueryContext, a as MemoryQueryContext } from './dexie-ChZ0o0Sz.js';
1
+ import { d as StorageTable, c as StorageAdapter, T as TableSchemaDefinition, D as DexieQueryContext, b as SqliteQueryContext, a as MemoryQueryContext } from './dexie-DRLMKLl5.js';
2
2
  import { c as SQLiteVersionConfigurator } from './types-CSbIAfu2.js';
3
3
 
4
4
  type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'none';
@@ -1,5 +1,5 @@
1
- import { a as ApiFunctions, h as SyncOptions, B as BatchSync, D as Dync, i as SyncState } from '../index.shared-DsDBNWlz.cjs';
2
- import { c as StorageAdapter } from '../dexie-1_xyU5MV.cjs';
1
+ import { a as ApiFunctions, h as SyncOptions, B as BatchSync, D as Dync, i as SyncState } from '../index.shared-C8JTfet7.cjs';
2
+ import { c as StorageAdapter } from '../dexie-BqktVP7s.cjs';
3
3
  import '../types-CSbIAfu2.cjs';
4
4
  import 'dexie';
5
5
 
@@ -1,5 +1,5 @@
1
- import { a as ApiFunctions, h as SyncOptions, B as BatchSync, D as Dync, i as SyncState } from '../index.shared-Byhq6TyU.js';
2
- import { c as StorageAdapter } from '../dexie-ChZ0o0Sz.js';
1
+ import { a as ApiFunctions, h as SyncOptions, B as BatchSync, D as Dync, i as SyncState } from '../index.shared-DajtjVW7.js';
2
+ import { c as StorageAdapter } from '../dexie-DRLMKLl5.js';
3
3
  import '../types-CSbIAfu2.js';
4
4
  import 'dexie';
5
5
 
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  Dync
3
- } from "../chunk-PCA4XM2N.js";
3
+ } from "../chunk-MOYMEJP5.js";
4
4
  import "../chunk-SQB6E7V2.js";
5
5
 
6
6
  // src/react/useDync.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anfenn/dync",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "private": false,
5
5
  "description": "Write once, run IndexedDB & SQLite with sync anywhere - React, React Native, Expo, Capacitor, Electron & Node.js",
6
6
  "keywords": [
@@ -8,7 +8,6 @@ export class DexieTable<T = any> implements StorageTable<T> {
8
8
  readonly name: string;
9
9
  readonly schema: unknown;
10
10
  readonly primaryKey: unknown;
11
- readonly hook: unknown;
12
11
  readonly raw = Object.freeze({
13
12
  add: (item: T): Promise<string> => this.table.add(item) as Promise<string>,
14
13
  put: (item: T): Promise<string> => this.table.put(item) as Promise<string>,
@@ -29,7 +28,6 @@ export class DexieTable<T = any> implements StorageTable<T> {
29
28
  this.name = table.name;
30
29
  this.schema = table.schema;
31
30
  this.primaryKey = table.schema?.primKey;
32
- this.hook = table.hook;
33
31
  }
34
32
 
35
33
  add(item: AddItem<T>): Promise<string> {
@@ -84,8 +82,8 @@ export class DexieTable<T = any> implements StorageTable<T> {
84
82
  return this.table.bulkDelete(keys as any);
85
83
  }
86
84
 
87
- where(index: string | string[]): StorageWhereClause<T> {
88
- return new DexieWhereClause(this.table.where(normalizeIndexName(index)));
85
+ where(index: string): StorageWhereClause<T> {
86
+ return new DexieWhereClause(this.table.where(index));
89
87
  }
90
88
 
91
89
  orderBy(index: string | string[]): StorageCollection<T> {
@@ -104,11 +102,6 @@ export class DexieTable<T = any> implements StorageTable<T> {
104
102
  return new DexieCollection(this.table.limit(count));
105
103
  }
106
104
 
107
- mapToClass(ctor: new (...args: any[]) => any): StorageTable<T> {
108
- this.table.mapToClass(ctor as any);
109
- return this;
110
- }
111
-
112
105
  async each(callback: (item: T) => void | Promise<void>): Promise<void> {
113
106
  const tasks: Array<void | Promise<void>> = [];
114
107
  await this.table.each((item) => {
@@ -10,7 +10,6 @@ export class MemoryTable<T extends MemoryRecord = MemoryRecord> implements Stora
10
10
  readonly name: string;
11
11
  readonly schema: unknown = undefined;
12
12
  readonly primaryKey: unknown = LOCAL_PK;
13
- readonly hook: unknown = Object.freeze({});
14
13
  readonly raw: {
15
14
  add: (item: T) => Promise<string>;
16
15
  put: (item: T) => Promise<string>;
@@ -133,7 +132,7 @@ export class MemoryTable<T extends MemoryRecord = MemoryRecord> implements Stora
133
132
  }
134
133
  }
135
134
 
136
- where(index: string | string[]): StorageWhereClause<T> {
135
+ where(index: string): StorageWhereClause<T> {
137
136
  return this.createWhereClause(index);
138
137
  }
139
138
 
@@ -155,10 +154,6 @@ export class MemoryTable<T extends MemoryRecord = MemoryRecord> implements Stora
155
154
  return this.createCollection({ limit: count });
156
155
  }
157
156
 
158
- mapToClass(_ctor: new (...args: any[]) => any): StorageTable<T> {
159
- return this;
160
- }
161
-
162
157
  async each(callback: (item: T) => void | Promise<void>): Promise<void> {
163
158
  for (const [, record] of this.entries()) {
164
159
  await callback(this.cloneRecord(record));
@@ -187,8 +182,8 @@ export class MemoryTable<T extends MemoryRecord = MemoryRecord> implements Stora
187
182
  });
188
183
  }
189
184
 
190
- createWhereClause(index: string | string[], baseCollection?: MemoryCollection<T>): MemoryWhereClause<T> {
191
- return new MemoryWhereClause(this, index, baseCollection);
185
+ createWhereClause(column: string, baseCollection?: MemoryCollection<T>): MemoryWhereClause<T> {
186
+ return new MemoryWhereClause(this, column, baseCollection);
192
187
  }
193
188
 
194
189
  entries(): Array<[string, T]> {
@@ -5,12 +5,12 @@ import type { MemoryCollection } from './MemoryCollection';
5
5
 
6
6
  export class MemoryWhereClause<T extends MemoryRecord = MemoryRecord> implements StorageWhereClause<T> {
7
7
  private readonly table: MemoryTable<T>;
8
- private readonly index: string | string[];
8
+ private readonly column: string;
9
9
  private readonly baseCollection?: MemoryCollection<T>;
10
10
 
11
- constructor(table: MemoryTable<T>, index: string | string[], baseCollection?: MemoryCollection<T>) {
11
+ constructor(table: MemoryTable<T>, column: string, baseCollection?: MemoryCollection<T>) {
12
12
  this.table = table;
13
- this.index = index;
13
+ this.column = column;
14
14
  this.baseCollection = baseCollection;
15
15
  }
16
16
 
@@ -116,10 +116,10 @@ export class MemoryWhereClause<T extends MemoryRecord = MemoryRecord> implements
116
116
  }
117
117
 
118
118
  private createCollection(predicate: (indexValue: unknown) => boolean): StorageCollection<T> {
119
- const condition = (record: T, _key: string): boolean => predicate(this.table.getIndexValue(record, this.index));
119
+ const condition = (record: T, _key: string): boolean => predicate(this.table.getIndexValue(record, this.column));
120
120
  if (this.baseCollection) {
121
121
  const combined = (record: T, key: string): boolean =>
122
- this.baseCollection!.matches(record, key) || predicate(this.table.getIndexValue(record, this.index));
122
+ this.baseCollection!.matches(record, key) || predicate(this.table.getIndexValue(record, this.column));
123
123
  return this.table.createCollectionFromPredicate(combined, this.baseCollection);
124
124
  }
125
125
  return this.table.createCollectionFromPredicate(condition);
@@ -9,7 +9,6 @@ import { cloneValue, createDefaultState, normalizeComparableValue, quoteIdentifi
9
9
  export class SQLiteTable<T = any> implements StorageTable<T> {
10
10
  readonly name: string;
11
11
  readonly schema: SQLiteTableSchemaMetadata;
12
- readonly hook: unknown = Object.freeze({});
13
12
  readonly raw: {
14
13
  add: (item: T) => Promise<string>;
15
14
  put: (item: T) => Promise<string>;
@@ -224,7 +223,7 @@ export class SQLiteTable<T = any> implements StorageTable<T> {
224
223
  await this.adapter.run(`DELETE FROM ${quoteIdentifier(this.name)} WHERE ${quoteIdentifier(LOCAL_PK)} IN (${placeholders})`, validKeys);
225
224
  }
226
225
 
227
- where(index: string | string[]): StorageWhereClause<T> {
226
+ where(index: string): StorageWhereClause<T> {
228
227
  return this.createWhereClause(index);
229
228
  }
230
229
 
@@ -246,10 +245,6 @@ export class SQLiteTable<T = any> implements StorageTable<T> {
246
245
  return this.createCollection({ limit: count });
247
246
  }
248
247
 
249
- mapToClass(_ctor: new (...args: any[]) => any): StorageTable<T> {
250
- return this;
251
- }
252
-
253
248
  async each(callback: (item: T) => void | Promise<void>): Promise<void> {
254
249
  const entries = await this.getEntries();
255
250
  for (const entry of entries) {
@@ -277,8 +272,8 @@ export class SQLiteTable<T = any> implements StorageTable<T> {
277
272
  });
278
273
  }
279
274
 
280
- createWhereClause(index: string | string[], baseCollection?: SQLiteCollection<T>): SQLiteWhereClause<T> {
281
- return new SQLiteWhereClause(this, index, baseCollection);
275
+ createWhereClause(column: string, baseCollection?: SQLiteCollection<T>): SQLiteWhereClause<T> {
276
+ return new SQLiteWhereClause(this, column, baseCollection);
282
277
  }
283
278
 
284
279
  async *iterateEntries(options?: SQLiteIterateEntriesOptions): AsyncGenerator<TableEntry<T>> {
@@ -5,55 +5,20 @@ import { SQLiteCollection } from './SQLiteCollection';
5
5
 
6
6
  export class SQLiteWhereClause<T = any> implements StorageWhereClause<T> {
7
7
  private readonly table: SQLiteTable<T>;
8
- private readonly index: string | string[];
8
+ private readonly column: string;
9
9
  private readonly baseCollection?: SQLiteCollection<T>;
10
10
 
11
- constructor(table: SQLiteTable<T>, index: string | string[], baseCollection?: SQLiteCollection<T>) {
11
+ constructor(table: SQLiteTable<T>, column: string, baseCollection?: SQLiteCollection<T>) {
12
12
  this.table = table;
13
- this.index = index;
13
+ this.column = column;
14
14
  this.baseCollection = baseCollection;
15
15
  }
16
16
 
17
- private getColumn(): string {
18
- // For compound indexes, we only support the first column in SQL conditions
19
- // Complex compound index queries fall back to JS
20
- if (Array.isArray(this.index)) {
21
- return this.index[0]!;
22
- }
23
- return this.index;
24
- }
25
-
26
- private isCompoundIndex(): boolean {
27
- return Array.isArray(this.index) && this.index.length > 1;
28
- }
29
-
30
- private getCompoundColumns(): string[] {
31
- return Array.isArray(this.index) ? this.index : [this.index];
32
- }
33
-
34
- private getCompoundValues(value: unknown): unknown[] {
35
- // For compound indexes, value should be an array of values matching each column
36
- if (Array.isArray(value)) {
37
- return value;
38
- }
39
- // Single value for single-column index
40
- return [value];
41
- }
42
-
43
17
  private createCollectionWithCondition(condition: SQLiteCondition): SQLiteCollection<T> {
44
18
  const base = this.baseCollection ?? this.table.createCollection();
45
19
  return base.addSqlCondition(condition);
46
20
  }
47
21
 
48
- private createCollectionWithJsPredicate(predicate: (record: T) => boolean): SQLiteCollection<T> {
49
- const base = this.baseCollection ?? this.table.createCollection();
50
- return base.jsFilter(predicate) as SQLiteCollection<T>;
51
- }
52
-
53
- private getIndexValue(record: T): unknown {
54
- return this.table.getIndexValue(record, this.index);
55
- }
56
-
57
22
  private flattenArgs<TValue>(args: any[]): TValue[] {
58
23
  if (args.length === 1 && Array.isArray(args[0])) {
59
24
  return args[0] as TValue[];
@@ -62,85 +27,53 @@ export class SQLiteWhereClause<T = any> implements StorageWhereClause<T> {
62
27
  }
63
28
 
64
29
  equals(value: any): StorageCollection<T> {
65
- if (this.isCompoundIndex()) {
66
- // Use native SQL: WHERE col1 = ? AND col2 = ? AND ...
67
- const columns = this.getCompoundColumns();
68
- const values = this.getCompoundValues(value);
69
- return this.createCollectionWithCondition({
70
- type: 'compoundEquals',
71
- columns,
72
- values,
73
- });
74
- }
75
30
  return this.createCollectionWithCondition({
76
31
  type: 'equals',
77
- column: this.getColumn(),
32
+ column: this.column,
78
33
  value,
79
34
  });
80
35
  }
81
36
 
82
37
  above(value: any): StorageCollection<T> {
83
- if (this.isCompoundIndex()) {
84
- return this.createCollectionWithJsPredicate((record) => this.table.compareValues(this.getIndexValue(record), value) > 0);
85
- }
86
38
  return this.createCollectionWithCondition({
87
39
  type: 'comparison',
88
- column: this.getColumn(),
40
+ column: this.column,
89
41
  op: '>',
90
42
  value,
91
43
  });
92
44
  }
93
45
 
94
46
  aboveOrEqual(value: any): StorageCollection<T> {
95
- if (this.isCompoundIndex()) {
96
- return this.createCollectionWithJsPredicate((record) => this.table.compareValues(this.getIndexValue(record), value) >= 0);
97
- }
98
47
  return this.createCollectionWithCondition({
99
48
  type: 'comparison',
100
- column: this.getColumn(),
49
+ column: this.column,
101
50
  op: '>=',
102
51
  value,
103
52
  });
104
53
  }
105
54
 
106
55
  below(value: any): StorageCollection<T> {
107
- if (this.isCompoundIndex()) {
108
- return this.createCollectionWithJsPredicate((record) => this.table.compareValues(this.getIndexValue(record), value) < 0);
109
- }
110
56
  return this.createCollectionWithCondition({
111
57
  type: 'comparison',
112
- column: this.getColumn(),
58
+ column: this.column,
113
59
  op: '<',
114
60
  value,
115
61
  });
116
62
  }
117
63
 
118
64
  belowOrEqual(value: any): StorageCollection<T> {
119
- if (this.isCompoundIndex()) {
120
- return this.createCollectionWithJsPredicate((record) => this.table.compareValues(this.getIndexValue(record), value) <= 0);
121
- }
122
65
  return this.createCollectionWithCondition({
123
66
  type: 'comparison',
124
- column: this.getColumn(),
67
+ column: this.column,
125
68
  op: '<=',
126
69
  value,
127
70
  });
128
71
  }
129
72
 
130
73
  between(lower: any, upper: any, includeLower = true, includeUpper = false): StorageCollection<T> {
131
- if (this.isCompoundIndex()) {
132
- return this.createCollectionWithJsPredicate((record) => {
133
- const value = this.getIndexValue(record);
134
- const lowerCmp = this.table.compareValues(value, lower);
135
- const upperCmp = this.table.compareValues(value, upper);
136
- const lowerPass = includeLower ? lowerCmp >= 0 : lowerCmp > 0;
137
- const upperPass = includeUpper ? upperCmp <= 0 : upperCmp < 0;
138
- return lowerPass && upperPass;
139
- });
140
- }
141
74
  return this.createCollectionWithCondition({
142
75
  type: 'between',
143
- column: this.getColumn(),
76
+ column: this.column,
144
77
  lower,
145
78
  upper,
146
79
  includeLower,
@@ -149,24 +82,19 @@ export class SQLiteWhereClause<T = any> implements StorageWhereClause<T> {
149
82
  }
150
83
 
151
84
  inAnyRange(ranges: Array<[any, any]>, options?: { includeLower?: boolean; includeUpper?: boolean }): StorageCollection<T> {
152
- // inAnyRange with multiple ranges uses OR logic - can be expressed in SQL
153
- if (this.isCompoundIndex() || ranges.length === 0) {
154
- return this.createCollectionWithJsPredicate((record) => {
155
- const value = this.getIndexValue(record);
156
- return ranges.some(([lower, upper]) => {
157
- const lowerCmp = this.table.compareValues(value, lower);
158
- const upperCmp = this.table.compareValues(value, upper);
159
- const lowerPass = options?.includeLower !== false ? lowerCmp >= 0 : lowerCmp > 0;
160
- const upperPass = options?.includeUpper ? upperCmp <= 0 : upperCmp < 0;
161
- return lowerPass && upperPass;
162
- });
163
- });
85
+ if (ranges.length === 0) {
86
+ // Empty ranges = no matches
87
+ return this.createCollectionWithCondition({
88
+ type: 'comparison',
89
+ column: this.column,
90
+ op: '=',
91
+ value: null,
92
+ }).jsFilter(() => false) as SQLiteCollection<T>;
164
93
  }
165
94
 
166
- const column = this.getColumn();
167
95
  const orConditions: SQLiteCondition[] = ranges.map(([lower, upper]) => ({
168
96
  type: 'between' as const,
169
- column,
97
+ column: this.column,
170
98
  lower,
171
99
  upper,
172
100
  includeLower: options?.includeLower !== false,
@@ -180,31 +108,21 @@ export class SQLiteWhereClause<T = any> implements StorageWhereClause<T> {
180
108
  }
181
109
 
182
110
  startsWith(prefix: string): StorageCollection<T> {
183
- if (this.isCompoundIndex()) {
184
- return this.createCollectionWithJsPredicate((record) => String(this.getIndexValue(record) ?? '').startsWith(prefix));
185
- }
186
111
  // SQLite LIKE pattern: 'prefix%' matches strings starting with prefix
187
112
  // Escape special LIKE characters in the prefix
188
113
  const escapedPrefix = prefix.replace(/[%_\\]/g, '\\$&');
189
114
  return this.createCollectionWithCondition({
190
115
  type: 'like',
191
- column: this.getColumn(),
116
+ column: this.column,
192
117
  pattern: `${escapedPrefix}%`,
193
118
  });
194
119
  }
195
120
 
196
121
  startsWithIgnoreCase(prefix: string): StorageCollection<T> {
197
- if (this.isCompoundIndex()) {
198
- return this.createCollectionWithJsPredicate((record) =>
199
- String(this.getIndexValue(record) ?? '')
200
- .toLowerCase()
201
- .startsWith(prefix.toLowerCase()),
202
- );
203
- }
204
122
  const escapedPrefix = prefix.replace(/[%_\\]/g, '\\$&');
205
123
  return this.createCollectionWithCondition({
206
124
  type: 'like',
207
- column: this.getColumn(),
125
+ column: this.column,
208
126
  pattern: `${escapedPrefix}%`,
209
127
  caseInsensitive: true,
210
128
  });
@@ -212,19 +130,20 @@ export class SQLiteWhereClause<T = any> implements StorageWhereClause<T> {
212
130
 
213
131
  startsWithAnyOf(...args: any[]): StorageCollection<T> {
214
132
  const prefixes = this.flattenArgs<string>(args);
215
- if (this.isCompoundIndex() || prefixes.length === 0) {
216
- return this.createCollectionWithJsPredicate((record) => {
217
- const value = String(this.getIndexValue(record) ?? '');
218
- return prefixes.some((prefix) => value.startsWith(prefix));
219
- });
133
+ if (prefixes.length === 0) {
134
+ return this.createCollectionWithCondition({
135
+ type: 'comparison',
136
+ column: this.column,
137
+ op: '=',
138
+ value: null,
139
+ }).jsFilter(() => false) as SQLiteCollection<T>;
220
140
  }
221
141
 
222
- const column = this.getColumn();
223
142
  const orConditions: SQLiteCondition[] = prefixes.map((prefix) => {
224
143
  const escapedPrefix = prefix.replace(/[%_\\]/g, '\\$&');
225
144
  return {
226
145
  type: 'like' as const,
227
- column,
146
+ column: this.column,
228
147
  pattern: `${escapedPrefix}%`,
229
148
  };
230
149
  });
@@ -237,20 +156,20 @@ export class SQLiteWhereClause<T = any> implements StorageWhereClause<T> {
237
156
 
238
157
  startsWithAnyOfIgnoreCase(...args: any[]): StorageCollection<T> {
239
158
  const prefixes = this.flattenArgs<string>(args);
240
- if (this.isCompoundIndex() || prefixes.length === 0) {
241
- const lowerPrefixes = prefixes.map((p) => p.toLowerCase());
242
- return this.createCollectionWithJsPredicate((record) => {
243
- const value = String(this.getIndexValue(record) ?? '').toLowerCase();
244
- return lowerPrefixes.some((prefix) => value.startsWith(prefix));
245
- });
159
+ if (prefixes.length === 0) {
160
+ return this.createCollectionWithCondition({
161
+ type: 'comparison',
162
+ column: this.column,
163
+ op: '=',
164
+ value: null,
165
+ }).jsFilter(() => false) as SQLiteCollection<T>;
246
166
  }
247
167
 
248
- const column = this.getColumn();
249
168
  const orConditions: SQLiteCondition[] = prefixes.map((prefix) => {
250
169
  const escapedPrefix = prefix.replace(/[%_\\]/g, '\\$&');
251
170
  return {
252
171
  type: 'like' as const,
253
- column,
172
+ column: this.column,
254
173
  pattern: `${escapedPrefix}%`,
255
174
  caseInsensitive: true,
256
175
  };
@@ -263,12 +182,9 @@ export class SQLiteWhereClause<T = any> implements StorageWhereClause<T> {
263
182
  }
264
183
 
265
184
  equalsIgnoreCase(value: string): StorageCollection<T> {
266
- if (this.isCompoundIndex()) {
267
- return this.createCollectionWithJsPredicate((record) => String(this.getIndexValue(record) ?? '').toLowerCase() === value.toLowerCase());
268
- }
269
185
  return this.createCollectionWithCondition({
270
186
  type: 'equals',
271
- column: this.getColumn(),
187
+ column: this.column,
272
188
  value,
273
189
  caseInsensitive: true,
274
190
  });
@@ -276,38 +192,18 @@ export class SQLiteWhereClause<T = any> implements StorageWhereClause<T> {
276
192
 
277
193
  anyOf(...args: any[]): StorageCollection<T> {
278
194
  const values = this.flattenArgs<any>(args);
279
- if (this.isCompoundIndex()) {
280
- // Use native SQL: (col1 = ? AND col2 = ?) OR (col1 = ? AND col2 = ?) OR ...
281
- const columns = this.getCompoundColumns();
282
- const orConditions: SQLiteCondition[] = values.map((value) => ({
283
- type: 'compoundEquals' as const,
284
- columns,
285
- values: this.getCompoundValues(value),
286
- }));
287
- return this.createCollectionWithCondition({
288
- type: 'or',
289
- conditions: orConditions,
290
- });
291
- }
292
195
  return this.createCollectionWithCondition({
293
196
  type: 'in',
294
- column: this.getColumn(),
197
+ column: this.column,
295
198
  values,
296
199
  });
297
200
  }
298
201
 
299
202
  anyOfIgnoreCase(...args: any[]): StorageCollection<T> {
300
203
  const values = this.flattenArgs<string>(args);
301
- if (this.isCompoundIndex()) {
302
- const lowerValues = values.map((v) => v.toLowerCase());
303
- return this.createCollectionWithJsPredicate((record) => {
304
- const value = String(this.getIndexValue(record) ?? '').toLowerCase();
305
- return lowerValues.includes(value);
306
- });
307
- }
308
204
  return this.createCollectionWithCondition({
309
205
  type: 'in',
310
- column: this.getColumn(),
206
+ column: this.column,
311
207
  values,
312
208
  caseInsensitive: true,
313
209
  });
@@ -315,25 +211,17 @@ export class SQLiteWhereClause<T = any> implements StorageWhereClause<T> {
315
211
 
316
212
  noneOf(...args: any[]): StorageCollection<T> {
317
213
  const values = this.flattenArgs<any>(args);
318
- if (this.isCompoundIndex()) {
319
- return this.createCollectionWithJsPredicate((record) =>
320
- values.every((candidate) => this.table.compareValues(this.getIndexValue(record), candidate) !== 0),
321
- );
322
- }
323
214
  return this.createCollectionWithCondition({
324
215
  type: 'notIn',
325
- column: this.getColumn(),
216
+ column: this.column,
326
217
  values,
327
218
  });
328
219
  }
329
220
 
330
221
  notEqual(value: any): StorageCollection<T> {
331
- if (this.isCompoundIndex()) {
332
- return this.createCollectionWithJsPredicate((record) => this.table.compareValues(this.getIndexValue(record), value) !== 0);
333
- }
334
222
  return this.createCollectionWithCondition({
335
223
  type: 'comparison',
336
- column: this.getColumn(),
224
+ column: this.column,
337
225
  op: '!=',
338
226
  value,
339
227
  });
@@ -59,12 +59,6 @@ const buildCondition = (condition: SQLiteCondition): BuiltCondition => {
59
59
  return { clause: `(${subClauses.join(' OR ')})`, parameters: subParams };
60
60
  }
61
61
 
62
- // Handle compound equals (multiple columns ANDed together)
63
- if (condition.type === 'compoundEquals') {
64
- const clauses = condition.columns.map((col) => `${quoteIdentifier(col)} = ?`);
65
- return { clause: `(${clauses.join(' AND ')})`, parameters: condition.values };
66
- }
67
-
68
62
  const col = quoteIdentifier(condition.column);
69
63
 
70
64
  switch (condition.type) {
@@ -69,12 +69,6 @@ export interface SQLiteConditionOr {
69
69
  conditions: SQLiteCondition[];
70
70
  }
71
71
 
72
- export interface SQLiteConditionCompoundEquals {
73
- type: 'compoundEquals';
74
- columns: string[];
75
- values: unknown[];
76
- }
77
-
78
72
  export type SQLiteCondition =
79
73
  | SQLiteConditionEquals
80
74
  | SQLiteConditionComparison
@@ -82,8 +76,7 @@ export type SQLiteCondition =
82
76
  | SQLiteConditionIn
83
77
  | SQLiteConditionNotIn
84
78
  | SQLiteConditionLike
85
- | SQLiteConditionOr
86
- | SQLiteConditionCompoundEquals;
79
+ | SQLiteConditionOr;
87
80
 
88
81
  export interface SQLiteCollectionState<T> {
89
82
  /** SQL-expressible WHERE conditions (ANDed together) */
@@ -77,7 +77,6 @@ export type AddItem<T> = Omit<T, '_localId'> & { _localId?: string };
77
77
  export interface StorageTable<T = any> {
78
78
  readonly name: string;
79
79
  readonly schema: unknown;
80
- readonly hook: unknown;
81
80
  add(item: AddItem<T>): Promise<string>;
82
81
  put(item: T): Promise<string>;
83
82
  update(key: string, changes: Partial<T>): Promise<number>;
@@ -91,12 +90,11 @@ export interface StorageTable<T = any> {
91
90
  bulkGet(keys: string[]): Promise<Array<T | undefined>>;
92
91
  bulkUpdate(keysAndChanges: Array<{ key: string; changes: Partial<T> }>): Promise<number>;
93
92
  bulkDelete(keys: string[]): Promise<void>;
94
- where(index: string | string[]): StorageWhereClause<T>;
93
+ where(index: string): StorageWhereClause<T>;
95
94
  orderBy(index: string | string[]): StorageCollection<T>;
96
95
  reverse(): StorageCollection<T>;
97
96
  offset(offset: number): StorageCollection<T>;
98
97
  limit(count: number): StorageCollection<T>;
99
- mapToClass(ctor: new (...args: any[]) => any): StorageTable<T>;
100
98
  each(callback: (item: T) => void | Promise<void>): Promise<void>;
101
99
  jsFilter(predicate: (item: T) => boolean): StorageCollection<T>;
102
100
  // The "raw" property exposes the underlying storage operations without Dync sync logic.