@promakeai/dbreact 1.0.1 → 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 +122 -106
- package/dist/adapters/RestAdapter.d.ts +83 -0
- package/dist/adapters/SqliteAdapter.d.ts +169 -0
- package/dist/adapters/SqliteAdapter.d.ts.map +1 -1
- package/dist/core/DataManager.d.ts +147 -0
- package/dist/hooks/useDataManager.d.ts +7 -0
- package/dist/hooks/useDbHooks.d.ts +132 -0
- package/dist/hooks/useDbHooks.d.ts.map +1 -1
- package/dist/hooks/useDbLang.d.ts +7 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +61 -12
- package/dist/providers/DbProvider.d.ts +47 -0
- package/dist/providers/DbProvider.d.ts.map +1 -1
- package/dist/types.d.ts +36 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/whereBuilder.d.ts +39 -0
- package/package.json +5 -2
- package/SKILL.md +0 -311
- package/providers/DbProvider.tsx +0 -191
package/SKILL.md
DELETED
|
@@ -1,311 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: dbreact
|
|
3
|
-
description: |
|
|
4
|
-
React hooks and providers for schema-driven multi-language databases (@promakeai/dbreact).
|
|
5
|
-
Use when: integrating React apps with SQLite database, using DbProvider setup,
|
|
6
|
-
data hooks (useDbList, useDbGet, useDbCreate, useDbUpdate, useDbDelete),
|
|
7
|
-
language switching (useDbLang), SqliteAdapter for browser, React Query patterns,
|
|
8
|
-
or any @promakeai/dbreact task.
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
# dbreact - React Database Integration
|
|
12
|
-
|
|
13
|
-
## Installation
|
|
14
|
-
|
|
15
|
-
```bash
|
|
16
|
-
npm install @promakeai/dbreact @promakeai/orm @tanstack/react-query sql.js
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
Peer dependencies: `react >= 18`, `react-dom >= 18`, `@tanstack/react-query >= 5`
|
|
20
|
-
|
|
21
|
-
---
|
|
22
|
-
|
|
23
|
-
## Quick Setup
|
|
24
|
-
|
|
25
|
-
```tsx
|
|
26
|
-
import { DbProvider, SqliteAdapter, parseJSONSchema } from '@promakeai/dbreact';
|
|
27
|
-
import schema from './db/schema.json';
|
|
28
|
-
|
|
29
|
-
const adapter = new SqliteAdapter({
|
|
30
|
-
storageKey: 'myapp',
|
|
31
|
-
schema: parseJSONSchema(schema),
|
|
32
|
-
defaultLang: 'en',
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
function App() {
|
|
36
|
-
return (
|
|
37
|
-
<DbProvider adapter={adapter} lang="en" fallbackLang="en">
|
|
38
|
-
<YourApp />
|
|
39
|
-
</DbProvider>
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
---
|
|
45
|
-
|
|
46
|
-
## DbProvider Props
|
|
47
|
-
|
|
48
|
-
```tsx
|
|
49
|
-
interface DbProviderProps {
|
|
50
|
-
adapter: IDataAdapter; // Required: SqliteAdapter instance
|
|
51
|
-
lang?: string; // Current language (default: 'en')
|
|
52
|
-
fallbackLang?: string; // Fallback if translation missing (default: 'en')
|
|
53
|
-
autoConnect?: boolean; // Auto-connect on mount (default: true)
|
|
54
|
-
queryClient?: QueryClient; // Custom React Query client (optional)
|
|
55
|
-
}
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
Language changes automatically invalidate all queries and refetch with new language.
|
|
59
|
-
|
|
60
|
-
---
|
|
61
|
-
|
|
62
|
-
## SqliteAdapter Config
|
|
63
|
-
|
|
64
|
-
```tsx
|
|
65
|
-
const adapter = new SqliteAdapter({
|
|
66
|
-
storageKey: 'myapp', // localStorage key
|
|
67
|
-
schema: parsedSchema, // For translation support
|
|
68
|
-
defaultLang: 'en', // Default language
|
|
69
|
-
initialData?: Uint8Array, // Seed with existing DB
|
|
70
|
-
wasmPath?: string, // Custom sql.js WASM path
|
|
71
|
-
});
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
### Loading Existing Database
|
|
75
|
-
|
|
76
|
-
```tsx
|
|
77
|
-
// Load from base64 file
|
|
78
|
-
const response = await fetch('/app.db.b64');
|
|
79
|
-
const base64 = await response.text();
|
|
80
|
-
const bytes = Uint8Array.from(atob(base64), c => c.charCodeAt(0));
|
|
81
|
-
|
|
82
|
-
const adapter = new SqliteAdapter({
|
|
83
|
-
storageKey: 'myapp',
|
|
84
|
-
initialData: bytes,
|
|
85
|
-
schema: parseJSONSchema(schema),
|
|
86
|
-
});
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
---
|
|
90
|
-
|
|
91
|
-
## Data Hooks
|
|
92
|
-
|
|
93
|
-
### useDbList<T>(table, options?)
|
|
94
|
-
|
|
95
|
-
Query multiple records.
|
|
96
|
-
|
|
97
|
-
```tsx
|
|
98
|
-
interface ListOptions {
|
|
99
|
-
where?: Record<string, unknown>; // MongoDB-style filter
|
|
100
|
-
orderBy?: Array<{ field: string; direction: 'ASC' | 'DESC' }>;
|
|
101
|
-
limit?: number;
|
|
102
|
-
offset?: number;
|
|
103
|
-
enabled?: boolean; // Conditional query
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
function ProductList() {
|
|
107
|
-
const { data, isLoading, error } = useDbList<Product>('products', {
|
|
108
|
-
where: { stock: { $gt: 0 } },
|
|
109
|
-
orderBy: [{ field: 'name', direction: 'ASC' }],
|
|
110
|
-
limit: 10,
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
if (isLoading) return <div>Loading...</div>;
|
|
114
|
-
if (error) return <div>Error: {error.message}</div>;
|
|
115
|
-
|
|
116
|
-
return <ul>{data?.map(p => <li key={p.id}>{p.name}</li>)}</ul>;
|
|
117
|
-
}
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
### useDbGet<T>(table, id, options?)
|
|
121
|
-
|
|
122
|
-
Fetch single record by ID.
|
|
123
|
-
|
|
124
|
-
```tsx
|
|
125
|
-
function ProductDetail({ id }: { id: number }) {
|
|
126
|
-
const { data: product, isLoading } = useDbGet<Product>('products', id);
|
|
127
|
-
|
|
128
|
-
if (isLoading) return <div>Loading...</div>;
|
|
129
|
-
if (!product) return <div>Not found</div>;
|
|
130
|
-
|
|
131
|
-
return <div>{product.name} - ${product.price}</div>;
|
|
132
|
-
}
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
### useDbCreate<T>(table)
|
|
136
|
-
|
|
137
|
-
Create new record.
|
|
138
|
-
|
|
139
|
-
```tsx
|
|
140
|
-
function CreateProduct() {
|
|
141
|
-
const mutation = useDbCreate<Product>('products');
|
|
142
|
-
|
|
143
|
-
const handleCreate = () => {
|
|
144
|
-
mutation.mutate({ name: 'New Product', price: 99 });
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
return (
|
|
148
|
-
<button onClick={handleCreate} disabled={mutation.isPending}>
|
|
149
|
-
{mutation.isPending ? 'Creating...' : 'Create'}
|
|
150
|
-
</button>
|
|
151
|
-
);
|
|
152
|
-
}
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
### useDbUpdate<T>(table)
|
|
156
|
-
|
|
157
|
-
Update existing record.
|
|
158
|
-
|
|
159
|
-
```tsx
|
|
160
|
-
function EditProduct({ id }: { id: number }) {
|
|
161
|
-
const mutation = useDbUpdate<Product>('products');
|
|
162
|
-
|
|
163
|
-
const handleUpdate = () => {
|
|
164
|
-
mutation.mutate({ id, data: { price: 149 } });
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
return <button onClick={handleUpdate}>Update Price</button>;
|
|
168
|
-
}
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
### useDbDelete(table)
|
|
172
|
-
|
|
173
|
-
Delete record by ID.
|
|
174
|
-
|
|
175
|
-
```tsx
|
|
176
|
-
function DeleteProduct({ id }: { id: number }) {
|
|
177
|
-
const mutation = useDbDelete('products');
|
|
178
|
-
|
|
179
|
-
return (
|
|
180
|
-
<button onClick={() => mutation.mutate(id)}>
|
|
181
|
-
{mutation.isPending ? 'Deleting...' : 'Delete'}
|
|
182
|
-
</button>
|
|
183
|
-
);
|
|
184
|
-
}
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
---
|
|
188
|
-
|
|
189
|
-
## Language Hook
|
|
190
|
-
|
|
191
|
-
### useDbLang()
|
|
192
|
-
|
|
193
|
-
Access and change current language.
|
|
194
|
-
|
|
195
|
-
```tsx
|
|
196
|
-
function LanguageSwitcher() {
|
|
197
|
-
const { lang, setLang } = useDbLang();
|
|
198
|
-
|
|
199
|
-
return (
|
|
200
|
-
<select value={lang} onChange={(e) => setLang(e.target.value)}>
|
|
201
|
-
<option value="en">English</option>
|
|
202
|
-
<option value="tr">Turkish</option>
|
|
203
|
-
<option value="de">German</option>
|
|
204
|
-
</select>
|
|
205
|
-
);
|
|
206
|
-
}
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
When `setLang()` is called:
|
|
210
|
-
1. Provider state updates
|
|
211
|
-
2. All queries invalidated
|
|
212
|
-
3. Queries refetch with new language
|
|
213
|
-
4. UI updates automatically
|
|
214
|
-
|
|
215
|
-
---
|
|
216
|
-
|
|
217
|
-
## Context Hooks
|
|
218
|
-
|
|
219
|
-
### useDb()
|
|
220
|
-
|
|
221
|
-
Access connection state.
|
|
222
|
-
|
|
223
|
-
```tsx
|
|
224
|
-
const { adapter, isConnected, error } = useDb();
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
### useAdapter()
|
|
228
|
-
|
|
229
|
-
Direct adapter access for advanced operations.
|
|
230
|
-
|
|
231
|
-
```tsx
|
|
232
|
-
const adapter = useAdapter();
|
|
233
|
-
await adapter.createWithTranslations('products', data, translations);
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
---
|
|
237
|
-
|
|
238
|
-
## Query Operators
|
|
239
|
-
|
|
240
|
-
Same MongoDB-style operators as dbcli:
|
|
241
|
-
|
|
242
|
-
```tsx
|
|
243
|
-
useDbList('products', {
|
|
244
|
-
where: {
|
|
245
|
-
$and: [
|
|
246
|
-
{ price: { $between: [50, 500] } },
|
|
247
|
-
{ stock: { $gt: 0 } },
|
|
248
|
-
{ categoryId: { $in: [1, 5, 10] } },
|
|
249
|
-
{ $or: [{ active: true }, { featured: true }] }
|
|
250
|
-
]
|
|
251
|
-
}
|
|
252
|
-
});
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
Operators: `$eq`, `$ne`, `$gt`, `$gte`, `$lt`, `$lte`, `$in`, `$nin`, `$like`, `$notLike`, `$between`, `$isNull`, `$and`, `$or`, `$nor`, `$not`
|
|
256
|
-
|
|
257
|
-
---
|
|
258
|
-
|
|
259
|
-
## Type Definitions
|
|
260
|
-
|
|
261
|
-
Use generated types from `dbcli generate`:
|
|
262
|
-
|
|
263
|
-
```tsx
|
|
264
|
-
// src/db/types.ts (generated)
|
|
265
|
-
export interface DbProduct {
|
|
266
|
-
id: number;
|
|
267
|
-
name: string;
|
|
268
|
-
price: number;
|
|
269
|
-
stock: number;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
// Usage
|
|
273
|
-
const { data } = useDbList<DbProduct>('products');
|
|
274
|
-
const mutation = useDbCreate<DbProduct>('products');
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
---
|
|
278
|
-
|
|
279
|
-
## Best Practices
|
|
280
|
-
|
|
281
|
-
1. **Single DbProvider at root** - Don't nest providers
|
|
282
|
-
2. **Use generated types** - Type safety with `DbXxx` interfaces
|
|
283
|
-
3. **Conditional queries** - Use `enabled: false` to prevent unwanted fetches
|
|
284
|
-
4. **Handle all states** - Check `isLoading`, `error`, and empty data
|
|
285
|
-
5. **Language via hook** - Use `setLang()` not prop changes for proper invalidation
|
|
286
|
-
6. **Batch with adapter** - Use `adapter.createMany()` for bulk operations
|
|
287
|
-
7. **Check connection** - Use `useDb().isConnected` before critical operations
|
|
288
|
-
|
|
289
|
-
---
|
|
290
|
-
|
|
291
|
-
## Exports
|
|
292
|
-
|
|
293
|
-
```tsx
|
|
294
|
-
// Provider & Context
|
|
295
|
-
export { DbProvider, useDb, useAdapter, useDbLang };
|
|
296
|
-
|
|
297
|
-
// Data Hooks
|
|
298
|
-
export { useDbList, useDbGet, useDbCreate, useDbUpdate, useDbDelete };
|
|
299
|
-
|
|
300
|
-
// Adapter
|
|
301
|
-
export { SqliteAdapter };
|
|
302
|
-
|
|
303
|
-
// Schema
|
|
304
|
-
export { parseJSONSchema, defineSchema, f };
|
|
305
|
-
|
|
306
|
-
// Query Utilities
|
|
307
|
-
export { buildWhereClause };
|
|
308
|
-
|
|
309
|
-
// Types
|
|
310
|
-
export type { DbProviderConfig, DbContextValue, DbLangContextValue, ListOptions };
|
|
311
|
-
```
|
package/providers/DbProvider.tsx
DELETED
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Database Provider
|
|
3
|
-
*
|
|
4
|
-
* React context provider for database operations with language support.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
createContext,
|
|
9
|
-
useContext,
|
|
10
|
-
useState,
|
|
11
|
-
useEffect,
|
|
12
|
-
useMemo,
|
|
13
|
-
useCallback,
|
|
14
|
-
useRef,
|
|
15
|
-
type ReactNode,
|
|
16
|
-
} from "react";
|
|
17
|
-
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
18
|
-
import type {
|
|
19
|
-
IDataAdapter,
|
|
20
|
-
DbProviderConfig,
|
|
21
|
-
DbLangContextValue,
|
|
22
|
-
DbContextValue,
|
|
23
|
-
} from "../types";
|
|
24
|
-
|
|
25
|
-
// Database context
|
|
26
|
-
const DbContext = createContext<DbContextValue | null>(null);
|
|
27
|
-
|
|
28
|
-
// Language context
|
|
29
|
-
const DbLangContext = createContext<DbLangContextValue | null>(null);
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Default QueryClient for React Query
|
|
33
|
-
*/
|
|
34
|
-
const defaultQueryClient = new QueryClient({
|
|
35
|
-
defaultOptions: {
|
|
36
|
-
queries: {
|
|
37
|
-
staleTime: 1000 * 60 * 5, // 5 minutes
|
|
38
|
-
gcTime: 1000 * 60 * 30, // 30 minutes (formerly cacheTime)
|
|
39
|
-
refetchOnWindowFocus: false,
|
|
40
|
-
},
|
|
41
|
-
},
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
interface DbProviderProps extends DbProviderConfig {
|
|
45
|
-
children: ReactNode;
|
|
46
|
-
queryClient?: QueryClient;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Database Provider Component
|
|
51
|
-
*
|
|
52
|
-
* Wraps application with database context, language context, and React Query.
|
|
53
|
-
*
|
|
54
|
-
* @example
|
|
55
|
-
* ```tsx
|
|
56
|
-
* import { DbProvider, SqliteAdapter } from '@promakeai/dbreact';
|
|
57
|
-
*
|
|
58
|
-
* const adapter = new SqliteAdapter({ storageKey: 'myapp' });
|
|
59
|
-
*
|
|
60
|
-
* function App() {
|
|
61
|
-
* return (
|
|
62
|
-
* <DbProvider adapter={adapter} lang="tr" fallbackLang="en">
|
|
63
|
-
* <MyApp />
|
|
64
|
-
* </DbProvider>
|
|
65
|
-
* );
|
|
66
|
-
* }
|
|
67
|
-
* ```
|
|
68
|
-
*/
|
|
69
|
-
export function DbProvider({
|
|
70
|
-
adapter,
|
|
71
|
-
lang: langProp = "en",
|
|
72
|
-
fallbackLang = "en",
|
|
73
|
-
autoConnect = true,
|
|
74
|
-
queryClient = defaultQueryClient,
|
|
75
|
-
children,
|
|
76
|
-
}: DbProviderProps) {
|
|
77
|
-
const [isConnected, setIsConnected] = useState(false);
|
|
78
|
-
const [error, setError] = useState<Error | null>(null);
|
|
79
|
-
const [lang, setLangState] = useState(langProp);
|
|
80
|
-
const isFirstRender = useRef(true);
|
|
81
|
-
|
|
82
|
-
// Sync internal state when prop changes
|
|
83
|
-
useEffect(() => {
|
|
84
|
-
if (langProp !== lang) {
|
|
85
|
-
setLangState(langProp);
|
|
86
|
-
}
|
|
87
|
-
}, [langProp]);
|
|
88
|
-
|
|
89
|
-
// Invalidate all queries when language changes (skip first render)
|
|
90
|
-
useEffect(() => {
|
|
91
|
-
if (isFirstRender.current) {
|
|
92
|
-
isFirstRender.current = false;
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
// Invalidate all queries to refetch with new language
|
|
96
|
-
queryClient.invalidateQueries();
|
|
97
|
-
}, [lang]);
|
|
98
|
-
|
|
99
|
-
// Connect to adapter on mount
|
|
100
|
-
useEffect(() => {
|
|
101
|
-
if (!autoConnect) return;
|
|
102
|
-
|
|
103
|
-
let mounted = true;
|
|
104
|
-
|
|
105
|
-
async function connect() {
|
|
106
|
-
try {
|
|
107
|
-
await adapter.connect?.();
|
|
108
|
-
if (mounted) {
|
|
109
|
-
setIsConnected(true);
|
|
110
|
-
setError(null);
|
|
111
|
-
}
|
|
112
|
-
} catch (err) {
|
|
113
|
-
if (mounted) {
|
|
114
|
-
setError(err instanceof Error ? err : new Error(String(err)));
|
|
115
|
-
setIsConnected(false);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
connect();
|
|
121
|
-
|
|
122
|
-
return () => {
|
|
123
|
-
mounted = false;
|
|
124
|
-
};
|
|
125
|
-
}, [adapter, autoConnect]);
|
|
126
|
-
|
|
127
|
-
// setLang updates internal state (and triggers invalidation via effect)
|
|
128
|
-
const setLang = useCallback((newLang: string) => {
|
|
129
|
-
setLangState(newLang);
|
|
130
|
-
}, []);
|
|
131
|
-
|
|
132
|
-
// Database context value
|
|
133
|
-
const dbContextValue = useMemo<DbContextValue>(
|
|
134
|
-
() => ({
|
|
135
|
-
adapter,
|
|
136
|
-
isConnected,
|
|
137
|
-
error,
|
|
138
|
-
}),
|
|
139
|
-
[adapter, isConnected, error]
|
|
140
|
-
);
|
|
141
|
-
|
|
142
|
-
// Language context value
|
|
143
|
-
const langContextValue = useMemo<DbLangContextValue>(
|
|
144
|
-
() => ({
|
|
145
|
-
lang,
|
|
146
|
-
fallbackLang,
|
|
147
|
-
setLang,
|
|
148
|
-
}),
|
|
149
|
-
[lang, fallbackLang, setLang]
|
|
150
|
-
);
|
|
151
|
-
|
|
152
|
-
return (
|
|
153
|
-
<QueryClientProvider client={queryClient}>
|
|
154
|
-
<DbContext.Provider value={dbContextValue}>
|
|
155
|
-
<DbLangContext.Provider value={langContextValue}>
|
|
156
|
-
{children}
|
|
157
|
-
</DbLangContext.Provider>
|
|
158
|
-
</DbContext.Provider>
|
|
159
|
-
</QueryClientProvider>
|
|
160
|
-
);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Hook to access database context
|
|
165
|
-
*/
|
|
166
|
-
export function useDb(): DbContextValue {
|
|
167
|
-
const context = useContext(DbContext);
|
|
168
|
-
if (!context) {
|
|
169
|
-
throw new Error("useDb must be used within a DbProvider");
|
|
170
|
-
}
|
|
171
|
-
return context;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* Hook to access the raw adapter
|
|
176
|
-
*/
|
|
177
|
-
export function useAdapter(): IDataAdapter {
|
|
178
|
-
const { adapter } = useDb();
|
|
179
|
-
return adapter;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Hook to access language context
|
|
184
|
-
*/
|
|
185
|
-
export function useDbLang(): DbLangContextValue {
|
|
186
|
-
const context = useContext(DbLangContext);
|
|
187
|
-
if (!context) {
|
|
188
|
-
throw new Error("useDbLang must be used within a DbProvider");
|
|
189
|
-
}
|
|
190
|
-
return context;
|
|
191
|
-
}
|