@promakeai/dbreact 1.0.3 → 1.0.4

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/README.md CHANGED
@@ -4,12 +4,12 @@ React hooks and providers for schema-driven, multi-language databases. Type-safe
4
4
 
5
5
  ## Features
6
6
 
7
- - **Type-Safe Hooks** - Generated TypeScript types and React hooks
7
+ - **Type-Safe Hooks** - Generic React hooks with generated TypeScript types
8
8
  - **Multi-Language Support** - Automatic translation queries with fallback
9
9
  - **Browser SQLite** - sql.js WASM adapter for offline-first apps
10
- - **React Query Integration** - Built-in caching, loading states, optimistic updates
11
- - **Zero-Config Language Switching** - Change language, queries refetch automatically
12
- - **MongoDB-Style Queries** - Intuitive filter syntax (`$gt`, `$in`, `$like`, etc.)
10
+ - **React Query Integration** - Built-in caching, loading states, optimistic updates
11
+ - **Zero-Config Language Switching** - Change language, queries refetch automatically
12
+ - **MongoDB-Style Queries** - Intuitive filter syntax (`$gt`, `$in`, `$like`, `$contains`, etc.)
13
13
 
14
14
  ## Installation
15
15
 
@@ -26,11 +26,16 @@ npm install @promakeai/dbreact @tanstack/react-query
26
26
  ### 1. Setup Adapter
27
27
 
28
28
  ```tsx
29
- import { SqliteAdapter } from '@promakeai/dbreact';
30
-
31
- const adapter = new SqliteAdapter({
32
- storageKey: 'myapp-db', // localStorage key for persistence
33
- });
29
+ import { SqliteAdapter } from '@promakeai/dbreact';
30
+ import { parseJSONSchema } from '@promakeai/dbreact';
31
+ import schemaJson from './schema.json';
32
+
33
+ const schema = parseJSONSchema(schemaJson as any);
34
+
35
+ const adapter = new SqliteAdapter({
36
+ storageKey: 'myapp-db', // localStorage key for persistence
37
+ schema,
38
+ });
34
39
  ```
35
40
 
36
41
  ### 2. Wrap App with Provider
@@ -98,24 +103,27 @@ Main provider component that wraps your application.
98
103
 
99
104
  ```tsx
100
105
  <DbProvider
101
- adapter={adapter}
102
- lang="tr"
103
- fallbackLang="en"
104
- autoConnect={true}
105
- >
106
+ adapter={adapter}
107
+ schema={schema}
108
+ lang="tr"
109
+ fallbackLang="en"
110
+ autoConnect={true}
111
+ >
106
112
  <App />
107
113
  </DbProvider>
108
114
  ```
109
115
 
110
116
  **Props:**
111
117
 
112
- | Prop | Type | Required | Default | Description |
113
- |------|------|----------|---------|-------------|
114
- | `adapter` | `IDataAdapter` | Yes | - | Database adapter instance |
115
- | `lang` | `string` | No | `'en'` | Current language code |
116
- | `fallbackLang` | `string` | No | `'en'` | Fallback language |
117
- | `autoConnect` | `boolean` | No | `true` | Auto-connect on mount |
118
- | `children` | `ReactNode` | Yes | - | Child components |
118
+ | Prop | Type | Required | Default | Description |
119
+ |------|------|----------|---------|-------------|
120
+ | `adapter` | `IDataAdapter` | Yes | - | Database adapter instance |
121
+ | `schema` | `SchemaDefinition` | No | - | Enables populate + typed serialization |
122
+ | `lang` | `string` | No | `'en'` | Current language code |
123
+ | `fallbackLang` | `string` | No | `'en'` | Fallback language |
124
+ | `autoConnect` | `boolean` | No | `true` | Auto-connect on mount |
125
+ | `queryClient` | `QueryClient` | No | Internal | Provide a custom React Query client |
126
+ | `children` | `ReactNode` | Yes | - | Child components |
119
127
 
120
128
  ---
121
129
 
@@ -143,19 +151,29 @@ const { data, isLoading, error, refetch } = useDbList<Product>('products', {
143
151
  | `orderBy` | `array` | Sort order `[{ field, direction }]` |
144
152
  | `limit` | `number` | Max records to return |
145
153
  | `offset` | `number` | Skip records |
146
- | `populate` | `string[]` | Resolve foreign key references |
154
+ | `populate` | `PopulateOption` | Resolve foreign key references (string, array, or object) |
147
155
  | `enabled` | `boolean` | Enable/disable query |
148
156
 
149
- #### useDbGet
150
-
151
- Fetch single record by ID.
152
-
153
- ```tsx
154
- const { data: product, isLoading } = useDbGet<Product>('products', productId, {
155
- populate: ['categoryId'],
156
- enabled: !!productId,
157
- });
158
- ```
157
+ #### useDbGet
158
+
159
+ Fetch single record by ID.
160
+
161
+ ```tsx
162
+ const { data: product, isLoading } = useDbGet<Product>('products', productId, {
163
+ populate: ['categoryId'],
164
+ enabled: !!productId,
165
+ });
166
+ ```
167
+
168
+ Find-one style (by where clause):
169
+
170
+ ```tsx
171
+ const { data: product } = useDbGet<Product>('products', {
172
+ where: { slug: 'my-product' },
173
+ enabled: !!slug,
174
+ populate: { categoryId: true },
175
+ });
176
+ ```
159
177
 
160
178
  ---
161
179
 
@@ -182,13 +200,13 @@ createProduct.mutate(
182
200
  Update an existing record.
183
201
 
184
202
  ```tsx
185
- const updateProduct = useDbUpdate<Product>('products', productId);
186
-
187
- updateProduct.mutate(
188
- { price: 89.99 },
189
- {
190
- onSuccess: () => console.log('Updated'),
191
- }
203
+ const updateProduct = useDbUpdate<Product>('products');
204
+
205
+ updateProduct.mutate(
206
+ { id: productId, data: { price: 89.99 } },
207
+ {
208
+ onSuccess: () => console.log('Updated'),
209
+ }
192
210
  );
193
211
  ```
194
212
 
@@ -197,11 +215,11 @@ updateProduct.mutate(
197
215
  Delete a record.
198
216
 
199
217
  ```tsx
200
- const deleteProduct = useDbDelete('products', productId);
201
-
202
- deleteProduct.mutate(undefined, {
203
- onSuccess: () => console.log('Deleted'),
204
- });
218
+ const deleteProduct = useDbDelete('products');
219
+
220
+ deleteProduct.mutate(productId, {
221
+ onSuccess: () => console.log('Deleted'),
222
+ });
205
223
  ```
206
224
 
207
225
  ---
@@ -294,12 +312,16 @@ const adapter = new SqliteAdapter({
294
312
  { name: { $like: '%shirt%' } } // LIKE '%shirt%'
295
313
  { name: { $notLike: '%test%' } } // NOT LIKE '%test%'
296
314
 
297
- // Range
298
- { price: { $between: [10, 100] } } // BETWEEN 10 AND 100
299
-
300
- // Null
301
- { description: { $isNull: true } } // IS NULL
302
- { description: { $isNull: false } } // IS NOT NULL
315
+ // Range
316
+ { price: { $between: [10, 100] } } // BETWEEN 10 AND 100
317
+
318
+ // Null
319
+ { description: { $isNull: true } } // IS NULL
320
+ { description: { $isNull: false } } // IS NOT NULL
321
+
322
+ // JSON array contains
323
+ { tags: { $contains: "sale" } }
324
+ { tags: { $containsAny: ["sale", "new"] } }
303
325
 
304
326
  // Logical
305
327
  { $and: [
@@ -318,18 +340,18 @@ const adapter = new SqliteAdapter({
318
340
  ### Query Interface
319
341
 
320
342
  ```typescript
321
- interface QueryOptions {
322
- where?: Record<string, unknown>;
323
- orderBy?: Array<{
324
- field: string;
325
- direction: 'ASC' | 'DESC';
326
- }>;
327
- limit?: number;
328
- offset?: number;
329
- populate?: string[];
330
- lang?: string;
331
- fallbackLang?: string;
332
- }
343
+ interface QueryOptions {
344
+ where?: Record<string, unknown>;
345
+ orderBy?: Array<{
346
+ field: string;
347
+ direction: 'ASC' | 'DESC';
348
+ }>;
349
+ limit?: number;
350
+ offset?: number;
351
+ populate?: PopulateOption;
352
+ lang?: string;
353
+ fallbackLang?: string;
354
+ }
333
355
  ```
334
356
 
335
357
  ---
@@ -387,36 +409,32 @@ function LanguageSwitcher() {
387
409
 
388
410
  ---
389
411
 
390
- ## Generated Hooks
391
-
392
- Generate type-safe hooks from your schema:
393
-
394
- ```bash
395
- dbcli generate --schema ./schema.ts --output ./src/db/generated
396
- ```
397
-
398
- **Generated files:**
399
- - `types.ts` - TypeScript interfaces for each table
400
- - `hooks.ts` - Type-safe hooks for each table
401
-
402
- ```tsx
403
- // Generated hooks usage
404
- import { useProducts, useProduct, useCreateProduct } from './db/generated/hooks';
405
-
406
- function ProductManager() {
407
- const { data: products } = useProducts({
408
- where: { stock: { $gt: 0 } },
409
- });
410
-
411
- const { data: product } = useProduct(1);
412
-
413
- const createProduct = useCreateProduct();
414
-
415
- return (
416
- // ...
417
- );
418
- }
419
- ```
412
+ ## Generated Types + Generic Hooks
413
+
414
+ Generate runtime schema and TypeScript interfaces:
415
+
416
+ ```bash
417
+ dbcli generate --schema ./schema.json --output ./src/db
418
+ ```
419
+
420
+ `dbcli generate` writes `schema.json` and `types.ts`. React hooks are imported from `@promakeai/dbreact`:
421
+
422
+ ```tsx
423
+ import { useDbList, useDbGet, useDbCreate } from '@promakeai/dbreact';
424
+ import type { DbProduct, DbProductInput } from './db/types';
425
+
426
+ function ProductManager() {
427
+ const { data: products } = useDbList<DbProduct>('products', {
428
+ where: { stock: { $gt: 0 } },
429
+ });
430
+
431
+ const { data: product } = useDbGet<DbProduct>('products', 1);
432
+
433
+ const createProduct = useDbCreate<DbProduct, DbProductInput>('products');
434
+
435
+ return null;
436
+ }
437
+ ```
420
438
 
421
439
  ---
422
440
 
@@ -425,15 +443,10 @@ function ProductManager() {
425
443
  ### Custom React Query Options
426
444
 
427
445
  ```tsx
428
- const { data } = useDbList('products', {
429
- where: { active: true },
430
- }, {
431
- // React Query options
432
- staleTime: 1000 * 60 * 5, // 5 minutes
433
- gcTime: 1000 * 60 * 30, // 30 minutes
434
- refetchOnWindowFocus: false,
435
- retry: 3,
436
- });
446
+ const { data } = useDbList('products', {
447
+ where: { active: true },
448
+ limit: 50,
449
+ });
437
450
  ```
438
451
 
439
452
  ### Direct Adapter Access
@@ -467,7 +480,7 @@ function AdvancedSearch() {
467
480
  ```tsx
468
481
  function ProductPrice({ product }) {
469
482
  const queryClient = useQueryClient();
470
- const updateProduct = useDbUpdate('products', product.id);
483
+ const updateProduct = useDbUpdate('products');
471
484
 
472
485
  const handlePriceChange = async (newPrice: number) => {
473
486
  // Optimistic update
@@ -476,7 +489,10 @@ function ProductPrice({ product }) {
476
489
  { ...product, price: newPrice }
477
490
  );
478
491
 
479
- await updateProduct.mutateAsync({ price: newPrice });
492
+ await updateProduct.mutateAsync({
493
+ id: product.id,
494
+ data: { price: newPrice },
495
+ });
480
496
  };
481
497
 
482
498
  return <PriceInput value={product.price} onChange={handlePriceChange} />;
@@ -568,13 +584,13 @@ function ProductSearch() {
568
584
  Full TypeScript support with generated types:
569
585
 
570
586
  ```typescript
571
- import type { Product, ProductInput } from './db/generated/types';
587
+ import type { DbProduct, DbProductInput } from './db/types';
572
588
 
573
589
  // Type-safe queries
574
- const products: Product[] = await adapter.list('products');
590
+ const products: DbProduct[] = await adapter.list('products');
575
591
 
576
592
  // Type-safe creates
577
- const newProduct: ProductInput = {
593
+ const newProduct: DbProductInput = {
578
594
  sku: 'SHIRT-001',
579
595
  price: 99.99,
580
596
  };
@@ -32,6 +32,7 @@ export interface SqliteAdapterConfig {
32
32
  export declare class SqliteAdapter implements IDataAdapter {
33
33
  private db;
34
34
  private SQL;
35
+ private tableColumnsCache;
35
36
  private config;
36
37
  schema?: SchemaDefinition;
37
38
  defaultLang?: string;
@@ -141,6 +142,8 @@ export declare class SqliteAdapter implements IDataAdapter {
141
142
  created: number;
142
143
  ids: (number | bigint)[];
143
144
  }>;
145
+ private getAvailableMainFallbackFields;
146
+ private getTableColumns;
144
147
  updateMany(table: string, updates: {
145
148
  id: number | string;
146
149
  data: Record<string, unknown>;
@@ -1 +1 @@
1
- {"version":3,"file":"SqliteAdapter.d.ts","sourceRoot":"","sources":["../../adapters/SqliteAdapter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SqliteAdapter.d.ts","sourceRoot":"","sources":["../../adapters/SqliteAdapter.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -224,6 +224,7 @@ import {
224
224
  class SqliteAdapter {
225
225
  db = null;
226
226
  SQL = null;
227
+ tableColumnsCache = new Map;
227
228
  config;
228
229
  schema;
229
230
  defaultLang;
@@ -241,6 +242,7 @@ class SqliteAdapter {
241
242
  setSchema(schema) {
242
243
  this.schema = schema;
243
244
  this.config.schema = schema;
245
+ this.tableColumnsCache.clear();
244
246
  }
245
247
  async connect() {
246
248
  this.SQL = await initSqlJs({
@@ -348,6 +350,7 @@ class SqliteAdapter {
348
350
  schema: this.schema,
349
351
  lang: options.lang,
350
352
  fallbackLang: options.fallbackLang ?? this.defaultLang,
353
+ mainFallbackFields: await this.getAvailableMainFallbackFields(table),
351
354
  where: options.where,
352
355
  orderBy: options.orderBy,
353
356
  limit: options.limit,
@@ -377,7 +380,7 @@ class SqliteAdapter {
377
380
  const results = await this.list(table, { where: { id }, limit: 1 });
378
381
  return results[0] ?? null;
379
382
  }
380
- const { sql, params } = buildTranslationQueryById(table, this.schema, id, options.lang, options.fallbackLang ?? this.defaultLang);
383
+ const { sql, params } = buildTranslationQueryById(table, this.schema, id, options.lang, options.fallbackLang ?? this.defaultLang, await this.getAvailableMainFallbackFields(table));
381
384
  const rows = this.runQuery(sql, params);
382
385
  const deserialized = this.deserializeResults(table, rows);
383
386
  return deserialized[0] ?? null;
@@ -573,6 +576,7 @@ class SqliteAdapter {
573
576
  this.persist();
574
577
  this.db.close();
575
578
  this.db = null;
579
+ this.tableColumnsCache.clear();
576
580
  }
577
581
  }
578
582
  async beginTransaction() {
@@ -615,6 +619,25 @@ class SqliteAdapter {
615
619
  this.persist();
616
620
  return { created: ids.length, ids };
617
621
  }
622
+ async getAvailableMainFallbackFields(table) {
623
+ const tableSchema = this.schema?.tables[table];
624
+ if (!tableSchema)
625
+ return [];
626
+ const translatableFields = getTranslatableFields(tableSchema);
627
+ if (translatableFields.length === 0)
628
+ return [];
629
+ const tableColumns = await this.getTableColumns(table);
630
+ return translatableFields.filter((field) => tableColumns.has(field));
631
+ }
632
+ async getTableColumns(table) {
633
+ const cached = this.tableColumnsCache.get(table);
634
+ if (cached)
635
+ return cached;
636
+ const schema = await this.getTableSchema(table);
637
+ const columnSet = new Set(schema.map((col) => col.name));
638
+ this.tableColumnsCache.set(table, columnSet);
639
+ return columnSet;
640
+ }
618
641
  async updateMany(table, updates) {
619
642
  let updated = 0;
620
643
  for (const { id, data } of updates) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@promakeai/dbreact",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "React client for schema-driven multi-language database",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -40,7 +40,7 @@
40
40
  "sql.js": ">=1.11.0"
41
41
  },
42
42
  "dependencies": {
43
- "@promakeai/orm": "1.0.3"
43
+ "@promakeai/orm": "1.0.4"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@tanstack/query-core": "5.90.20",