@promakeai/dbreact 1.0.4 → 1.0.5
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 +8 -4
- package/dist/adapters/SqliteAdapter.js +24 -1
- package/dist/hooks/useDbHooks.js +33 -9
- package/dist/index.js +14 -697
- package/dist/providers/DbProvider.js +3 -2
- package/package.json +5 -3
package/README.md
CHANGED
|
@@ -622,10 +622,14 @@ await adapter.create('products', newProduct);
|
|
|
622
622
|
|
|
623
623
|
---
|
|
624
624
|
|
|
625
|
-
## Troubleshooting
|
|
626
|
-
|
|
627
|
-
**
|
|
628
|
-
-
|
|
625
|
+
## Troubleshooting
|
|
626
|
+
|
|
627
|
+
**Production crash: `jsxDEV is not a function`**
|
|
628
|
+
- Run `bun run test:build-runtime` before publishing.
|
|
629
|
+
- This verifies `dist/index.js` does not include `react/jsx-dev-runtime`.
|
|
630
|
+
|
|
631
|
+
**"useDbLang must be used within a DbProvider"**
|
|
632
|
+
- Ensure component is wrapped in DbProvider
|
|
629
633
|
|
|
630
634
|
**Queries return empty results**
|
|
631
635
|
- Check adapter is connected: `const { isConnected } = useDb()`
|
|
@@ -21,6 +21,7 @@ import { buildWhereClause, buildTranslationQuery, buildTranslationQueryById, bui
|
|
|
21
21
|
export class SqliteAdapter {
|
|
22
22
|
db = null;
|
|
23
23
|
SQL = null;
|
|
24
|
+
tableColumnsCache = new Map();
|
|
24
25
|
config;
|
|
25
26
|
schema;
|
|
26
27
|
defaultLang;
|
|
@@ -39,6 +40,7 @@ export class SqliteAdapter {
|
|
|
39
40
|
setSchema(schema) {
|
|
40
41
|
this.schema = schema;
|
|
41
42
|
this.config.schema = schema;
|
|
43
|
+
this.tableColumnsCache.clear();
|
|
42
44
|
}
|
|
43
45
|
async connect() {
|
|
44
46
|
// Initialize sql.js
|
|
@@ -162,6 +164,7 @@ export class SqliteAdapter {
|
|
|
162
164
|
schema: this.schema,
|
|
163
165
|
lang: options.lang,
|
|
164
166
|
fallbackLang: options.fallbackLang ?? this.defaultLang,
|
|
167
|
+
mainFallbackFields: await this.getAvailableMainFallbackFields(table),
|
|
165
168
|
where: options.where,
|
|
166
169
|
orderBy: options.orderBy,
|
|
167
170
|
limit: options.limit,
|
|
@@ -195,7 +198,7 @@ export class SqliteAdapter {
|
|
|
195
198
|
const results = await this.list(table, { where: { id }, limit: 1 });
|
|
196
199
|
return results[0] ?? null;
|
|
197
200
|
}
|
|
198
|
-
const { sql, params } = buildTranslationQueryById(table, this.schema, id, options.lang, options.fallbackLang ?? this.defaultLang);
|
|
201
|
+
const { sql, params } = buildTranslationQueryById(table, this.schema, id, options.lang, options.fallbackLang ?? this.defaultLang, await this.getAvailableMainFallbackFields(table));
|
|
199
202
|
const rows = this.runQuery(sql, params);
|
|
200
203
|
const deserialized = this.deserializeResults(table, rows);
|
|
201
204
|
return deserialized[0] ?? null;
|
|
@@ -449,6 +452,7 @@ export class SqliteAdapter {
|
|
|
449
452
|
this.persist();
|
|
450
453
|
this.db.close();
|
|
451
454
|
this.db = null;
|
|
455
|
+
this.tableColumnsCache.clear();
|
|
452
456
|
}
|
|
453
457
|
}
|
|
454
458
|
// Transaction methods
|
|
@@ -495,6 +499,25 @@ export class SqliteAdapter {
|
|
|
495
499
|
this.persist();
|
|
496
500
|
return { created: ids.length, ids };
|
|
497
501
|
}
|
|
502
|
+
async getAvailableMainFallbackFields(table) {
|
|
503
|
+
const tableSchema = this.schema?.tables[table];
|
|
504
|
+
if (!tableSchema)
|
|
505
|
+
return [];
|
|
506
|
+
const translatableFields = getTranslatableFields(tableSchema);
|
|
507
|
+
if (translatableFields.length === 0)
|
|
508
|
+
return [];
|
|
509
|
+
const tableColumns = await this.getTableColumns(table);
|
|
510
|
+
return translatableFields.filter((field) => tableColumns.has(field));
|
|
511
|
+
}
|
|
512
|
+
async getTableColumns(table) {
|
|
513
|
+
const cached = this.tableColumnsCache.get(table);
|
|
514
|
+
if (cached)
|
|
515
|
+
return cached;
|
|
516
|
+
const schema = await this.getTableSchema(table);
|
|
517
|
+
const columnSet = new Set(schema.map((col) => col.name));
|
|
518
|
+
this.tableColumnsCache.set(table, columnSet);
|
|
519
|
+
return columnSet;
|
|
520
|
+
}
|
|
498
521
|
async updateMany(table, updates) {
|
|
499
522
|
let updated = 0;
|
|
500
523
|
for (const { id, data } of updates) {
|
package/dist/hooks/useDbHooks.js
CHANGED
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
* ```
|
|
22
22
|
*/
|
|
23
23
|
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
|
24
|
-
import { useAdapter, useDbLang } from "../providers/DbProvider";
|
|
24
|
+
import { useAdapter, useDb, useDbLang } from "../providers/DbProvider";
|
|
25
|
+
import { resolvePopulate } from "@promakeai/orm";
|
|
25
26
|
/**
|
|
26
27
|
* Hook to list all records from a table
|
|
27
28
|
*
|
|
@@ -40,14 +41,25 @@ import { useAdapter, useDbLang } from "../providers/DbProvider";
|
|
|
40
41
|
*/
|
|
41
42
|
export function useDbList(table, options) {
|
|
42
43
|
const adapter = useAdapter();
|
|
44
|
+
const { schema } = useDb();
|
|
43
45
|
const { lang, fallbackLang } = useDbLang();
|
|
46
|
+
const { populate, ...queryOpts } = options || {};
|
|
44
47
|
return useQuery({
|
|
45
|
-
queryKey: [table, "list",
|
|
46
|
-
queryFn: () =>
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
queryKey: [table, "list", queryOpts, lang, populate],
|
|
49
|
+
queryFn: async () => {
|
|
50
|
+
const records = await adapter.list(table, {
|
|
51
|
+
...queryOpts,
|
|
52
|
+
lang,
|
|
53
|
+
fallbackLang,
|
|
54
|
+
});
|
|
55
|
+
if (populate && schema) {
|
|
56
|
+
const adapterWrapper = {
|
|
57
|
+
findMany: (t, opts) => adapter.list(t, { ...opts, lang, fallbackLang }),
|
|
58
|
+
};
|
|
59
|
+
return resolvePopulate(records, table, populate, schema, adapterWrapper);
|
|
60
|
+
}
|
|
61
|
+
return records;
|
|
62
|
+
},
|
|
51
63
|
enabled: options?.enabled ?? true,
|
|
52
64
|
});
|
|
53
65
|
}
|
|
@@ -73,15 +85,27 @@ export function useDbList(table, options) {
|
|
|
73
85
|
*/
|
|
74
86
|
export function useDbGet(table, idOrOptions, maybeOptions) {
|
|
75
87
|
const adapter = useAdapter();
|
|
88
|
+
const { schema } = useDb();
|
|
76
89
|
const { lang, fallbackLang } = useDbLang();
|
|
77
90
|
const isWhereMode = typeof idOrOptions === "object" && idOrOptions !== null && "where" in idOrOptions;
|
|
78
91
|
const where = isWhereMode ? idOrOptions.where : { id: idOrOptions };
|
|
79
92
|
const enabled = isWhereMode
|
|
80
93
|
? (idOrOptions.enabled ?? true)
|
|
81
94
|
: ((maybeOptions?.enabled ?? true) && idOrOptions !== undefined);
|
|
95
|
+
const populate = isWhereMode ? idOrOptions.populate : maybeOptions?.populate;
|
|
82
96
|
return useQuery({
|
|
83
|
-
queryKey: [table, "single", where, lang],
|
|
84
|
-
queryFn: () =>
|
|
97
|
+
queryKey: [table, "single", where, lang, populate],
|
|
98
|
+
queryFn: async () => {
|
|
99
|
+
const record = await adapter.findOne(table, { where, lang, fallbackLang });
|
|
100
|
+
if (record && populate && schema) {
|
|
101
|
+
const adapterWrapper = {
|
|
102
|
+
findMany: (t, opts) => adapter.list(t, { ...opts, lang, fallbackLang }),
|
|
103
|
+
};
|
|
104
|
+
const [populated] = await resolvePopulate([record], table, populate, schema, adapterWrapper);
|
|
105
|
+
return populated;
|
|
106
|
+
}
|
|
107
|
+
return record;
|
|
108
|
+
},
|
|
85
109
|
enabled,
|
|
86
110
|
});
|
|
87
111
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,697 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
//
|
|
14
|
-
|
|
15
|
-
createContext,
|
|
16
|
-
useContext,
|
|
17
|
-
useState,
|
|
18
|
-
useEffect,
|
|
19
|
-
useMemo,
|
|
20
|
-
useCallback,
|
|
21
|
-
useRef
|
|
22
|
-
} from "react";
|
|
23
|
-
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
24
|
-
import { jsxDEV } from "react/jsx-dev-runtime";
|
|
25
|
-
var DbContext = createContext(null);
|
|
26
|
-
var DbLangContext = createContext(null);
|
|
27
|
-
var defaultQueryClient = new QueryClient({
|
|
28
|
-
defaultOptions: {
|
|
29
|
-
queries: {
|
|
30
|
-
staleTime: 1000 * 60 * 5,
|
|
31
|
-
gcTime: 1000 * 60 * 30,
|
|
32
|
-
refetchOnWindowFocus: false
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
function DbProvider({
|
|
37
|
-
adapter,
|
|
38
|
-
schema,
|
|
39
|
-
lang: langProp = "en",
|
|
40
|
-
fallbackLang = "en",
|
|
41
|
-
autoConnect = true,
|
|
42
|
-
queryClient = defaultQueryClient,
|
|
43
|
-
children
|
|
44
|
-
}) {
|
|
45
|
-
const [isConnected, setIsConnected] = useState(false);
|
|
46
|
-
const [error, setError] = useState(null);
|
|
47
|
-
const [lang, setLangState] = useState(langProp);
|
|
48
|
-
const isFirstRender = useRef(true);
|
|
49
|
-
useEffect(() => {
|
|
50
|
-
if (langProp !== lang) {
|
|
51
|
-
setLangState(langProp);
|
|
52
|
-
}
|
|
53
|
-
}, [langProp]);
|
|
54
|
-
useEffect(() => {
|
|
55
|
-
if (isFirstRender.current) {
|
|
56
|
-
isFirstRender.current = false;
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
queryClient.invalidateQueries();
|
|
60
|
-
}, [lang]);
|
|
61
|
-
useEffect(() => {
|
|
62
|
-
if (!autoConnect)
|
|
63
|
-
return;
|
|
64
|
-
let mounted = true;
|
|
65
|
-
async function connect() {
|
|
66
|
-
try {
|
|
67
|
-
await adapter.connect?.();
|
|
68
|
-
if (mounted) {
|
|
69
|
-
setIsConnected(true);
|
|
70
|
-
setError(null);
|
|
71
|
-
}
|
|
72
|
-
} catch (err) {
|
|
73
|
-
if (mounted) {
|
|
74
|
-
setError(err instanceof Error ? err : new Error(String(err)));
|
|
75
|
-
setIsConnected(false);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
connect();
|
|
80
|
-
return () => {
|
|
81
|
-
mounted = false;
|
|
82
|
-
};
|
|
83
|
-
}, [adapter, autoConnect]);
|
|
84
|
-
const setLang = useCallback((newLang) => {
|
|
85
|
-
setLangState(newLang);
|
|
86
|
-
}, []);
|
|
87
|
-
const dbContextValue = useMemo(() => ({
|
|
88
|
-
adapter,
|
|
89
|
-
schema,
|
|
90
|
-
isConnected,
|
|
91
|
-
error
|
|
92
|
-
}), [adapter, schema, isConnected, error]);
|
|
93
|
-
const langContextValue = useMemo(() => ({
|
|
94
|
-
lang,
|
|
95
|
-
fallbackLang,
|
|
96
|
-
setLang
|
|
97
|
-
}), [lang, fallbackLang, setLang]);
|
|
98
|
-
return /* @__PURE__ */ jsxDEV(QueryClientProvider, {
|
|
99
|
-
client: queryClient,
|
|
100
|
-
children: /* @__PURE__ */ jsxDEV(DbContext.Provider, {
|
|
101
|
-
value: dbContextValue,
|
|
102
|
-
children: /* @__PURE__ */ jsxDEV(DbLangContext.Provider, {
|
|
103
|
-
value: langContextValue,
|
|
104
|
-
children
|
|
105
|
-
}, undefined, false, undefined, this)
|
|
106
|
-
}, undefined, false, undefined, this)
|
|
107
|
-
}, undefined, false, undefined, this);
|
|
108
|
-
}
|
|
109
|
-
function useDb() {
|
|
110
|
-
const context = useContext(DbContext);
|
|
111
|
-
if (!context) {
|
|
112
|
-
throw new Error("useDb must be used within a DbProvider");
|
|
113
|
-
}
|
|
114
|
-
return context;
|
|
115
|
-
}
|
|
116
|
-
function useAdapter() {
|
|
117
|
-
const { adapter } = useDb();
|
|
118
|
-
return adapter;
|
|
119
|
-
}
|
|
120
|
-
function useDbLang() {
|
|
121
|
-
const context = useContext(DbLangContext);
|
|
122
|
-
if (!context) {
|
|
123
|
-
throw new Error("useDbLang must be used within a DbProvider");
|
|
124
|
-
}
|
|
125
|
-
return context;
|
|
126
|
-
}
|
|
127
|
-
// hooks/useDbHooks.ts
|
|
128
|
-
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
|
129
|
-
import { resolvePopulate } from "@promakeai/orm";
|
|
130
|
-
function useDbList(table, options) {
|
|
131
|
-
const adapter = useAdapter();
|
|
132
|
-
const { schema } = useDb();
|
|
133
|
-
const { lang, fallbackLang } = useDbLang();
|
|
134
|
-
const { populate, ...queryOpts } = options || {};
|
|
135
|
-
return useQuery({
|
|
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
|
-
},
|
|
151
|
-
enabled: options?.enabled ?? true
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
function useDbGet(table, idOrOptions, maybeOptions) {
|
|
155
|
-
const adapter = useAdapter();
|
|
156
|
-
const { schema } = useDb();
|
|
157
|
-
const { lang, fallbackLang } = useDbLang();
|
|
158
|
-
const isWhereMode = typeof idOrOptions === "object" && idOrOptions !== null && "where" in idOrOptions;
|
|
159
|
-
const where = isWhereMode ? idOrOptions.where : { id: idOrOptions };
|
|
160
|
-
const enabled = isWhereMode ? idOrOptions.enabled ?? true : (maybeOptions?.enabled ?? true) && idOrOptions !== undefined;
|
|
161
|
-
const populate = isWhereMode ? idOrOptions.populate : maybeOptions?.populate;
|
|
162
|
-
return useQuery({
|
|
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
|
-
},
|
|
175
|
-
enabled
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
function useDbCreate(table) {
|
|
179
|
-
const adapter = useAdapter();
|
|
180
|
-
const queryClient = useQueryClient();
|
|
181
|
-
return useMutation({
|
|
182
|
-
mutationFn: (data) => adapter.create(table, data),
|
|
183
|
-
onSuccess: () => {
|
|
184
|
-
queryClient.invalidateQueries({ queryKey: [table] });
|
|
185
|
-
}
|
|
186
|
-
});
|
|
187
|
-
}
|
|
188
|
-
function useDbUpdate(table) {
|
|
189
|
-
const adapter = useAdapter();
|
|
190
|
-
const queryClient = useQueryClient();
|
|
191
|
-
return useMutation({
|
|
192
|
-
mutationFn: ({ id, data }) => adapter.update(table, id, data),
|
|
193
|
-
onSuccess: (_, { id }) => {
|
|
194
|
-
queryClient.invalidateQueries({ queryKey: [table] });
|
|
195
|
-
queryClient.invalidateQueries({ queryKey: [table, "single", id] });
|
|
196
|
-
}
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
|
-
function useDbDelete(table) {
|
|
200
|
-
const adapter = useAdapter();
|
|
201
|
-
const queryClient = useQueryClient();
|
|
202
|
-
return useMutation({
|
|
203
|
-
mutationFn: (id) => adapter.delete(table, id),
|
|
204
|
-
onSuccess: () => {
|
|
205
|
-
queryClient.invalidateQueries({ queryKey: [table] });
|
|
206
|
-
}
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
// adapters/SqliteAdapter.ts
|
|
210
|
-
import initSqlJs from "sql.js";
|
|
211
|
-
import {
|
|
212
|
-
buildWhereClause,
|
|
213
|
-
buildTranslationQuery,
|
|
214
|
-
buildTranslationQueryById,
|
|
215
|
-
buildTranslationUpsert,
|
|
216
|
-
extractTranslatableData,
|
|
217
|
-
getTranslatableFields,
|
|
218
|
-
toTranslationTableName,
|
|
219
|
-
toTranslationFKName,
|
|
220
|
-
deserializeRow,
|
|
221
|
-
serializeRow
|
|
222
|
-
} from "@promakeai/orm";
|
|
223
|
-
|
|
224
|
-
class SqliteAdapter {
|
|
225
|
-
db = null;
|
|
226
|
-
SQL = null;
|
|
227
|
-
tableColumnsCache = new Map;
|
|
228
|
-
config;
|
|
229
|
-
schema;
|
|
230
|
-
defaultLang;
|
|
231
|
-
constructor(config = {}) {
|
|
232
|
-
this.config = {
|
|
233
|
-
storageKey: config.storageKey ?? "dbreact_db",
|
|
234
|
-
wasmPath: config.wasmPath ?? "https://sql.js.org/dist/sql-wasm.wasm",
|
|
235
|
-
initialData: config.initialData ?? new Uint8Array,
|
|
236
|
-
schema: config.schema,
|
|
237
|
-
defaultLang: config.defaultLang
|
|
238
|
-
};
|
|
239
|
-
this.schema = config.schema;
|
|
240
|
-
this.defaultLang = config.defaultLang;
|
|
241
|
-
}
|
|
242
|
-
setSchema(schema) {
|
|
243
|
-
this.schema = schema;
|
|
244
|
-
this.config.schema = schema;
|
|
245
|
-
this.tableColumnsCache.clear();
|
|
246
|
-
}
|
|
247
|
-
async connect() {
|
|
248
|
-
this.SQL = await initSqlJs({
|
|
249
|
-
locateFile: (file) => file === "sql-wasm.wasm" ? this.config.wasmPath : file
|
|
250
|
-
});
|
|
251
|
-
const saved = localStorage.getItem(this.config.storageKey);
|
|
252
|
-
if (saved) {
|
|
253
|
-
const data = Uint8Array.from(atob(saved), (c) => c.charCodeAt(0));
|
|
254
|
-
this.db = new this.SQL.Database(data);
|
|
255
|
-
} else if (this.config.initialData.length > 0) {
|
|
256
|
-
this.db = new this.SQL.Database(this.config.initialData);
|
|
257
|
-
this.persist();
|
|
258
|
-
} else {
|
|
259
|
-
this.db = new this.SQL.Database;
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
persist() {
|
|
263
|
-
if (!this.db)
|
|
264
|
-
return;
|
|
265
|
-
const data = this.db.export();
|
|
266
|
-
const base64 = btoa(String.fromCharCode(...data));
|
|
267
|
-
localStorage.setItem(this.config.storageKey, base64);
|
|
268
|
-
}
|
|
269
|
-
getDb() {
|
|
270
|
-
if (!this.db) {
|
|
271
|
-
throw new Error("Database not connected. Call connect() first.");
|
|
272
|
-
}
|
|
273
|
-
return this.db;
|
|
274
|
-
}
|
|
275
|
-
runQuery(sql, params = []) {
|
|
276
|
-
const db = this.getDb();
|
|
277
|
-
const result = db.exec(sql, params);
|
|
278
|
-
if (result.length === 0 || result[0].values.length === 0) {
|
|
279
|
-
return [];
|
|
280
|
-
}
|
|
281
|
-
const columns = result[0].columns;
|
|
282
|
-
return result[0].values.map((row) => {
|
|
283
|
-
const obj = {};
|
|
284
|
-
columns.forEach((col, i) => {
|
|
285
|
-
obj[col] = row[i];
|
|
286
|
-
});
|
|
287
|
-
return obj;
|
|
288
|
-
});
|
|
289
|
-
}
|
|
290
|
-
deserializeResults(table, rows) {
|
|
291
|
-
const tableSchema = this.schema?.tables[table];
|
|
292
|
-
if (!tableSchema || rows.length === 0)
|
|
293
|
-
return rows;
|
|
294
|
-
return rows.map((row) => deserializeRow(row, tableSchema.fields));
|
|
295
|
-
}
|
|
296
|
-
serializeData(table, data) {
|
|
297
|
-
const tableSchema = this.schema?.tables[table];
|
|
298
|
-
if (!tableSchema)
|
|
299
|
-
return data;
|
|
300
|
-
return serializeRow(data, tableSchema.fields);
|
|
301
|
-
}
|
|
302
|
-
buildSelectQuery(table, options, countOnly = false) {
|
|
303
|
-
const select = countOnly ? "COUNT(*) as count" : "*";
|
|
304
|
-
let sql = `SELECT ${select} FROM ${table}`;
|
|
305
|
-
const params = [];
|
|
306
|
-
if (options?.where) {
|
|
307
|
-
const where = buildWhereClause(options.where);
|
|
308
|
-
if (where.sql) {
|
|
309
|
-
sql += ` WHERE ${where.sql}`;
|
|
310
|
-
params.push(...where.params);
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
if (!countOnly) {
|
|
314
|
-
if (options?.orderBy && options.orderBy.length > 0) {
|
|
315
|
-
const orderParts = options.orderBy.map((o) => `${o.field} ${o.direction}`);
|
|
316
|
-
sql += ` ORDER BY ${orderParts.join(", ")}`;
|
|
317
|
-
}
|
|
318
|
-
if (options?.limit !== undefined) {
|
|
319
|
-
sql += ` LIMIT ?`;
|
|
320
|
-
params.push(options.limit);
|
|
321
|
-
}
|
|
322
|
-
if (options?.offset !== undefined) {
|
|
323
|
-
sql += ` OFFSET ?`;
|
|
324
|
-
params.push(options.offset);
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
return { sql, params };
|
|
328
|
-
}
|
|
329
|
-
async list(table, options) {
|
|
330
|
-
if (options?.lang && this.schema?.tables[table]) {
|
|
331
|
-
return this.listWithLang(table, options);
|
|
332
|
-
}
|
|
333
|
-
const { sql, params } = this.buildSelectQuery(table, options);
|
|
334
|
-
const rows = this.runQuery(sql, params);
|
|
335
|
-
return this.deserializeResults(table, rows);
|
|
336
|
-
}
|
|
337
|
-
async listWithLang(table, options) {
|
|
338
|
-
const tableSchema = this.schema?.tables[table];
|
|
339
|
-
if (!tableSchema) {
|
|
340
|
-
const { sql: sql2, params: params2 } = this.buildSelectQuery(table, options);
|
|
341
|
-
return this.deserializeResults(table, this.runQuery(sql2, params2));
|
|
342
|
-
}
|
|
343
|
-
const translatableFields = getTranslatableFields(tableSchema);
|
|
344
|
-
if (translatableFields.length === 0) {
|
|
345
|
-
const { sql: sql2, params: params2 } = this.buildSelectQuery(table, options);
|
|
346
|
-
return this.deserializeResults(table, this.runQuery(sql2, params2));
|
|
347
|
-
}
|
|
348
|
-
const { sql, params } = buildTranslationQuery({
|
|
349
|
-
table,
|
|
350
|
-
schema: this.schema,
|
|
351
|
-
lang: options.lang,
|
|
352
|
-
fallbackLang: options.fallbackLang ?? this.defaultLang,
|
|
353
|
-
mainFallbackFields: await this.getAvailableMainFallbackFields(table),
|
|
354
|
-
where: options.where,
|
|
355
|
-
orderBy: options.orderBy,
|
|
356
|
-
limit: options.limit,
|
|
357
|
-
offset: options.offset
|
|
358
|
-
});
|
|
359
|
-
return this.deserializeResults(table, this.runQuery(sql, params));
|
|
360
|
-
}
|
|
361
|
-
async get(table, id, options) {
|
|
362
|
-
if (options?.lang && this.schema?.tables[table]) {
|
|
363
|
-
return this.getWithLang(table, id, options);
|
|
364
|
-
}
|
|
365
|
-
const results = await this.list(table, { where: { id }, limit: 1 });
|
|
366
|
-
return results[0] ?? null;
|
|
367
|
-
}
|
|
368
|
-
async findOne(table, options) {
|
|
369
|
-
const results = await this.list(table, { ...options, limit: 1 });
|
|
370
|
-
return results[0] ?? null;
|
|
371
|
-
}
|
|
372
|
-
async getWithLang(table, id, options) {
|
|
373
|
-
const tableSchema = this.schema?.tables[table];
|
|
374
|
-
if (!tableSchema) {
|
|
375
|
-
const results = await this.list(table, { where: { id }, limit: 1 });
|
|
376
|
-
return results[0] ?? null;
|
|
377
|
-
}
|
|
378
|
-
const translatableFields = getTranslatableFields(tableSchema);
|
|
379
|
-
if (translatableFields.length === 0) {
|
|
380
|
-
const results = await this.list(table, { where: { id }, limit: 1 });
|
|
381
|
-
return results[0] ?? null;
|
|
382
|
-
}
|
|
383
|
-
const { sql, params } = buildTranslationQueryById(table, this.schema, id, options.lang, options.fallbackLang ?? this.defaultLang, await this.getAvailableMainFallbackFields(table));
|
|
384
|
-
const rows = this.runQuery(sql, params);
|
|
385
|
-
const deserialized = this.deserializeResults(table, rows);
|
|
386
|
-
return deserialized[0] ?? null;
|
|
387
|
-
}
|
|
388
|
-
async count(table, options) {
|
|
389
|
-
const { sql, params } = this.buildSelectQuery(table, options, true);
|
|
390
|
-
const result = this.runQuery(sql, params);
|
|
391
|
-
return result[0]?.count ?? 0;
|
|
392
|
-
}
|
|
393
|
-
async paginate(table, page, limit, options) {
|
|
394
|
-
const total = await this.count(table, options);
|
|
395
|
-
const totalPages = Math.ceil(total / limit);
|
|
396
|
-
const offset = (page - 1) * limit;
|
|
397
|
-
const data = await this.list(table, {
|
|
398
|
-
...options,
|
|
399
|
-
limit,
|
|
400
|
-
offset
|
|
401
|
-
});
|
|
402
|
-
return {
|
|
403
|
-
data,
|
|
404
|
-
page,
|
|
405
|
-
limit,
|
|
406
|
-
total,
|
|
407
|
-
totalPages,
|
|
408
|
-
hasMore: page < totalPages
|
|
409
|
-
};
|
|
410
|
-
}
|
|
411
|
-
async create(table, data) {
|
|
412
|
-
const db = this.getDb();
|
|
413
|
-
const tableSchema = this.schema?.tables[table];
|
|
414
|
-
const serializedData = this.serializeData(table, data);
|
|
415
|
-
if (tableSchema) {
|
|
416
|
-
const { mainData, translatableData } = extractTranslatableData(serializedData, tableSchema);
|
|
417
|
-
const columns2 = Object.keys(mainData);
|
|
418
|
-
const values2 = Object.values(mainData);
|
|
419
|
-
const placeholders2 = columns2.map(() => "?").join(", ");
|
|
420
|
-
const sql2 = `INSERT INTO ${table} (${columns2.join(", ")}) VALUES (${placeholders2})`;
|
|
421
|
-
db.run(sql2, values2);
|
|
422
|
-
const lastId2 = db.exec("SELECT last_insert_rowid() as id")[0].values[0][0];
|
|
423
|
-
this.persist();
|
|
424
|
-
if (Object.keys(translatableData).length > 0 && this.defaultLang) {
|
|
425
|
-
await this.upsertTranslation(table, lastId2, this.defaultLang, translatableData);
|
|
426
|
-
}
|
|
427
|
-
const result2 = await this.get(table, lastId2);
|
|
428
|
-
return result2;
|
|
429
|
-
}
|
|
430
|
-
const columns = Object.keys(serializedData);
|
|
431
|
-
const values = Object.values(serializedData);
|
|
432
|
-
const placeholders = columns.map(() => "?").join(", ");
|
|
433
|
-
const sql = `INSERT INTO ${table} (${columns.join(", ")}) VALUES (${placeholders})`;
|
|
434
|
-
db.run(sql, values);
|
|
435
|
-
const lastId = db.exec("SELECT last_insert_rowid() as id")[0].values[0][0];
|
|
436
|
-
this.persist();
|
|
437
|
-
const result = await this.get(table, lastId);
|
|
438
|
-
return result;
|
|
439
|
-
}
|
|
440
|
-
async createWithTranslations(table, data, translations) {
|
|
441
|
-
const db = this.getDb();
|
|
442
|
-
const tableSchema = this.schema?.tables[table];
|
|
443
|
-
const serializedData = this.serializeData(table, data);
|
|
444
|
-
let mainData = serializedData;
|
|
445
|
-
let translatableData = {};
|
|
446
|
-
if (tableSchema) {
|
|
447
|
-
const extracted = extractTranslatableData(serializedData, tableSchema);
|
|
448
|
-
mainData = extracted.mainData;
|
|
449
|
-
translatableData = extracted.translatableData;
|
|
450
|
-
}
|
|
451
|
-
const columns = Object.keys(mainData);
|
|
452
|
-
const values = Object.values(mainData);
|
|
453
|
-
const placeholders = columns.map(() => "?").join(", ");
|
|
454
|
-
const sql = `INSERT INTO ${table} (${columns.join(", ")}) VALUES (${placeholders})`;
|
|
455
|
-
db.run(sql, values);
|
|
456
|
-
const lastId = db.exec("SELECT last_insert_rowid() as id")[0].values[0][0];
|
|
457
|
-
if (translations) {
|
|
458
|
-
for (const [lang, langData] of Object.entries(translations)) {
|
|
459
|
-
await this.upsertTranslation(table, lastId, lang, langData);
|
|
460
|
-
}
|
|
461
|
-
} else if (Object.keys(translatableData).length > 0 && this.defaultLang) {
|
|
462
|
-
await this.upsertTranslation(table, lastId, this.defaultLang, translatableData);
|
|
463
|
-
}
|
|
464
|
-
this.persist();
|
|
465
|
-
const result = await this.get(table, lastId);
|
|
466
|
-
return result;
|
|
467
|
-
}
|
|
468
|
-
async update(table, id, data) {
|
|
469
|
-
const db = this.getDb();
|
|
470
|
-
const tableSchema = this.schema?.tables[table];
|
|
471
|
-
const serializedData = this.serializeData(table, data);
|
|
472
|
-
if (tableSchema) {
|
|
473
|
-
const { mainData, translatableData } = extractTranslatableData(serializedData, tableSchema);
|
|
474
|
-
if (Object.keys(mainData).length > 0) {
|
|
475
|
-
const columns2 = Object.keys(mainData);
|
|
476
|
-
const values2 = Object.values(mainData);
|
|
477
|
-
const setParts2 = columns2.map((col) => `${col} = ?`).join(", ");
|
|
478
|
-
const sql2 = `UPDATE ${table} SET ${setParts2} WHERE id = ?`;
|
|
479
|
-
db.run(sql2, [...values2, id]);
|
|
480
|
-
}
|
|
481
|
-
if (Object.keys(translatableData).length > 0 && this.defaultLang) {
|
|
482
|
-
await this.upsertTranslation(table, id, this.defaultLang, translatableData);
|
|
483
|
-
}
|
|
484
|
-
this.persist();
|
|
485
|
-
const result2 = await this.get(table, id);
|
|
486
|
-
return result2;
|
|
487
|
-
}
|
|
488
|
-
const columns = Object.keys(serializedData);
|
|
489
|
-
const values = Object.values(serializedData);
|
|
490
|
-
const setParts = columns.map((col) => `${col} = ?`).join(", ");
|
|
491
|
-
const sql = `UPDATE ${table} SET ${setParts} WHERE id = ?`;
|
|
492
|
-
db.run(sql, [...values, id]);
|
|
493
|
-
this.persist();
|
|
494
|
-
const result = await this.get(table, id);
|
|
495
|
-
return result;
|
|
496
|
-
}
|
|
497
|
-
async upsertTranslation(table, id, lang, data) {
|
|
498
|
-
const db = this.getDb();
|
|
499
|
-
if (!this.schema) {
|
|
500
|
-
throw new Error(`No schema found for table: ${table}`);
|
|
501
|
-
}
|
|
502
|
-
const { sql, params } = buildTranslationUpsert(table, this.schema, id, lang, data);
|
|
503
|
-
db.run(sql, params);
|
|
504
|
-
this.persist();
|
|
505
|
-
}
|
|
506
|
-
async getTranslations(table, id) {
|
|
507
|
-
const tableSchema = this.schema?.tables[table];
|
|
508
|
-
if (!tableSchema) {
|
|
509
|
-
return [];
|
|
510
|
-
}
|
|
511
|
-
const translationTable = toTranslationTableName(table);
|
|
512
|
-
const fkName = toTranslationFKName(table);
|
|
513
|
-
const sql = `SELECT * FROM ${translationTable} WHERE ${fkName} = ?`;
|
|
514
|
-
return this.runQuery(sql, [id]);
|
|
515
|
-
}
|
|
516
|
-
async delete(table, id) {
|
|
517
|
-
const db = this.getDb();
|
|
518
|
-
if (this.schema?.tables[table]) {
|
|
519
|
-
const translationTable = toTranslationTableName(table);
|
|
520
|
-
const fkName = toTranslationFKName(table);
|
|
521
|
-
try {
|
|
522
|
-
db.run(`DELETE FROM ${translationTable} WHERE ${fkName} = ?`, [id]);
|
|
523
|
-
} catch {}
|
|
524
|
-
}
|
|
525
|
-
const sql = `DELETE FROM ${table} WHERE id = ?`;
|
|
526
|
-
db.run(sql, [id]);
|
|
527
|
-
this.persist();
|
|
528
|
-
const changes = db.getRowsModified();
|
|
529
|
-
return changes > 0;
|
|
530
|
-
}
|
|
531
|
-
async execute(query, params) {
|
|
532
|
-
const db = this.getDb();
|
|
533
|
-
db.run(query, params);
|
|
534
|
-
this.persist();
|
|
535
|
-
const changes = db.getRowsModified();
|
|
536
|
-
const result = db.exec("SELECT last_insert_rowid() as id");
|
|
537
|
-
const lastInsertRowid = result[0]?.values[0]?.[0] ?? 0;
|
|
538
|
-
return { changes, lastInsertRowid };
|
|
539
|
-
}
|
|
540
|
-
async raw(query, params) {
|
|
541
|
-
return this.runQuery(query, params ?? []);
|
|
542
|
-
}
|
|
543
|
-
async seed(data) {
|
|
544
|
-
const db = this.getDb();
|
|
545
|
-
for (const [table, records] of Object.entries(data)) {
|
|
546
|
-
for (const record of records) {
|
|
547
|
-
const serialized = this.serializeData(table, record);
|
|
548
|
-
const columns = Object.keys(serialized);
|
|
549
|
-
const values = Object.values(serialized);
|
|
550
|
-
const placeholders = columns.map(() => "?").join(", ");
|
|
551
|
-
const sql = `INSERT INTO ${table} (${columns.join(", ")}) VALUES (${placeholders})`;
|
|
552
|
-
db.run(sql, values);
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
this.persist();
|
|
556
|
-
}
|
|
557
|
-
async getTables() {
|
|
558
|
-
const result = this.runQuery("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'");
|
|
559
|
-
return result.map((row) => row.name);
|
|
560
|
-
}
|
|
561
|
-
async getTableSchema(table) {
|
|
562
|
-
const db = this.getDb();
|
|
563
|
-
const result = db.exec(`PRAGMA table_info(${table})`);
|
|
564
|
-
if (result.length === 0 || result[0].values.length === 0) {
|
|
565
|
-
return [];
|
|
566
|
-
}
|
|
567
|
-
return result[0].values.map((row) => ({
|
|
568
|
-
name: String(row[1]),
|
|
569
|
-
type: String(row[2]),
|
|
570
|
-
notnull: Number(row[3]),
|
|
571
|
-
pk: Number(row[5])
|
|
572
|
-
}));
|
|
573
|
-
}
|
|
574
|
-
close() {
|
|
575
|
-
if (this.db) {
|
|
576
|
-
this.persist();
|
|
577
|
-
this.db.close();
|
|
578
|
-
this.db = null;
|
|
579
|
-
this.tableColumnsCache.clear();
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
|
-
async beginTransaction() {
|
|
583
|
-
await this.execute("BEGIN TRANSACTION");
|
|
584
|
-
}
|
|
585
|
-
async commit() {
|
|
586
|
-
await this.execute("COMMIT");
|
|
587
|
-
this.persist();
|
|
588
|
-
}
|
|
589
|
-
async rollback() {
|
|
590
|
-
await this.execute("ROLLBACK");
|
|
591
|
-
}
|
|
592
|
-
async createMany(table, records, options) {
|
|
593
|
-
const db = this.getDb();
|
|
594
|
-
const ids = [];
|
|
595
|
-
const tableSchema = this.schema?.tables[table];
|
|
596
|
-
for (const record of records) {
|
|
597
|
-
const serializedRecord = this.serializeData(table, record);
|
|
598
|
-
let mainData = serializedRecord;
|
|
599
|
-
let translatableData = {};
|
|
600
|
-
if (tableSchema) {
|
|
601
|
-
const extracted = extractTranslatableData(serializedRecord, tableSchema);
|
|
602
|
-
mainData = extracted.mainData;
|
|
603
|
-
translatableData = extracted.translatableData;
|
|
604
|
-
}
|
|
605
|
-
const columns = Object.keys(mainData);
|
|
606
|
-
const values = Object.values(mainData);
|
|
607
|
-
const placeholders = columns.map(() => "?").join(", ");
|
|
608
|
-
const insertType = options?.ignore ? "INSERT OR IGNORE" : "INSERT";
|
|
609
|
-
const sql = `${insertType} INTO ${table} (${columns.join(", ")}) VALUES (${placeholders})`;
|
|
610
|
-
db.run(sql, values);
|
|
611
|
-
const lastId = db.exec("SELECT last_insert_rowid() as id")[0].values[0][0];
|
|
612
|
-
if (db.getRowsModified() > 0) {
|
|
613
|
-
ids.push(lastId);
|
|
614
|
-
if (Object.keys(translatableData).length > 0 && this.defaultLang) {
|
|
615
|
-
await this.upsertTranslation(table, lastId, this.defaultLang, translatableData);
|
|
616
|
-
}
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
|
-
this.persist();
|
|
620
|
-
return { created: ids.length, ids };
|
|
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
|
-
}
|
|
641
|
-
async updateMany(table, updates) {
|
|
642
|
-
let updated = 0;
|
|
643
|
-
for (const { id, data } of updates) {
|
|
644
|
-
await this.update(table, id, data);
|
|
645
|
-
updated++;
|
|
646
|
-
}
|
|
647
|
-
return { updated };
|
|
648
|
-
}
|
|
649
|
-
async deleteMany(table, ids) {
|
|
650
|
-
let deleted = 0;
|
|
651
|
-
for (const id of ids) {
|
|
652
|
-
const success = await this.delete(table, id);
|
|
653
|
-
if (success)
|
|
654
|
-
deleted++;
|
|
655
|
-
}
|
|
656
|
-
return { deleted };
|
|
657
|
-
}
|
|
658
|
-
export() {
|
|
659
|
-
return this.getDb().export();
|
|
660
|
-
}
|
|
661
|
-
async import(data) {
|
|
662
|
-
if (!this.SQL) {
|
|
663
|
-
throw new Error("Database not connected. Call connect() first.");
|
|
664
|
-
}
|
|
665
|
-
this.db?.close();
|
|
666
|
-
this.db = new this.SQL.Database(data);
|
|
667
|
-
this.persist();
|
|
668
|
-
}
|
|
669
|
-
clear() {
|
|
670
|
-
if (!this.SQL) {
|
|
671
|
-
throw new Error("Database not connected. Call connect() first.");
|
|
672
|
-
}
|
|
673
|
-
this.db?.close();
|
|
674
|
-
this.db = new this.SQL.Database;
|
|
675
|
-
this.persist();
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
|
-
export {
|
|
679
|
-
validatePopulate,
|
|
680
|
-
useDbUpdate,
|
|
681
|
-
useDbList,
|
|
682
|
-
useDbLang,
|
|
683
|
-
useDbGet,
|
|
684
|
-
useDbDelete,
|
|
685
|
-
useDbCreate,
|
|
686
|
-
useDb,
|
|
687
|
-
useAdapter,
|
|
688
|
-
resolvePopulate2 as resolvePopulate,
|
|
689
|
-
parseJSONSchema,
|
|
690
|
-
getPopulatableFields,
|
|
691
|
-
f,
|
|
692
|
-
defineSchema,
|
|
693
|
-
buildWhereClause2 as buildWhereClause,
|
|
694
|
-
SqliteAdapter,
|
|
695
|
-
ORM,
|
|
696
|
-
DbProvider
|
|
697
|
-
};
|
|
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
|
+
// Re-export ORM core for browser usage
|
|
8
|
+
export { ORM, defineSchema, f, buildWhereClause, resolvePopulate, getPopulatableFields, validatePopulate, parseJSONSchema, } from "@promakeai/orm";
|
|
9
|
+
// Provider
|
|
10
|
+
export { DbProvider, useDb, useAdapter, useDbLang, } from "./providers/DbProvider";
|
|
11
|
+
// Generic Hooks
|
|
12
|
+
export { useDbList, useDbGet, useDbCreate, useDbUpdate, useDbDelete, } from "./hooks/useDbHooks";
|
|
13
|
+
// Adapters
|
|
14
|
+
export { SqliteAdapter } from "./adapters/SqliteAdapter";
|
|
@@ -42,7 +42,7 @@ const defaultQueryClient = new QueryClient({
|
|
|
42
42
|
* }
|
|
43
43
|
* ```
|
|
44
44
|
*/
|
|
45
|
-
export function DbProvider({ adapter, lang: langProp = "en", fallbackLang = "en", autoConnect = true, queryClient = defaultQueryClient, children, }) {
|
|
45
|
+
export function DbProvider({ adapter, schema, lang: langProp = "en", fallbackLang = "en", autoConnect = true, queryClient = defaultQueryClient, children, }) {
|
|
46
46
|
const [isConnected, setIsConnected] = useState(false);
|
|
47
47
|
const [error, setError] = useState(null);
|
|
48
48
|
const [lang, setLangState] = useState(langProp);
|
|
@@ -94,9 +94,10 @@ export function DbProvider({ adapter, lang: langProp = "en", fallbackLang = "en"
|
|
|
94
94
|
// Database context value
|
|
95
95
|
const dbContextValue = useMemo(() => ({
|
|
96
96
|
adapter,
|
|
97
|
+
schema,
|
|
97
98
|
isConnected,
|
|
98
99
|
error,
|
|
99
|
-
}), [adapter, isConnected, error]);
|
|
100
|
+
}), [adapter, schema, isConnected, error]);
|
|
100
101
|
// Language context value
|
|
101
102
|
const langContextValue = useMemo(() => ({
|
|
102
103
|
lang,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@promakeai/dbreact",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "React client for schema-driven multi-language database",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -14,10 +14,12 @@
|
|
|
14
14
|
}
|
|
15
15
|
},
|
|
16
16
|
"scripts": {
|
|
17
|
-
"build": "
|
|
17
|
+
"build:js": "tsc --project tsconfig.json --declaration false --declarationMap false --emitDeclarationOnly false --outDir dist",
|
|
18
|
+
"build": "bun run build:js && bun run build:types",
|
|
18
19
|
"build:types": "tsc --emitDeclarationOnly --declaration --outDir dist",
|
|
19
20
|
"dev": "bun build index.ts --outdir dist --target browser --packages=external --watch",
|
|
20
21
|
"test": "bun test",
|
|
22
|
+
"test:build-runtime": "bun run build && bun test ./tests/build-runtime.test.ts",
|
|
21
23
|
"typecheck": "tsc --noEmit",
|
|
22
24
|
"release": "bun run build && npm publish --access public"
|
|
23
25
|
},
|
|
@@ -40,7 +42,7 @@
|
|
|
40
42
|
"sql.js": ">=1.11.0"
|
|
41
43
|
},
|
|
42
44
|
"dependencies": {
|
|
43
|
-
"@promakeai/orm": "1.0.
|
|
45
|
+
"@promakeai/orm": "1.0.5"
|
|
44
46
|
},
|
|
45
47
|
"devDependencies": {
|
|
46
48
|
"@tanstack/query-core": "5.90.20",
|