appflare 0.2.5 → 0.2.8
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/cli/commands/index.ts +73 -0
- package/cli/generate.ts +8 -0
- package/cli/index.ts +32 -1
- package/cli/templates/auth/config.ts +0 -2
- package/cli/templates/core/handlers.route.ts +1 -0
- package/cli/templates/core/imports.ts +1 -0
- package/cli/templates/dashboard/builders/functions/execute-handler.ts +124 -0
- package/cli/templates/dashboard/builders/functions/index.ts +22 -0
- package/cli/templates/dashboard/builders/functions/render-page/header.ts +20 -0
- package/cli/templates/dashboard/builders/functions/render-page/index.ts +33 -0
- package/cli/templates/dashboard/builders/functions/render-page/request-panel.ts +67 -0
- package/cli/templates/dashboard/builders/functions/render-page/result-panel.ts +19 -0
- package/cli/templates/dashboard/builders/functions/render-page/scripts.ts +17 -0
- package/cli/templates/dashboard/builders/navigation.ts +122 -0
- package/cli/templates/dashboard/builders/storage/index.ts +13 -0
- package/cli/templates/dashboard/builders/storage/routes/create-directory-route.ts +29 -0
- package/cli/templates/dashboard/builders/storage/routes/delete-route.ts +18 -0
- package/cli/templates/dashboard/builders/storage/routes/download-route.ts +23 -0
- package/cli/templates/dashboard/builders/storage/routes/index.ts +22 -0
- package/cli/templates/dashboard/builders/storage/routes/list-route.ts +25 -0
- package/cli/templates/dashboard/builders/storage/routes/preview-route.ts +21 -0
- package/cli/templates/dashboard/builders/storage/routes/upload-route.ts +21 -0
- package/cli/templates/dashboard/builders/storage/runtime/helpers.ts +72 -0
- package/cli/templates/dashboard/builders/storage/runtime/storage-page.ts +130 -0
- package/cli/templates/dashboard/builders/table-routes/common/drawer-panel.ts +27 -0
- package/cli/templates/dashboard/builders/table-routes/common/pagination.ts +30 -0
- package/cli/templates/dashboard/builders/table-routes/common/search-bar.ts +23 -0
- package/cli/templates/dashboard/builders/table-routes/fragments.ts +214 -0
- package/cli/templates/dashboard/builders/table-routes/helpers.ts +49 -0
- package/cli/templates/dashboard/builders/table-routes/index.ts +8 -0
- package/cli/templates/dashboard/builders/table-routes/table/actions-cell.ts +71 -0
- package/cli/templates/dashboard/builders/table-routes/table/get-route.ts +291 -0
- package/cli/templates/dashboard/builders/table-routes/table/index.ts +80 -0
- package/cli/templates/dashboard/builders/table-routes/table/post-routes.ts +163 -0
- package/cli/templates/dashboard/builders/table-routes/table-route.ts +7 -0
- package/cli/templates/dashboard/builders/table-routes/users/get-route.ts +69 -0
- package/cli/templates/dashboard/builders/table-routes/users/html/modals.ts +57 -0
- package/cli/templates/dashboard/builders/table-routes/users/html/page.ts +27 -0
- package/cli/templates/dashboard/builders/table-routes/users/html/table.ts +127 -0
- package/cli/templates/dashboard/builders/table-routes/users/index.ts +32 -0
- package/cli/templates/dashboard/builders/table-routes/users/post-routes.ts +150 -0
- package/cli/templates/dashboard/builders/table-routes/users/redirect.ts +14 -0
- package/cli/templates/dashboard/builders/table-routes/users-route.ts +10 -0
- package/cli/templates/dashboard/components/dashboard-home.ts +23 -0
- package/cli/templates/dashboard/components/layout.ts +388 -0
- package/cli/templates/dashboard/components/login-page.ts +65 -0
- package/cli/templates/dashboard/index.ts +61 -0
- package/cli/templates/dashboard/types.ts +9 -0
- package/cli/templates/handlers/generators/types/core.ts +5 -0
- package/cli/templates/handlers/generators/types/query-definitions/filter-and-where-types.ts +168 -0
- package/cli/templates/handlers/generators/types/query-definitions/query-api-types.ts +133 -0
- package/cli/templates/handlers/generators/types/query-definitions/query-helper-functions.ts +686 -0
- package/cli/templates/handlers/generators/types/query-definitions/schema-and-table-types.ts +97 -0
- package/cli/templates/handlers/generators/types/query-definitions.ts +11 -1083
- package/cli/templates/handlers/generators/types/query-runtime/handled-error.ts +13 -0
- package/cli/templates/handlers/generators/types/query-runtime/runtime-aggregate-and-footer.ts +164 -0
- package/cli/templates/handlers/generators/types/query-runtime/runtime-read.ts +85 -0
- package/cli/templates/handlers/generators/types/query-runtime/runtime-setup.ts +45 -0
- package/cli/templates/handlers/generators/types/query-runtime/runtime-write.ts +137 -0
- package/cli/templates/handlers/generators/types/query-runtime.ts +13 -431
- package/cli/utils/schema-discovery.ts +10 -1
- package/package.json +1 -1
- package/test-better-auth-hash.ts +2 -0
|
@@ -1,433 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const cache = new Map<string, unknown>();
|
|
7
|
-
const onMutation = options?.onMutation;
|
|
8
|
-
const queryDb = $db.query as Record<
|
|
9
|
-
string,
|
|
10
|
-
{
|
|
11
|
-
findMany: (args?: unknown) => Promise<unknown>;
|
|
12
|
-
findFirst: (args?: unknown) => Promise<unknown>;
|
|
13
|
-
}
|
|
14
|
-
>;
|
|
15
|
-
|
|
16
|
-
return new Proxy({} as AppflareQueryDb, {
|
|
17
|
-
get: (_target, property) => {
|
|
18
|
-
const tableName = String(property);
|
|
19
|
-
if (cache.has(tableName)) {
|
|
20
|
-
return cache.get(tableName);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const queryTable = queryDb[tableName];
|
|
24
|
-
if (!queryTable) {
|
|
25
|
-
return undefined;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const table = (mergedSchema as Record<string, unknown>)[tableName];
|
|
29
|
-
|
|
30
|
-
const emitMutation = (
|
|
31
|
-
kind: DbMutationKind,
|
|
32
|
-
args: Record<string, unknown>,
|
|
33
|
-
rows: unknown[],
|
|
34
|
-
): void => {
|
|
35
|
-
onMutation?.({
|
|
36
|
-
kind,
|
|
37
|
-
table: tableName,
|
|
38
|
-
args,
|
|
39
|
-
rows,
|
|
40
|
-
});
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
const tableApi = {
|
|
44
|
-
findMany: (args?: Record<string, unknown>) => {
|
|
45
|
-
const where = isRecord(args?.where)
|
|
46
|
-
? (args?.where as Record<string, unknown>)
|
|
47
|
-
: undefined;
|
|
48
|
-
const whereFilter = buildWhereFilter(table, where, tableName);
|
|
49
|
-
const passthroughArgs =
|
|
50
|
-
where !== undefined && !whereFilter
|
|
51
|
-
? (() => {
|
|
52
|
-
const nextArgs = { ...(args ?? {}) };
|
|
53
|
-
delete nextArgs.where;
|
|
54
|
-
return nextArgs;
|
|
55
|
-
})()
|
|
56
|
-
: args;
|
|
57
|
-
const withValue = args?.with;
|
|
58
|
-
const transformedWithResult =
|
|
59
|
-
withValue === undefined
|
|
60
|
-
? {
|
|
61
|
-
with: undefined,
|
|
62
|
-
aggregatePlan: undefined,
|
|
63
|
-
}
|
|
64
|
-
: transformWithRelationsAndExtractAggregates(withValue);
|
|
65
|
-
const transformedWith = transformedWithResult.with;
|
|
66
|
-
const aggregatePlan = transformedWithResult.aggregatePlan;
|
|
67
|
-
if (!whereFilter && transformedWith === withValue && !aggregatePlan) {
|
|
68
|
-
return queryTable.findMany(passthroughArgs);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const queryPromise = queryTable.findMany({
|
|
72
|
-
...(passthroughArgs ?? {}),
|
|
73
|
-
...(whereFilter ? { where: () => whereFilter } : {}),
|
|
74
|
-
...(transformedWith !== undefined ? { with: transformedWith } : {}),
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
if (!aggregatePlan) {
|
|
78
|
-
return queryPromise;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
return queryPromise.then((result) =>
|
|
82
|
-
applyRelationAggregatePlanToResult(result, aggregatePlan),
|
|
83
|
-
);
|
|
84
|
-
},
|
|
85
|
-
findFirst: (args?: Record<string, unknown>) => {
|
|
86
|
-
const where = isRecord(args?.where)
|
|
87
|
-
? (args?.where as Record<string, unknown>)
|
|
88
|
-
: undefined;
|
|
89
|
-
const whereFilter = buildWhereFilter(table, where, tableName);
|
|
90
|
-
const passthroughArgs =
|
|
91
|
-
where !== undefined && !whereFilter
|
|
92
|
-
? (() => {
|
|
93
|
-
const nextArgs = { ...(args ?? {}) };
|
|
94
|
-
delete nextArgs.where;
|
|
95
|
-
return nextArgs;
|
|
96
|
-
})()
|
|
97
|
-
: args;
|
|
98
|
-
const withValue = args?.with;
|
|
99
|
-
const transformedWithResult =
|
|
100
|
-
withValue === undefined
|
|
101
|
-
? {
|
|
102
|
-
with: undefined,
|
|
103
|
-
aggregatePlan: undefined,
|
|
104
|
-
}
|
|
105
|
-
: transformWithRelationsAndExtractAggregates(withValue);
|
|
106
|
-
const transformedWith = transformedWithResult.with;
|
|
107
|
-
const aggregatePlan = transformedWithResult.aggregatePlan;
|
|
108
|
-
if (!whereFilter && transformedWith === withValue && !aggregatePlan) {
|
|
109
|
-
return queryTable.findFirst(passthroughArgs);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const queryPromise = queryTable.findFirst({
|
|
113
|
-
...(passthroughArgs ?? {}),
|
|
114
|
-
...(whereFilter ? { where: () => whereFilter } : {}),
|
|
115
|
-
...(transformedWith !== undefined ? { with: transformedWith } : {}),
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
if (!aggregatePlan) {
|
|
119
|
-
return queryPromise;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
return queryPromise.then((result) =>
|
|
123
|
-
applyRelationAggregatePlanToResult(result, aggregatePlan),
|
|
124
|
-
);
|
|
125
|
-
},
|
|
126
|
-
insert: async (args: QueryInsertArgs<TableName>) => {
|
|
127
|
-
let insertQuery: any = ($db as any)
|
|
128
|
-
.insert(table as any)
|
|
129
|
-
.values(args.values as any);
|
|
130
|
-
|
|
131
|
-
if (typeof insertQuery.returning === "function") {
|
|
132
|
-
insertQuery = insertQuery.returning();
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
const rows = (await insertQuery) as Array<TableModel<TableName>>;
|
|
136
|
-
emitMutation(
|
|
137
|
-
"insert",
|
|
138
|
-
{ values: args.values as unknown as Record<string, unknown> },
|
|
139
|
-
rows,
|
|
140
|
-
);
|
|
141
|
-
return rows;
|
|
142
|
-
},
|
|
143
|
-
update: async (args: QueryUpdateArgs<TableName>) => {
|
|
144
|
-
const whereFilter = buildWhereFilter(
|
|
145
|
-
table,
|
|
146
|
-
args.where as Record<string, unknown> | undefined,
|
|
147
|
-
tableName,
|
|
148
|
-
);
|
|
149
|
-
let updateQuery: any = ($db as any)
|
|
150
|
-
.update(table as any)
|
|
151
|
-
.set(args.set as any);
|
|
152
|
-
|
|
153
|
-
if (whereFilter) {
|
|
154
|
-
updateQuery = updateQuery.where(whereFilter);
|
|
155
|
-
}
|
|
156
|
-
if (typeof args.limit === "number" && typeof updateQuery.limit === "function") {
|
|
157
|
-
updateQuery = updateQuery.limit(args.limit);
|
|
158
|
-
}
|
|
159
|
-
if (typeof updateQuery.returning === "function") {
|
|
160
|
-
updateQuery = updateQuery.returning();
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
const rows = (await updateQuery) as Array<TableModel<TableName>>;
|
|
164
|
-
emitMutation(
|
|
165
|
-
"update",
|
|
166
|
-
{
|
|
167
|
-
set: args.set as unknown as Record<string, unknown>,
|
|
168
|
-
where: (args.where ?? undefined) as unknown as Record<string, unknown>,
|
|
169
|
-
limit: args.limit,
|
|
170
|
-
},
|
|
171
|
-
rows,
|
|
172
|
-
);
|
|
173
|
-
return rows;
|
|
174
|
-
},
|
|
175
|
-
upsert: async (args: QueryUpsertArgs<TableName>) => {
|
|
176
|
-
const valuesArray = Array.isArray(args.values)
|
|
177
|
-
? args.values
|
|
178
|
-
: [args.values];
|
|
179
|
-
const values = Array.isArray(args.values)
|
|
180
|
-
? args.values
|
|
181
|
-
: args.values;
|
|
182
|
-
|
|
183
|
-
const targets = args.target
|
|
184
|
-
? Array.isArray(args.target)
|
|
185
|
-
? args.target
|
|
186
|
-
: [args.target]
|
|
187
|
-
: inferConflictTarget(table);
|
|
188
|
-
|
|
189
|
-
if (targets.length === 0) {
|
|
190
|
-
throw new Error(
|
|
191
|
-
"Unable to infer conflict target for table " + tableName + ". Provide target explicitly.",
|
|
192
|
-
);
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
const tableColumns = getTableColumns(table as never) as Record<string, unknown>;
|
|
196
|
-
const targetColumns = targets
|
|
197
|
-
.map((target) => tableColumns[target])
|
|
198
|
-
.filter(Boolean);
|
|
199
|
-
|
|
200
|
-
if (targetColumns.length === 0) {
|
|
201
|
-
throw new Error(
|
|
202
|
-
"Invalid conflict target for table " + tableName + ".",
|
|
203
|
-
);
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
const setPayload = args.set ?? valuesArray[0] ?? {};
|
|
207
|
-
let upsertQuery: any = ($db as any)
|
|
208
|
-
.insert(table as any)
|
|
209
|
-
.values(values as any)
|
|
210
|
-
.onConflictDoUpdate({
|
|
211
|
-
target: targetColumns as any,
|
|
212
|
-
set: setPayload as any,
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
if (typeof upsertQuery.returning === "function") {
|
|
216
|
-
upsertQuery = upsertQuery.returning();
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
const rows = (await upsertQuery) as Array<TableModel<TableName>>;
|
|
220
|
-
emitMutation(
|
|
221
|
-
"upsert",
|
|
222
|
-
{
|
|
223
|
-
values: args.values as unknown as Record<string, unknown>,
|
|
224
|
-
target: targets as unknown as Record<string, unknown>,
|
|
225
|
-
set: (args.set ?? undefined) as unknown as Record<string, unknown>,
|
|
226
|
-
},
|
|
227
|
-
rows,
|
|
228
|
-
);
|
|
229
|
-
return rows;
|
|
230
|
-
},
|
|
231
|
-
delete: async (args?: QueryDeleteArgs<TableName>) => {
|
|
232
|
-
const whereFilter = buildWhereFilter(
|
|
233
|
-
table,
|
|
234
|
-
args?.where as Record<string, unknown> | undefined,
|
|
235
|
-
tableName,
|
|
236
|
-
);
|
|
237
|
-
let deleteQuery: any = ($db as any).delete(table as any);
|
|
238
|
-
|
|
239
|
-
if (whereFilter) {
|
|
240
|
-
deleteQuery = deleteQuery.where(whereFilter);
|
|
241
|
-
}
|
|
242
|
-
if (typeof args?.limit === "number" && typeof deleteQuery.limit === "function") {
|
|
243
|
-
deleteQuery = deleteQuery.limit(args.limit);
|
|
244
|
-
}
|
|
245
|
-
if (typeof deleteQuery.returning === "function") {
|
|
246
|
-
deleteQuery = deleteQuery.returning();
|
|
247
|
-
}
|
|
1
|
+
import { generateQueryRuntimeAggregateAndFooterSection } from "./query-runtime/runtime-aggregate-and-footer";
|
|
2
|
+
import { generateQueryRuntimeHandledErrorSection } from "./query-runtime/handled-error";
|
|
3
|
+
import { generateQueryRuntimeReadSection } from "./query-runtime/runtime-read";
|
|
4
|
+
import { generateQueryRuntimeSetupSection } from "./query-runtime/runtime-setup";
|
|
5
|
+
import { generateQueryRuntimeWriteSection } from "./query-runtime/runtime-write";
|
|
248
6
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
);
|
|
258
|
-
return rows;
|
|
259
|
-
},
|
|
260
|
-
count: async (args?: QueryCountArgs<TableName>) => {
|
|
261
|
-
const withValue = args?.with;
|
|
262
|
-
const pathSegments = args?.field
|
|
263
|
-
? splitAggregateFieldPath(String(args.field))
|
|
264
|
-
: [];
|
|
265
|
-
if (args?.field && pathSegments.length === 0) {
|
|
266
|
-
throw new Error(
|
|
267
|
-
"Invalid count field for table " + tableName + ": " + String(args.field),
|
|
268
|
-
);
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
if (withValue !== undefined || pathSegments.length > 1) {
|
|
272
|
-
const whereFilter = buildWhereFilter(
|
|
273
|
-
table,
|
|
274
|
-
args?.where as Record<string, unknown> | undefined,
|
|
275
|
-
tableName,
|
|
276
|
-
);
|
|
277
|
-
const transformedWith =
|
|
278
|
-
withValue === undefined
|
|
279
|
-
? undefined
|
|
280
|
-
: transformWithRelations(withValue);
|
|
281
|
-
const rawRows = await queryTable.findMany({
|
|
282
|
-
...(whereFilter ? { where: () => whereFilter } : {}),
|
|
283
|
-
...(transformedWith !== undefined ? { with: transformedWith } : {}),
|
|
284
|
-
});
|
|
285
|
-
const rows = Array.isArray(rawRows) ? rawRows : [];
|
|
286
|
-
const constrainedRows = hasAggregateWithConstraints(withValue)
|
|
287
|
-
? rows.filter((row) =>
|
|
288
|
-
rowMatchesAggregateWithConstraints(row, withValue),
|
|
289
|
-
)
|
|
290
|
-
: rows;
|
|
291
|
-
|
|
292
|
-
if (!args?.field) {
|
|
293
|
-
return constrainedRows.length;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
const values = constrainedRows.flatMap((row) =>
|
|
297
|
-
collectValuesFromPath(row, pathSegments),
|
|
298
|
-
);
|
|
299
|
-
const useDistinct = args?.distinct ?? withValue !== undefined;
|
|
300
|
-
return countAggregateValues(values, useDistinct);
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
const whereFilter = buildWhereFilter(
|
|
304
|
-
table,
|
|
305
|
-
args?.where as Record<string, unknown> | undefined,
|
|
306
|
-
tableName,
|
|
307
|
-
);
|
|
308
|
-
const tableColumns = getTableColumns(table as never) as Record<string, unknown>;
|
|
309
|
-
const selectedField = args?.field
|
|
310
|
-
? tableColumns[String(args.field)]
|
|
311
|
-
: undefined;
|
|
312
|
-
|
|
313
|
-
if (args?.field && !selectedField) {
|
|
314
|
-
throw new Error(
|
|
315
|
-
"Invalid count field for table " + tableName + ": " + args.field,
|
|
316
|
-
);
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
let expression: SQL;
|
|
320
|
-
if (selectedField) {
|
|
321
|
-
expression = args?.distinct
|
|
322
|
-
? sql\`count(distinct \${selectedField as never})\`
|
|
323
|
-
: sql\`count(\${selectedField as never})\`;
|
|
324
|
-
} else {
|
|
325
|
-
expression = sql\`count(*)\`;
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
let query = ($db as any)
|
|
329
|
-
.select({ value: expression })
|
|
330
|
-
.from(table as any);
|
|
331
|
-
|
|
332
|
-
if (whereFilter) {
|
|
333
|
-
query = query.where(whereFilter);
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
const rows = (await query) as Array<{ value: unknown }>;
|
|
337
|
-
const value = Number(rows[0]?.value ?? 0);
|
|
338
|
-
return Number.isFinite(value) ? value : 0;
|
|
339
|
-
},
|
|
340
|
-
avg: async (args: QueryAvgArgs<TableName>) => {
|
|
341
|
-
const withValue = args.with;
|
|
342
|
-
const pathSegments = splitAggregateFieldPath(String(args.field));
|
|
343
|
-
if (pathSegments.length === 0) {
|
|
344
|
-
throw new Error(
|
|
345
|
-
"Invalid avg field for table " + tableName + ": " + String(args.field),
|
|
346
|
-
);
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
if (withValue !== undefined || pathSegments.length > 1) {
|
|
350
|
-
const whereFilter = buildWhereFilter(
|
|
351
|
-
table,
|
|
352
|
-
args.where as Record<string, unknown> | undefined,
|
|
353
|
-
tableName,
|
|
354
|
-
);
|
|
355
|
-
const transformedWith =
|
|
356
|
-
withValue === undefined
|
|
357
|
-
? undefined
|
|
358
|
-
: transformWithRelations(withValue);
|
|
359
|
-
const rawRows = await queryTable.findMany({
|
|
360
|
-
...(whereFilter ? { where: () => whereFilter } : {}),
|
|
361
|
-
...(transformedWith !== undefined ? { with: transformedWith } : {}),
|
|
362
|
-
});
|
|
363
|
-
const rows = Array.isArray(rawRows) ? rawRows : [];
|
|
364
|
-
const constrainedRows = hasAggregateWithConstraints(withValue)
|
|
365
|
-
? rows.filter((row) =>
|
|
366
|
-
rowMatchesAggregateWithConstraints(row, withValue),
|
|
367
|
-
)
|
|
368
|
-
: rows;
|
|
369
|
-
const numericValues = constrainedRows
|
|
370
|
-
.flatMap((row) => collectValuesFromPath(row, pathSegments))
|
|
371
|
-
.map((value) => toFiniteNumber(value))
|
|
372
|
-
.filter((value): value is number => value !== null);
|
|
373
|
-
const values = args.distinct
|
|
374
|
-
? Array.from(new Set<number>(numericValues))
|
|
375
|
-
: numericValues;
|
|
376
|
-
return averageAggregateValues(values);
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
const whereFilter = buildWhereFilter(
|
|
380
|
-
table,
|
|
381
|
-
args.where as Record<string, unknown> | undefined,
|
|
382
|
-
tableName,
|
|
383
|
-
);
|
|
384
|
-
const tableColumns = getTableColumns(table as never) as Record<string, unknown>;
|
|
385
|
-
const selectedField = tableColumns[String(args.field)];
|
|
386
|
-
|
|
387
|
-
if (!selectedField) {
|
|
388
|
-
throw new Error(
|
|
389
|
-
"Invalid avg field for table " + tableName + ": " + String(args.field),
|
|
390
|
-
);
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
const expression = args.distinct
|
|
394
|
-
? sql\`avg(distinct \${selectedField as never})\`
|
|
395
|
-
: sql\`avg(\${selectedField as never})\`;
|
|
396
|
-
|
|
397
|
-
let query = ($db as any)
|
|
398
|
-
.select({ value: expression })
|
|
399
|
-
.from(table as any);
|
|
400
|
-
|
|
401
|
-
if (whereFilter) {
|
|
402
|
-
query = query.where(whereFilter);
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
const rows = (await query) as Array<{ value: unknown }>;
|
|
406
|
-
const rawValue = rows[0]?.value;
|
|
407
|
-
if (rawValue === null || rawValue === undefined) {
|
|
408
|
-
return null;
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
const value = Number(rawValue);
|
|
412
|
-
return Number.isFinite(value) ? value : null;
|
|
413
|
-
},
|
|
414
|
-
};
|
|
415
|
-
|
|
416
|
-
cache.set(tableName, tableApi);
|
|
417
|
-
return tableApi;
|
|
418
|
-
},
|
|
419
|
-
}) as AppflareQueryDb;
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
export class AppflareHandledError extends Error {
|
|
423
|
-
public readonly status: number;
|
|
424
|
-
public readonly payload: unknown;
|
|
425
|
-
|
|
426
|
-
public constructor(status: number, payload: unknown) {
|
|
427
|
-
super(typeof payload === "object" ? "Handled error" : String(payload));
|
|
428
|
-
this.status = status;
|
|
429
|
-
this.payload = payload;
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
`;
|
|
7
|
+
export function generateTypesQueryRuntimeSection(): string {
|
|
8
|
+
return [
|
|
9
|
+
generateQueryRuntimeSetupSection(),
|
|
10
|
+
generateQueryRuntimeReadSection(),
|
|
11
|
+
generateQueryRuntimeWriteSection(),
|
|
12
|
+
generateQueryRuntimeAggregateAndFooterSection(),
|
|
13
|
+
generateQueryRuntimeHandledErrorSection(),
|
|
14
|
+
].join("\n\n");
|
|
433
15
|
}
|
|
@@ -5,7 +5,7 @@ import type { LoadedAppflareConfig } from "../types";
|
|
|
5
5
|
export type DiscoveredColumn = {
|
|
6
6
|
name: string;
|
|
7
7
|
expression: string;
|
|
8
|
-
type: "string" | "number" | "boolean" | "unknown";
|
|
8
|
+
type: "string" | "number" | "boolean" | "date" | "unknown";
|
|
9
9
|
optional: boolean;
|
|
10
10
|
primaryKey: boolean;
|
|
11
11
|
autoIncrement: boolean;
|
|
@@ -191,6 +191,15 @@ function getTopLevelColonIndex(entry: string): number {
|
|
|
191
191
|
|
|
192
192
|
function inferColumnType(expression: string): DiscoveredColumn["type"] {
|
|
193
193
|
const lowered = expression.toLowerCase();
|
|
194
|
+
if (/mode\s*:\s*["'`](timestamp|timestamp_ms)["'`]/.test(lowered)) {
|
|
195
|
+
return "date";
|
|
196
|
+
}
|
|
197
|
+
if (/mode\s*:\s*["'`]boolean["'`]/.test(lowered)) {
|
|
198
|
+
return "boolean";
|
|
199
|
+
}
|
|
200
|
+
if (/\.(date|datetime|timestamp)\s*\(/.test(lowered)) {
|
|
201
|
+
return "date";
|
|
202
|
+
}
|
|
194
203
|
if (/\.(int|integer|real|numeric|decimal|float|double)\s*\(/.test(lowered)) {
|
|
195
204
|
return "number";
|
|
196
205
|
}
|
package/package.json
CHANGED