@promakeai/dbreact 1.0.1 → 1.0.3

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.
@@ -0,0 +1,83 @@
1
+ /**
2
+ * REST API Adapter
3
+ *
4
+ * Fetches data from a REST API backend.
5
+ * Sends Accept-Language header for multi-language support.
6
+ */
7
+ import type { IDataAdapter, QueryOptions, PaginatedResult } from "../types";
8
+ export interface RestAdapterConfig {
9
+ /** Base URL for API (e.g., "https://api.example.com") */
10
+ baseUrl: string;
11
+ /** Language code for Accept-Language header */
12
+ lang?: string;
13
+ /** Custom headers to include in all requests */
14
+ headers?: Record<string, string>;
15
+ /** Custom fetch function (for testing/SSR) */
16
+ fetch?: typeof fetch;
17
+ }
18
+ /**
19
+ * REST API Adapter
20
+ *
21
+ * Makes HTTP requests to a REST API backend.
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * const adapter = new RestAdapter({
26
+ * baseUrl: 'https://api.example.com',
27
+ * lang: 'tr'
28
+ * });
29
+ * const users = await adapter.findMany('users');
30
+ * ```
31
+ */
32
+ export declare class RestAdapter implements IDataAdapter {
33
+ private config;
34
+ constructor(config: RestAdapterConfig);
35
+ connect(): Promise<void>;
36
+ private buildUrl;
37
+ private getHeaders;
38
+ private request;
39
+ private buildQueryParams;
40
+ findMany<T = unknown>(table: string, options?: QueryOptions): Promise<T[]>;
41
+ findOne<T = unknown>(table: string, options?: QueryOptions): Promise<T | null>;
42
+ findById<T = unknown>(table: string, id: number | string): Promise<T | null>;
43
+ count(table: string, options?: QueryOptions): Promise<number>;
44
+ paginate<T = unknown>(table: string, page: number, limit: number, options?: QueryOptions): Promise<PaginatedResult<T>>;
45
+ create<T = unknown>(table: string, data: Record<string, unknown>): Promise<T>;
46
+ update<T = unknown>(table: string, id: number | string, data: Record<string, unknown>): Promise<T>;
47
+ delete(table: string, id: number | string): Promise<boolean>;
48
+ execute(_query: string, _params?: unknown[]): Promise<void>;
49
+ executeQuery<T = unknown>(_query: string, _params?: unknown[]): Promise<T[]>;
50
+ seed(data: Record<string, Record<string, unknown>[]>): Promise<void>;
51
+ getTables(): Promise<string[]>;
52
+ getTableSchema(table: string): Promise<{
53
+ name: string;
54
+ type: string;
55
+ notnull: number;
56
+ pk: number;
57
+ }[]>;
58
+ close(): void;
59
+ /**
60
+ * Update language for subsequent requests
61
+ */
62
+ setLang(lang: string): void;
63
+ /**
64
+ * Get current language
65
+ */
66
+ getLang(): string;
67
+ createMany<T = unknown>(table: string, records: Record<string, unknown>[], options?: {
68
+ ignore?: boolean;
69
+ }): Promise<{
70
+ created: number;
71
+ ids: (number | bigint)[];
72
+ }>;
73
+ updateMany(table: string, updates: {
74
+ id: number | string;
75
+ data: Record<string, unknown>;
76
+ }[]): Promise<{
77
+ updated: number;
78
+ }>;
79
+ deleteMany(table: string, ids: (number | string)[]): Promise<{
80
+ deleted: number;
81
+ }>;
82
+ }
83
+ //# sourceMappingURL=RestAdapter.d.ts.map
@@ -0,0 +1,166 @@
1
+ /**
2
+ * Browser SQLite Adapter
3
+ *
4
+ * Uses sql.js (WASM) for in-browser SQLite database.
5
+ * Persists to localStorage for offline support.
6
+ */
7
+ import type { IDataAdapter, QueryOptions, PaginatedResult, SchemaDefinition } from "@promakeai/orm";
8
+ export interface SqliteAdapterConfig {
9
+ /** localStorage key for persistence (default: "dbreact_db") */
10
+ storageKey?: string;
11
+ /** sql.js WASM path (default: CDN) */
12
+ wasmPath?: string;
13
+ /** Initial data to seed if database is empty */
14
+ initialData?: Uint8Array;
15
+ /** Schema definition for translation support */
16
+ schema?: SchemaDefinition;
17
+ /** Default language for translations */
18
+ defaultLang?: string;
19
+ }
20
+ /**
21
+ * Browser SQLite Adapter
22
+ *
23
+ * Provides SQLite database in the browser using sql.js WASM.
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * const adapter = new SqliteAdapter({ storageKey: 'myapp' });
28
+ * await adapter.connect();
29
+ * const users = await adapter.list('users');
30
+ * ```
31
+ */
32
+ export declare class SqliteAdapter implements IDataAdapter {
33
+ private db;
34
+ private SQL;
35
+ private config;
36
+ schema?: SchemaDefinition;
37
+ defaultLang?: string;
38
+ constructor(config?: SqliteAdapterConfig);
39
+ setSchema(schema: SchemaDefinition): void;
40
+ connect(): Promise<void>;
41
+ private persist;
42
+ private getDb;
43
+ private runQuery;
44
+ /**
45
+ * Deserialize rows using schema field definitions (bool 0/1 → boolean, json TEXT → parsed)
46
+ */
47
+ private deserializeResults;
48
+ /**
49
+ * Serialize data for DB storage (bool → 0/1, json → TEXT)
50
+ */
51
+ private serializeData;
52
+ private buildSelectQuery;
53
+ /**
54
+ * List records from a table
55
+ */
56
+ list<T = unknown>(table: string, options?: QueryOptions): Promise<T[]>;
57
+ private listWithLang;
58
+ /**
59
+ * Get a single record by ID
60
+ */
61
+ get<T = unknown>(table: string, id: number | string, options?: {
62
+ lang?: string;
63
+ fallbackLang?: string;
64
+ }): Promise<T | null>;
65
+ findOne<T = unknown>(table: string, options?: {
66
+ where?: Record<string, unknown>;
67
+ lang?: string;
68
+ fallbackLang?: string;
69
+ }): Promise<T | null>;
70
+ private getWithLang;
71
+ /**
72
+ * Count records in a table
73
+ */
74
+ count(table: string, options?: QueryOptions): Promise<number>;
75
+ /**
76
+ * Paginate records
77
+ */
78
+ paginate<T = unknown>(table: string, page: number, limit: number, options?: QueryOptions): Promise<PaginatedResult<T>>;
79
+ /**
80
+ * Create a new record
81
+ */
82
+ create<T = unknown>(table: string, data: Record<string, unknown>): Promise<T>;
83
+ /**
84
+ * Create a record with explicit translations
85
+ */
86
+ createWithTranslations<T = unknown>(table: string, data: Record<string, unknown>, translations?: Record<string, Record<string, unknown>>): Promise<T>;
87
+ /**
88
+ * Update a record by ID
89
+ */
90
+ update<T = unknown>(table: string, id: number | string, data: Record<string, unknown>): Promise<T>;
91
+ /**
92
+ * Upsert a translation for a record
93
+ */
94
+ upsertTranslation(table: string, id: number | string, lang: string, data: Record<string, unknown>): Promise<void>;
95
+ /**
96
+ * Get all translations for a record
97
+ */
98
+ getTranslations<T = unknown>(table: string, id: number | string): Promise<T[]>;
99
+ /**
100
+ * Delete a record by ID
101
+ */
102
+ delete(table: string, id: number | string): Promise<boolean>;
103
+ /**
104
+ * Execute a raw SQL statement
105
+ */
106
+ execute(query: string, params?: unknown[]): Promise<{
107
+ changes: number;
108
+ lastInsertRowid: number | bigint;
109
+ }>;
110
+ /**
111
+ * Execute a raw SQL query and return results
112
+ */
113
+ raw<T = unknown>(query: string, params?: unknown[]): Promise<T[]>;
114
+ /**
115
+ * Seed database with initial data
116
+ */
117
+ seed(data: Record<string, Record<string, unknown>[]>): Promise<void>;
118
+ /**
119
+ * Get all table names
120
+ */
121
+ getTables(): Promise<string[]>;
122
+ /**
123
+ * Get table schema
124
+ */
125
+ getTableSchema(table: string): Promise<{
126
+ name: string;
127
+ type: string;
128
+ notnull: number;
129
+ pk: number;
130
+ }[]>;
131
+ /**
132
+ * Close the database connection
133
+ */
134
+ close(): void;
135
+ beginTransaction(): Promise<void>;
136
+ commit(): Promise<void>;
137
+ rollback(): Promise<void>;
138
+ createMany<T = unknown>(table: string, records: Record<string, unknown>[], options?: {
139
+ ignore?: boolean;
140
+ }): Promise<{
141
+ created: number;
142
+ ids: (number | bigint)[];
143
+ }>;
144
+ updateMany(table: string, updates: {
145
+ id: number | string;
146
+ data: Record<string, unknown>;
147
+ }[]): Promise<{
148
+ updated: number;
149
+ }>;
150
+ deleteMany(table: string, ids: (number | string)[]): Promise<{
151
+ deleted: number;
152
+ }>;
153
+ /**
154
+ * Export database as Uint8Array
155
+ */
156
+ export(): Uint8Array;
157
+ /**
158
+ * Import database from Uint8Array
159
+ */
160
+ import(data: Uint8Array): Promise<void>;
161
+ /**
162
+ * Clear all data and reset database
163
+ */
164
+ clear(): void;
165
+ }
166
+ //# sourceMappingURL=SqliteAdapter.d.ts.map
@@ -0,0 +1,147 @@
1
+ /**
2
+ * DataManager for React Client
3
+ *
4
+ * Central data access layer for the React client.
5
+ * Provides language-aware query methods using raw SQL when needed.
6
+ */
7
+ import type { IDataAdapter, QueryOptions, PaginatedResult, LangQueryOptions } from "../types";
8
+ /**
9
+ * Schema definition for language-aware queries
10
+ */
11
+ export interface TableSchema {
12
+ translatableFields?: string[];
13
+ translationTable?: string;
14
+ foreignKey?: string;
15
+ }
16
+ /**
17
+ * DataManager - Central data access layer for React
18
+ *
19
+ * Acts as a proxy to the underlying adapter with language-aware query support.
20
+ *
21
+ * @example
22
+ * ```ts
23
+ * const dm = useDataManager();
24
+ * const products = await dm.query('products', { lang: 'tr' });
25
+ * ```
26
+ */
27
+ export declare class DataManager {
28
+ private adapter;
29
+ private schemas;
30
+ constructor(adapter: IDataAdapter);
31
+ /**
32
+ * Register a table schema for language-aware queries
33
+ */
34
+ registerSchema(table: string, schema: TableSchema): void;
35
+ /**
36
+ * Get registered schema for a table
37
+ */
38
+ getSchema(table: string): TableSchema | undefined;
39
+ /**
40
+ * Query multiple records
41
+ */
42
+ query<T = unknown>(table: string, options?: QueryOptions): Promise<T[]>;
43
+ /**
44
+ * Query a single record
45
+ */
46
+ queryOne<T = unknown>(table: string, options?: QueryOptions): Promise<T | null>;
47
+ /**
48
+ * Get a record by ID
49
+ */
50
+ queryById<T = unknown>(table: string, id: number | string): Promise<T | null>;
51
+ /**
52
+ * Count records
53
+ */
54
+ count(table: string, options?: QueryOptions): Promise<number>;
55
+ /**
56
+ * Paginated query
57
+ */
58
+ paginate<T = unknown>(table: string, page: number, limit: number, options?: QueryOptions): Promise<PaginatedResult<T>>;
59
+ /**
60
+ * Create a new record
61
+ */
62
+ create<T = unknown>(table: string, data: Record<string, unknown>): Promise<T>;
63
+ /**
64
+ * Update a record by ID
65
+ */
66
+ update<T = unknown>(table: string, id: number | string, data: Record<string, unknown>): Promise<T>;
67
+ /**
68
+ * Delete a record by ID
69
+ */
70
+ delete(table: string, id: number | string): Promise<boolean>;
71
+ /**
72
+ * Execute raw SQL/query
73
+ */
74
+ execute(query: string, params?: unknown[]): Promise<void>;
75
+ /**
76
+ * Execute raw SQL query (SELECT)
77
+ */
78
+ executeQuery<T = unknown>(query: string, params?: unknown[]): Promise<T[]>;
79
+ /**
80
+ * Bulk seed data
81
+ */
82
+ seed(data: Record<string, Record<string, unknown>[]>): Promise<void>;
83
+ /**
84
+ * Get all table names
85
+ */
86
+ getTables(): Promise<string[]>;
87
+ /**
88
+ * Get table schema
89
+ */
90
+ getTableSchema(table: string): Promise<{
91
+ name: string;
92
+ type: string;
93
+ notnull: number;
94
+ pk: number;
95
+ }[]>;
96
+ /**
97
+ * Close connection
98
+ */
99
+ close(): void;
100
+ /**
101
+ * Get the underlying adapter
102
+ */
103
+ getAdapter(): IDataAdapter;
104
+ /**
105
+ * Query with automatic translation support
106
+ *
107
+ * If a schema is registered for the table with translatable fields,
108
+ * this will perform a JOIN with the translation table and use COALESCE
109
+ * to fallback to the default language.
110
+ *
111
+ * @example
112
+ * ```ts
113
+ * dm.registerSchema('products', {
114
+ * translatableFields: ['name', 'description'],
115
+ * translationTable: 'product_translations',
116
+ * foreignKey: 'product_id'
117
+ * });
118
+ *
119
+ * const products = await dm.queryWithLang('products', {
120
+ * lang: 'tr',
121
+ * fallbackLang: 'en'
122
+ * });
123
+ * ```
124
+ */
125
+ queryWithLang<T = unknown>(table: string, options?: LangQueryOptions): Promise<T[]>;
126
+ /**
127
+ * Query single record by ID with translation support
128
+ */
129
+ queryByIdWithLang<T = unknown>(table: string, id: number | string, options?: {
130
+ lang?: string;
131
+ fallbackLang?: string;
132
+ }): Promise<T | null>;
133
+ /**
134
+ * Create record with translations
135
+ */
136
+ createWithTranslations<T = unknown>(table: string, data: Record<string, unknown>, translations: Record<string, Record<string, unknown>>): Promise<T>;
137
+ /**
138
+ * Update or insert translation for specific language
139
+ */
140
+ upsertTranslation(table: string, id: number | string, lang: string, data: Record<string, unknown>): Promise<void>;
141
+ /**
142
+ * Get all translations for a record
143
+ */
144
+ getTranslations<T = unknown>(table: string, id: number | string): Promise<T[]>;
145
+ private buildTranslationQuery;
146
+ }
147
+ //# sourceMappingURL=DataManager.d.ts.map
@@ -0,0 +1,7 @@
1
+ /**
2
+ * useDataManager Hook
3
+ *
4
+ * Access DataManager from DbProvider.
5
+ */
6
+ export { useDataManager } from "../providers/DbProvider";
7
+ //# sourceMappingURL=useDataManager.d.ts.map
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Generic Database Hooks
3
+ *
4
+ * Type-safe React hooks for database operations.
5
+ * Works with any table - just pass the table name and type.
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * import { useDbList, useDbGet, useDbCreate } from '@promakeai/dbreact';
10
+ * import type { DbProduct } from './db/types';
11
+ *
12
+ * // List all products
13
+ * const { data } = useDbList<DbProduct>('products');
14
+ *
15
+ * // Get single product
16
+ * const { data } = useDbGet<DbProduct>('products', productId);
17
+ *
18
+ * // Create product
19
+ * const mutation = useDbCreate<DbProduct>('products');
20
+ * mutation.mutate({ name: 'New Product' });
21
+ * ```
22
+ */
23
+ import { type PopulateOption } from "@promakeai/orm";
24
+ /**
25
+ * List options for useDbList
26
+ */
27
+ export interface ListOptions {
28
+ where?: Record<string, unknown>;
29
+ orderBy?: Array<{
30
+ field: string;
31
+ direction: "ASC" | "DESC";
32
+ }>;
33
+ limit?: number;
34
+ offset?: number;
35
+ enabled?: boolean;
36
+ populate?: PopulateOption;
37
+ }
38
+ /**
39
+ * Hook to list all records from a table
40
+ *
41
+ * @param table - Table name
42
+ * @param options - Query options (where, orderBy, limit, offset, enabled)
43
+ * @returns React Query result with data array
44
+ *
45
+ * @example
46
+ * ```tsx
47
+ * const { data: products, isLoading } = useDbList<DbProduct>('products', {
48
+ * where: { price: { $gt: 100 } },
49
+ * orderBy: [{ field: 'name', direction: 'ASC' }],
50
+ * limit: 10,
51
+ * });
52
+ * ```
53
+ */
54
+ export declare function useDbList<T>(table: string, options?: ListOptions): import("@tanstack/react-query").UseQueryResult<T[], Error>;
55
+ /**
56
+ * Options for findOne-style queries
57
+ */
58
+ export interface FindOneOptions {
59
+ where: Record<string, unknown>;
60
+ enabled?: boolean;
61
+ populate?: PopulateOption;
62
+ }
63
+ /**
64
+ * Hook to get a single record by ID or where query
65
+ *
66
+ * @param table - Table name
67
+ * @param idOrOptions - Record ID, or FindOneOptions with where clause
68
+ * @param maybeOptions - Query options when using ID form
69
+ * @returns React Query result with single record or null
70
+ *
71
+ * @example
72
+ * ```tsx
73
+ * // By ID
74
+ * const { data: product } = useDbGet<DbProduct>('products', productId);
75
+ *
76
+ * // By where query (findOne style)
77
+ * const { data: product } = useDbGet<DbProduct>('products', {
78
+ * where: { slug: 'my-product' },
79
+ * enabled: !!slug,
80
+ * });
81
+ * ```
82
+ */
83
+ export declare function useDbGet<T>(table: string, idOrOptions: number | undefined | FindOneOptions, maybeOptions?: {
84
+ enabled?: boolean;
85
+ populate?: PopulateOption;
86
+ }): import("@tanstack/react-query").UseQueryResult<import("@tanstack/query-core").NoInfer<T | null>, Error>;
87
+ /**
88
+ * Hook to create a new record
89
+ *
90
+ * @param table - Table name
91
+ * @returns React Query mutation for creating records
92
+ *
93
+ * @example
94
+ * ```tsx
95
+ * const mutation = useDbCreate<DbProduct>('products');
96
+ *
97
+ * mutation.mutate({ sku: 'ABC', price: 100 });
98
+ * ```
99
+ */
100
+ export declare function useDbCreate<T, TInput = Partial<T>>(table: string): import("@tanstack/react-query").UseMutationResult<T, Error, TInput, unknown>;
101
+ /**
102
+ * Hook to update an existing record
103
+ *
104
+ * @param table - Table name
105
+ * @returns React Query mutation for updating records
106
+ *
107
+ * @example
108
+ * ```tsx
109
+ * const mutation = useDbUpdate<DbProduct>('products');
110
+ *
111
+ * mutation.mutate({ id: 1, data: { price: 150 } });
112
+ * ```
113
+ */
114
+ export declare function useDbUpdate<T, TInput = Partial<T>>(table: string): import("@tanstack/react-query").UseMutationResult<T, Error, {
115
+ id: number;
116
+ data: TInput;
117
+ }, unknown>;
118
+ /**
119
+ * Hook to delete a record
120
+ *
121
+ * @param table - Table name
122
+ * @returns React Query mutation for deleting records
123
+ *
124
+ * @example
125
+ * ```tsx
126
+ * const mutation = useDbDelete('products');
127
+ *
128
+ * mutation.mutate(productId);
129
+ * ```
130
+ */
131
+ export declare function useDbDelete(table: string): import("@tanstack/react-query").UseMutationResult<boolean, Error, number, unknown>;
132
+ //# sourceMappingURL=useDbHooks.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useDbHooks.d.ts","sourceRoot":"","sources":["../../hooks/useDbHooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAKH;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,KAAK,GAAG,MAAM,CAAA;KAAE,CAAC,CAAC;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,8DAchE;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EACxB,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,cAAc,EAChD,YAAY,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,2GAgBrC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,gFAUhE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM;QAO7B,MAAM;UAAQ,MAAM;YAKvD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,sFAUxC"}
1
+ {"version":3,"file":"useDbHooks.d.ts","sourceRoot":"","sources":["../../hooks/useDbHooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAIH,OAAO,EAAmB,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEtE;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,KAAK,GAAG,MAAM,CAAA;KAAE,CAAC,CAAC;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,8DA2BhE;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EACxB,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,cAAc,EAChD,YAAY,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,cAAc,CAAA;CAAE,2GAqChE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,gFAUhE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM;QAO7B,MAAM;UAAQ,MAAM;YAKvD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,sFAUxC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * useDbLang Hook
3
+ *
4
+ * Access language context from DbProvider.
5
+ */
6
+ export { useDbLang } from "../providers/DbProvider";
7
+ //# sourceMappingURL=useDbLang.d.ts.map
@@ -0,0 +1,13 @@
1
+ /**
2
+ * @promakeai/dbreact
3
+ *
4
+ * React client for schema-driven multi-language database.
5
+ * Works with SQL.js (browser SQLite) or REST API backends.
6
+ */
7
+ export { ORM, defineSchema, f, buildWhereClause, resolvePopulate, getPopulatableFields, validatePopulate, parseJSONSchema, } from "@promakeai/orm";
8
+ export type { SchemaDefinition, TableDefinition, FieldDefinition, PopulateOption, PopulateNested, ORMConfig, QueryOptions, PaginatedResult, IDataAdapter, WhereResult, } from "@promakeai/orm";
9
+ export type { DbProviderConfig, DbLangContextValue, DbContextValue, } from "./types";
10
+ export { DbProvider, useDb, useAdapter, useDbLang, } from "./providers/DbProvider";
11
+ export { useDbList, useDbGet, useDbCreate, useDbUpdate, useDbDelete, type ListOptions, type FindOneOptions, } from "./hooks/useDbHooks";
12
+ export { SqliteAdapter, type SqliteAdapterConfig } from "./adapters/SqliteAdapter";
13
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  defineSchema,
5
5
  f,
6
6
  buildWhereClause as buildWhereClause2,
7
- resolvePopulate,
7
+ resolvePopulate as resolvePopulate2,
8
8
  getPopulatableFields,
9
9
  validatePopulate,
10
10
  parseJSONSchema
@@ -35,6 +35,7 @@ var defaultQueryClient = new QueryClient({
35
35
  });
36
36
  function DbProvider({
37
37
  adapter,
38
+ schema,
38
39
  lang: langProp = "en",
39
40
  fallbackLang = "en",
40
41
  autoConnect = true,
@@ -85,9 +86,10 @@ function DbProvider({
85
86
  }, []);
86
87
  const dbContextValue = useMemo(() => ({
87
88
  adapter,
89
+ schema,
88
90
  isConnected,
89
91
  error
90
- }), [adapter, isConnected, error]);
92
+ }), [adapter, schema, isConnected, error]);
91
93
  const langContextValue = useMemo(() => ({
92
94
  lang,
93
95
  fallbackLang,
@@ -124,28 +126,52 @@ function useDbLang() {
124
126
  }
125
127
  // hooks/useDbHooks.ts
126
128
  import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
129
+ import { resolvePopulate } from "@promakeai/orm";
127
130
  function useDbList(table, options) {
128
131
  const adapter = useAdapter();
132
+ const { schema } = useDb();
129
133
  const { lang, fallbackLang } = useDbLang();
134
+ const { populate, ...queryOpts } = options || {};
130
135
  return useQuery({
131
- queryKey: [table, "list", options, lang],
132
- queryFn: () => adapter.list(table, {
133
- ...options,
134
- lang,
135
- fallbackLang
136
- }),
136
+ queryKey: [table, "list", queryOpts, lang, populate],
137
+ queryFn: async () => {
138
+ const records = await adapter.list(table, {
139
+ ...queryOpts,
140
+ lang,
141
+ fallbackLang
142
+ });
143
+ if (populate && schema) {
144
+ const adapterWrapper = {
145
+ findMany: (t, opts) => adapter.list(t, { ...opts, lang, fallbackLang })
146
+ };
147
+ return resolvePopulate(records, table, populate, schema, adapterWrapper);
148
+ }
149
+ return records;
150
+ },
137
151
  enabled: options?.enabled ?? true
138
152
  });
139
153
  }
140
154
  function useDbGet(table, idOrOptions, maybeOptions) {
141
155
  const adapter = useAdapter();
156
+ const { schema } = useDb();
142
157
  const { lang, fallbackLang } = useDbLang();
143
158
  const isWhereMode = typeof idOrOptions === "object" && idOrOptions !== null && "where" in idOrOptions;
144
159
  const where = isWhereMode ? idOrOptions.where : { id: idOrOptions };
145
160
  const enabled = isWhereMode ? idOrOptions.enabled ?? true : (maybeOptions?.enabled ?? true) && idOrOptions !== undefined;
161
+ const populate = isWhereMode ? idOrOptions.populate : maybeOptions?.populate;
146
162
  return useQuery({
147
- queryKey: [table, "single", where, lang],
148
- queryFn: () => adapter.findOne(table, { where, lang, fallbackLang }),
163
+ queryKey: [table, "single", where, lang, populate],
164
+ queryFn: async () => {
165
+ const record = await adapter.findOne(table, { where, lang, fallbackLang });
166
+ if (record && populate && schema) {
167
+ const adapterWrapper = {
168
+ findMany: (t, opts) => adapter.list(t, { ...opts, lang, fallbackLang })
169
+ };
170
+ const [populated] = await resolvePopulate([record], table, populate, schema, adapterWrapper);
171
+ return populated;
172
+ }
173
+ return record;
174
+ },
149
175
  enabled
150
176
  });
151
177
  }
@@ -636,7 +662,7 @@ export {
636
662
  useDbCreate,
637
663
  useDb,
638
664
  useAdapter,
639
- resolvePopulate,
665
+ resolvePopulate2 as resolvePopulate,
640
666
  parseJSONSchema,
641
667
  getPopulatableFields,
642
668
  f,
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Database Provider
3
+ *
4
+ * React context provider for database operations with language support.
5
+ */
6
+ import { type ReactNode } from "react";
7
+ import { QueryClient } from "@tanstack/react-query";
8
+ import type { IDataAdapter, DbProviderConfig, DbLangContextValue, DbContextValue } from "../types";
9
+ interface DbProviderProps extends DbProviderConfig {
10
+ children: ReactNode;
11
+ queryClient?: QueryClient;
12
+ }
13
+ /**
14
+ * Database Provider Component
15
+ *
16
+ * Wraps application with database context, language context, and React Query.
17
+ *
18
+ * @example
19
+ * ```tsx
20
+ * import { DbProvider, SqliteAdapter } from '@promakeai/dbreact';
21
+ *
22
+ * const adapter = new SqliteAdapter({ storageKey: 'myapp' });
23
+ *
24
+ * function App() {
25
+ * return (
26
+ * <DbProvider adapter={adapter} lang="tr" fallbackLang="en">
27
+ * <MyApp />
28
+ * </DbProvider>
29
+ * );
30
+ * }
31
+ * ```
32
+ */
33
+ export declare function DbProvider({ adapter, schema, lang: langProp, fallbackLang, autoConnect, queryClient, children, }: DbProviderProps): import("react/jsx-runtime").JSX.Element;
34
+ /**
35
+ * Hook to access database context
36
+ */
37
+ export declare function useDb(): DbContextValue;
38
+ /**
39
+ * Hook to access the raw adapter
40
+ */
41
+ export declare function useAdapter(): IDataAdapter;
42
+ /**
43
+ * Hook to access language context
44
+ */
45
+ export declare function useDbLang(): DbLangContextValue;
46
+ export {};
47
+ //# sourceMappingURL=DbProvider.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"DbProvider.d.ts","sourceRoot":"","sources":["../../providers/DbProvider.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAQL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,WAAW,EAAuB,MAAM,uBAAuB,CAAC;AACzE,OAAO,KAAK,EACV,YAAY,EACZ,gBAAgB,EAChB,kBAAkB,EAClB,cAAc,EACf,MAAM,UAAU,CAAC;AAqBlB,UAAU,eAAgB,SAAQ,gBAAgB;IAChD,QAAQ,EAAE,SAAS,CAAC;IACpB,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,UAAU,CAAC,EACzB,OAAO,EACP,IAAI,EAAE,QAAe,EACrB,YAAmB,EACnB,WAAkB,EAClB,WAAgC,EAChC,QAAQ,GACT,EAAE,eAAe,2CAqFjB;AAED;;GAEG;AACH,wBAAgB,KAAK,IAAI,cAAc,CAMtC;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,YAAY,CAGzC;AAED;;GAEG;AACH,wBAAgB,SAAS,IAAI,kBAAkB,CAM9C"}
1
+ {"version":3,"file":"DbProvider.d.ts","sourceRoot":"","sources":["../../providers/DbProvider.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAQL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,WAAW,EAAuB,MAAM,uBAAuB,CAAC;AACzE,OAAO,KAAK,EACV,YAAY,EACZ,gBAAgB,EAChB,kBAAkB,EAClB,cAAc,EACf,MAAM,UAAU,CAAC;AAqBlB,UAAU,eAAgB,SAAQ,gBAAgB;IAChD,QAAQ,EAAE,SAAS,CAAC;IACpB,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,UAAU,CAAC,EACzB,OAAO,EACP,MAAM,EACN,IAAI,EAAE,QAAe,EACrB,YAAmB,EACnB,WAAkB,EAClB,WAAgC,EAChC,QAAQ,GACT,EAAE,eAAe,2CAsFjB;AAED;;GAEG;AACH,wBAAgB,KAAK,IAAI,cAAc,CAMtC;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,YAAY,CAGzC;AAED;;GAEG;AACH,wBAAgB,SAAS,IAAI,kBAAkB,CAM9C"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * dbreact Types
3
+ *
4
+ * Re-exports from @promakeai/orm and React-specific types.
5
+ */
6
+ export type { IDataAdapter, QueryOptions, PaginatedResult, SchemaDefinition, } from "@promakeai/orm";
7
+ /**
8
+ * Provider configuration
9
+ */
10
+ export interface DbProviderConfig {
11
+ adapter: import("@promakeai/orm").IDataAdapter;
12
+ /** Schema definition for populate support */
13
+ schema?: import("@promakeai/orm").SchemaDefinition;
14
+ lang?: string;
15
+ fallbackLang?: string;
16
+ /** Auto-connect on mount (default: true) */
17
+ autoConnect?: boolean;
18
+ }
19
+ /**
20
+ * Language context value
21
+ */
22
+ export interface DbLangContextValue {
23
+ lang: string;
24
+ fallbackLang: string;
25
+ setLang: (lang: string) => void;
26
+ }
27
+ /**
28
+ * Database context value
29
+ */
30
+ export interface DbContextValue {
31
+ adapter: import("@promakeai/orm").IDataAdapter;
32
+ schema?: import("@promakeai/orm").SchemaDefinition;
33
+ isConnected: boolean;
34
+ error: Error | null;
35
+ }
36
+ //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,YAAY,EACV,YAAY,EACZ,YAAY,EACZ,eAAe,GAChB,MAAM,gBAAgB,CAAC;AAExB;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,gBAAgB,EAAE,YAAY,CAAC;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,4CAA4C;IAC5C,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,gBAAgB,EAAE,YAAY,CAAC;IAC/C,WAAW,EAAE,OAAO,CAAC;IACrB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CACrB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,YAAY,EACV,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AAExB;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,gBAAgB,EAAE,YAAY,CAAC;IAC/C,6CAA6C;IAC7C,MAAM,CAAC,EAAE,OAAO,gBAAgB,EAAE,gBAAgB,CAAC;IACnD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,4CAA4C;IAC5C,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,gBAAgB,EAAE,YAAY,CAAC;IAC/C,MAAM,CAAC,EAAE,OAAO,gBAAgB,EAAE,gBAAgB,CAAC;IACnD,WAAW,EAAE,OAAO,CAAC;IACrB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CACrB"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * MongoDB-style Where Clause Builder
3
+ *
4
+ * Converts MongoDB/Mongoose-style query objects into SQL WHERE clauses
5
+ * with parameterized values.
6
+ *
7
+ * Supported operators:
8
+ * - Comparison: $eq, $ne, $gt, $gte, $lt, $lte
9
+ * - Array: $in, $nin
10
+ * - String: $like, $notLike
11
+ * - Range: $between
12
+ * - Null: $isNull
13
+ * - Negation: $not (field-level)
14
+ * - Logical: $and, $or, $nor
15
+ */
16
+ export interface WhereResult {
17
+ sql: string;
18
+ params: unknown[];
19
+ }
20
+ /**
21
+ * Build a SQL WHERE clause from a MongoDB-style query object.
22
+ *
23
+ * @example
24
+ * // Simple equality (backward compatible)
25
+ * buildWhereClause({ active: 1 })
26
+ * // => { sql: "active = ?", params: [1] }
27
+ *
28
+ * @example
29
+ * // Comparison operators
30
+ * buildWhereClause({ age: { $gte: 18, $lt: 65 } })
31
+ * // => { sql: "(age >= ? AND age < ?)", params: [18, 65] }
32
+ *
33
+ * @example
34
+ * // Logical operators
35
+ * buildWhereClause({ $or: [{ active: 1 }, { role: "admin" }] })
36
+ * // => { sql: "(active = ? OR role = ?)", params: [1, "admin"] }
37
+ */
38
+ export declare function buildWhereClause(where?: Record<string, unknown>): WhereResult;
39
+ //# sourceMappingURL=whereBuilder.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@promakeai/dbreact",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "React client for schema-driven multi-language database",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -21,6 +21,9 @@
21
21
  "typecheck": "tsc --noEmit",
22
22
  "release": "bun run build && npm publish --access public"
23
23
  },
24
+ "files": [
25
+ "dist"
26
+ ],
24
27
  "keywords": [
25
28
  "react",
26
29
  "database",
@@ -37,7 +40,7 @@
37
40
  "sql.js": ">=1.11.0"
38
41
  },
39
42
  "dependencies": {
40
- "@promakeai/orm": "1.0.1"
43
+ "@promakeai/orm": "1.0.3"
41
44
  },
42
45
  "devDependencies": {
43
46
  "@tanstack/query-core": "5.90.20",
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
- ```
@@ -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
- }