@xylex-group/better-auth-athena 1.0.3 → 1.0.6
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/CONTRIBUTING.md +17 -0
- package/README.md +1 -1
- package/dist/index.cjs +466 -295
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +467 -298
- package/dist/index.js.map +1 -1
- package/package.json +4 -5
package/dist/index.cjs
CHANGED
|
@@ -42,9 +42,9 @@ var import_node_path = __toESM(require("path"), 1);
|
|
|
42
42
|
var import_yaml = __toESM(require("yaml"), 1);
|
|
43
43
|
var defaultAthenaGlobalConfig = {
|
|
44
44
|
athena: {
|
|
45
|
-
url: "
|
|
46
|
-
apiKey: "",
|
|
47
|
-
client: "
|
|
45
|
+
url: "https://mirror3.athena-db.com",
|
|
46
|
+
apiKey: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYXV0aGVudGljYXRlZCIsImVtYWlsIjoiZmxvcmlzQHh5bGV4LmFpIiwiZXhwIjoyNDk3MDMzNjY2fQ.LdPqTGaFq5pTokW1DA81WFjmG4nReJCOSKr3mFtXNoA",
|
|
47
|
+
client: "athena_logging"
|
|
48
48
|
}
|
|
49
49
|
};
|
|
50
50
|
var DEFAULT_CONFIG_FILENAME = "config.yaml";
|
|
@@ -119,7 +119,7 @@ function getAthenaGlobalConfig(options) {
|
|
|
119
119
|
return { config: cached, version };
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
-
// src/
|
|
122
|
+
// src/utils.ts
|
|
123
123
|
function toSnakeCase(key) {
|
|
124
124
|
return key.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/__/g, "_").toLowerCase();
|
|
125
125
|
}
|
|
@@ -164,7 +164,8 @@ function toDbRecord(data) {
|
|
|
164
164
|
);
|
|
165
165
|
return coerceDateFields(withDbKeys);
|
|
166
166
|
}
|
|
167
|
-
|
|
167
|
+
var defaultColumnMapper = (col) => hasUppercase(col) ? toSnakeCase(col) : col;
|
|
168
|
+
function applyWhere(builder, field, operator, value, columnMapper = defaultColumnMapper) {
|
|
168
169
|
const dbField = columnMapper(field);
|
|
169
170
|
switch (operator) {
|
|
170
171
|
case "eq":
|
|
@@ -197,6 +198,451 @@ function isMissingColumnError(error) {
|
|
|
197
198
|
const msg = String(error ?? "");
|
|
198
199
|
return msg.includes("specified column does not exist") || msg.includes("column does not exist");
|
|
199
200
|
}
|
|
201
|
+
function isSuccessMessageInError(error) {
|
|
202
|
+
const msg = String(error ?? "").toLowerCase();
|
|
203
|
+
return msg === "data inserted successfully" || msg === "data updated successfully" || msg === "data deleted successfully";
|
|
204
|
+
}
|
|
205
|
+
function snakeMapper(col) {
|
|
206
|
+
return hasUppercase(col) ? toSnakeCase(col) : col;
|
|
207
|
+
}
|
|
208
|
+
function identityMapper(col) {
|
|
209
|
+
return col;
|
|
210
|
+
}
|
|
211
|
+
function getRowValue(row, field) {
|
|
212
|
+
if (Object.prototype.hasOwnProperty.call(row, field)) return row[field];
|
|
213
|
+
const snake = hasUppercase(field) ? toSnakeCase(field) : field;
|
|
214
|
+
return row[snake];
|
|
215
|
+
}
|
|
216
|
+
function filterRowsByWhere(rows, where) {
|
|
217
|
+
if (!where.length) return rows;
|
|
218
|
+
return rows.filter((row) => {
|
|
219
|
+
for (const { field, operator, value } of where) {
|
|
220
|
+
const rowVal = getRowValue(row, field);
|
|
221
|
+
switch (operator) {
|
|
222
|
+
case "eq":
|
|
223
|
+
if (rowVal !== value) return false;
|
|
224
|
+
break;
|
|
225
|
+
case "ne":
|
|
226
|
+
if (rowVal === value) return false;
|
|
227
|
+
break;
|
|
228
|
+
case "in":
|
|
229
|
+
if (!Array.isArray(value) || !value.includes(rowVal)) return false;
|
|
230
|
+
break;
|
|
231
|
+
case "not_in":
|
|
232
|
+
if (Array.isArray(value) && value.includes(rowVal)) return false;
|
|
233
|
+
break;
|
|
234
|
+
default:
|
|
235
|
+
if (rowVal !== value) return false;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return true;
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// src/methods/create.ts
|
|
243
|
+
function createMethod(deps) {
|
|
244
|
+
const { ensureDbClient } = deps;
|
|
245
|
+
return async function create({
|
|
246
|
+
model,
|
|
247
|
+
data
|
|
248
|
+
}) {
|
|
249
|
+
const db = ensureDbClient();
|
|
250
|
+
const insertData = toDbRecord(data);
|
|
251
|
+
const { data: result, error } = await db.from(model).insert(insertData).select();
|
|
252
|
+
if (error && !isSuccessMessageInError(error)) {
|
|
253
|
+
throw new Error(`[AthenaAdapter] create on "${model}" failed: ${error}`);
|
|
254
|
+
}
|
|
255
|
+
const row = Array.isArray(result) ? result[0] : result;
|
|
256
|
+
return mapRowToBetterAuth(row ?? insertData);
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// src/methods/update.ts
|
|
261
|
+
function updateMethod(deps) {
|
|
262
|
+
const { ensureDbClient } = deps;
|
|
263
|
+
return async function update({
|
|
264
|
+
model,
|
|
265
|
+
where,
|
|
266
|
+
update
|
|
267
|
+
}) {
|
|
268
|
+
const db = ensureDbClient();
|
|
269
|
+
const updateData = toDbRecord(update);
|
|
270
|
+
const build = (useRetryShape) => {
|
|
271
|
+
if (!useRetryShape) {
|
|
272
|
+
let b2 = db.from(model).update({ data: updateData, set: updateData });
|
|
273
|
+
for (const clause of where) {
|
|
274
|
+
b2 = applyWhere(b2, clause.field, clause.operator, clause.value);
|
|
275
|
+
}
|
|
276
|
+
return b2;
|
|
277
|
+
}
|
|
278
|
+
let b = db.from(model).update(updateData, {
|
|
279
|
+
updateBody: { data: updateData, set: updateData }
|
|
280
|
+
});
|
|
281
|
+
for (const clause of where) {
|
|
282
|
+
b = applyWhere(b, clause.field, clause.operator, clause.value);
|
|
283
|
+
}
|
|
284
|
+
return b;
|
|
285
|
+
};
|
|
286
|
+
const run = async (b) => {
|
|
287
|
+
const { data: result, error } = await b.select();
|
|
288
|
+
return { result, error };
|
|
289
|
+
};
|
|
290
|
+
const first = await run(build(false));
|
|
291
|
+
if (first.error && !isSuccessMessageInError(first.error)) {
|
|
292
|
+
const msg = String(first.error);
|
|
293
|
+
if (msg.toLowerCase().includes("update payload required")) {
|
|
294
|
+
const retry = await run(build(true));
|
|
295
|
+
if (retry.error && !isSuccessMessageInError(retry.error)) {
|
|
296
|
+
throw new Error(
|
|
297
|
+
`[AthenaAdapter] update on "${model}" failed: ${retry.error}`
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
const row2 = Array.isArray(retry.result) ? retry.result[0] : retry.result;
|
|
301
|
+
return row2 ? mapRowToBetterAuth(row2) : null;
|
|
302
|
+
}
|
|
303
|
+
throw new Error(`[AthenaAdapter] update on "${model}" failed: ${first.error}`);
|
|
304
|
+
}
|
|
305
|
+
const row = Array.isArray(first.result) ? first.result[0] : first.result;
|
|
306
|
+
return row ? mapRowToBetterAuth(row) : null;
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// src/methods/update-many.ts
|
|
311
|
+
function updateManyMethod(deps) {
|
|
312
|
+
const { ensureDbClient } = deps;
|
|
313
|
+
return async function updateMany({
|
|
314
|
+
model,
|
|
315
|
+
where,
|
|
316
|
+
update
|
|
317
|
+
}) {
|
|
318
|
+
const db = ensureDbClient();
|
|
319
|
+
const updateData = toDbRecord(update);
|
|
320
|
+
const build = (useRetryShape) => {
|
|
321
|
+
if (!useRetryShape) {
|
|
322
|
+
let b2 = db.from(model).update({ data: updateData, set: updateData });
|
|
323
|
+
for (const clause of where) {
|
|
324
|
+
b2 = applyWhere(b2, clause.field, clause.operator, clause.value);
|
|
325
|
+
}
|
|
326
|
+
return b2;
|
|
327
|
+
}
|
|
328
|
+
let b = db.from(model).update(updateData, {
|
|
329
|
+
updateBody: { data: updateData, set: updateData }
|
|
330
|
+
});
|
|
331
|
+
for (const clause of where) {
|
|
332
|
+
b = applyWhere(b, clause.field, clause.operator, clause.value);
|
|
333
|
+
}
|
|
334
|
+
return b;
|
|
335
|
+
};
|
|
336
|
+
const run = async (b) => {
|
|
337
|
+
const { data: result, error } = await b.select();
|
|
338
|
+
return { result, error };
|
|
339
|
+
};
|
|
340
|
+
const first = await run(build(false));
|
|
341
|
+
if (first.error && !isSuccessMessageInError(first.error)) {
|
|
342
|
+
const msg = String(first.error);
|
|
343
|
+
if (msg.toLowerCase().includes("update payload required")) {
|
|
344
|
+
const retry = await run(build(true));
|
|
345
|
+
if (retry.error && !isSuccessMessageInError(retry.error)) {
|
|
346
|
+
throw new Error(
|
|
347
|
+
`[AthenaAdapter] updateMany on "${model}" failed: ${retry.error}`
|
|
348
|
+
);
|
|
349
|
+
}
|
|
350
|
+
return Array.isArray(retry.result) ? retry.result.length : retry.result ? 1 : 0;
|
|
351
|
+
}
|
|
352
|
+
throw new Error(
|
|
353
|
+
`[AthenaAdapter] updateMany on "${model}" failed: ${first.error}`
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
return Array.isArray(first.result) ? first.result.length : first.result ? 1 : 0;
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// src/methods/delete.ts
|
|
361
|
+
function deleteMethod(deps) {
|
|
362
|
+
const { ensureDbClient, headers } = deps;
|
|
363
|
+
return async function del({
|
|
364
|
+
model,
|
|
365
|
+
where
|
|
366
|
+
}) {
|
|
367
|
+
const db = ensureDbClient();
|
|
368
|
+
let builder = db.from(model);
|
|
369
|
+
for (const clause of where) {
|
|
370
|
+
builder = applyWhere(
|
|
371
|
+
builder,
|
|
372
|
+
clause.field,
|
|
373
|
+
clause.operator,
|
|
374
|
+
clause.value
|
|
375
|
+
);
|
|
376
|
+
}
|
|
377
|
+
const { error } = await builder.delete(
|
|
378
|
+
headers ? { headers } : void 0
|
|
379
|
+
);
|
|
380
|
+
if (error && !isSuccessMessageInError(error)) {
|
|
381
|
+
throw new Error(
|
|
382
|
+
`[AthenaAdapter] delete on "${model}" failed: ${error}`
|
|
383
|
+
);
|
|
384
|
+
}
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// src/methods/delete-many.ts
|
|
389
|
+
function deleteManyMethod(deps) {
|
|
390
|
+
const { ensureDbClient, headers } = deps;
|
|
391
|
+
return async function deleteMany({
|
|
392
|
+
model,
|
|
393
|
+
where
|
|
394
|
+
}) {
|
|
395
|
+
const db = ensureDbClient();
|
|
396
|
+
const mainBuilder = db.from(model);
|
|
397
|
+
let builder = mainBuilder;
|
|
398
|
+
for (const clause of where) {
|
|
399
|
+
builder = applyWhere(
|
|
400
|
+
builder,
|
|
401
|
+
clause.field,
|
|
402
|
+
clause.operator,
|
|
403
|
+
clause.value
|
|
404
|
+
);
|
|
405
|
+
}
|
|
406
|
+
const { data: result, error } = await builder.delete(
|
|
407
|
+
headers ? { headers } : void 0
|
|
408
|
+
).select();
|
|
409
|
+
if (error && !isSuccessMessageInError(error)) {
|
|
410
|
+
throw new Error(
|
|
411
|
+
`[AthenaAdapter] deleteMany on "${model}" failed: ${error}`
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
const deletedCount = Array.isArray(result) ? result.length : result ? 1 : 0;
|
|
415
|
+
const inClause = where.find(
|
|
416
|
+
(c) => c.operator === "in" && c.value != null
|
|
417
|
+
);
|
|
418
|
+
if (inClause && Array.isArray(inClause.value) && deletedCount < inClause.value.length) {
|
|
419
|
+
let n = 0;
|
|
420
|
+
for (const v of inClause.value) {
|
|
421
|
+
const b = db.from(model);
|
|
422
|
+
const filtered = applyWhere(
|
|
423
|
+
b,
|
|
424
|
+
inClause.field,
|
|
425
|
+
"eq",
|
|
426
|
+
v
|
|
427
|
+
);
|
|
428
|
+
const { data: rowData, error: rowErr } = await filtered.delete(
|
|
429
|
+
headers ? { headers } : void 0
|
|
430
|
+
).select();
|
|
431
|
+
if (rowErr && isSuccessMessageInError(rowErr)) continue;
|
|
432
|
+
n += Array.isArray(rowData) ? rowData.length : rowData ? 1 : 0;
|
|
433
|
+
}
|
|
434
|
+
return n;
|
|
435
|
+
}
|
|
436
|
+
return deletedCount;
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// src/methods/find-one.ts
|
|
441
|
+
function findOneMethod(deps) {
|
|
442
|
+
const { ensureDbClient } = deps;
|
|
443
|
+
return async function findOne({
|
|
444
|
+
model,
|
|
445
|
+
where,
|
|
446
|
+
select
|
|
447
|
+
}) {
|
|
448
|
+
const db = ensureDbClient();
|
|
449
|
+
const run = async (columnMapper) => {
|
|
450
|
+
const columns = select && select.length > 0 ? select.map((c) => columnMapper(c)).join(", ") : void 0;
|
|
451
|
+
let builder = db.from(model).select(columns);
|
|
452
|
+
for (const clause of where) {
|
|
453
|
+
builder = applyWhere(
|
|
454
|
+
builder,
|
|
455
|
+
clause.field,
|
|
456
|
+
clause.operator,
|
|
457
|
+
clause.value,
|
|
458
|
+
columnMapper
|
|
459
|
+
);
|
|
460
|
+
}
|
|
461
|
+
const { data: result, error } = await builder.limit(1);
|
|
462
|
+
return { result, error };
|
|
463
|
+
};
|
|
464
|
+
const first = await run(snakeMapper);
|
|
465
|
+
if (first.error) {
|
|
466
|
+
if (isMissingColumnError(first.error)) {
|
|
467
|
+
const retry = await run(identityMapper);
|
|
468
|
+
if (retry.error) {
|
|
469
|
+
throw new Error(
|
|
470
|
+
`[AthenaAdapter] findOne on "${model}" failed: ${retry.error}`
|
|
471
|
+
);
|
|
472
|
+
}
|
|
473
|
+
const rows2 = Array.isArray(retry.result) ? retry.result : retry.result ? [retry.result] : [];
|
|
474
|
+
const row2 = rows2[0] ?? null;
|
|
475
|
+
return row2 ? mapRowToBetterAuth(row2) : null;
|
|
476
|
+
}
|
|
477
|
+
throw new Error(
|
|
478
|
+
`[AthenaAdapter] findOne on "${model}" failed: ${first.error}`
|
|
479
|
+
);
|
|
480
|
+
}
|
|
481
|
+
const rows = Array.isArray(first.result) ? first.result : first.result ? [first.result] : [];
|
|
482
|
+
const row = rows[0] ?? null;
|
|
483
|
+
if (!row) return null;
|
|
484
|
+
const mapped = mapRowToBetterAuth(row);
|
|
485
|
+
const filtered = filterRowsByWhere(
|
|
486
|
+
[mapped],
|
|
487
|
+
where
|
|
488
|
+
);
|
|
489
|
+
return filtered[0] ? mapped : null;
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// src/methods/find-many.ts
|
|
494
|
+
function findManyMethod(deps) {
|
|
495
|
+
const { ensureDbClient } = deps;
|
|
496
|
+
return async function findMany({
|
|
497
|
+
model,
|
|
498
|
+
where,
|
|
499
|
+
limit,
|
|
500
|
+
sortBy,
|
|
501
|
+
offset,
|
|
502
|
+
select
|
|
503
|
+
}) {
|
|
504
|
+
const db = ensureDbClient();
|
|
505
|
+
const run = async (columnMapper, opts) => {
|
|
506
|
+
const columns = select && select.length > 0 ? select.map((c) => columnMapper(c)).join(", ") : void 0;
|
|
507
|
+
let builder = db.from(model).select(columns);
|
|
508
|
+
if (!opts?.skipWhere && where) {
|
|
509
|
+
for (const clause of where) {
|
|
510
|
+
builder = applyWhere(
|
|
511
|
+
builder,
|
|
512
|
+
clause.field,
|
|
513
|
+
clause.operator,
|
|
514
|
+
clause.value,
|
|
515
|
+
columnMapper
|
|
516
|
+
);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
const effectiveLimit = opts?.limitOverride ?? limit;
|
|
520
|
+
const effectiveOffset = opts?.offsetOverride ?? offset;
|
|
521
|
+
if (effectiveLimit !== void 0) {
|
|
522
|
+
builder = builder.limit(effectiveLimit);
|
|
523
|
+
}
|
|
524
|
+
if (effectiveOffset !== void 0) {
|
|
525
|
+
builder = builder.offset(effectiveOffset);
|
|
526
|
+
}
|
|
527
|
+
const { data: result, error } = await builder;
|
|
528
|
+
return { result, error };
|
|
529
|
+
};
|
|
530
|
+
const first = await run(snakeMapper);
|
|
531
|
+
const pickRows = (res) => Array.isArray(res) ? res : [];
|
|
532
|
+
const applySort = (rows) => {
|
|
533
|
+
if (!sortBy) return rows;
|
|
534
|
+
const sortField = sortBy.field;
|
|
535
|
+
rows.sort((a, b) => {
|
|
536
|
+
const aVal = a[sortField];
|
|
537
|
+
const bVal = b[sortField];
|
|
538
|
+
if (aVal == null && bVal == null) return 0;
|
|
539
|
+
if (aVal == null) return sortBy.direction === "asc" ? -1 : 1;
|
|
540
|
+
if (bVal == null) return sortBy.direction === "asc" ? 1 : -1;
|
|
541
|
+
const cmp = typeof aVal === "string" && typeof bVal === "string" ? aVal.localeCompare(bVal) : aVal < bVal ? -1 : aVal > bVal ? 1 : 0;
|
|
542
|
+
return sortBy.direction === "asc" ? cmp : -cmp;
|
|
543
|
+
});
|
|
544
|
+
return rows;
|
|
545
|
+
};
|
|
546
|
+
const mapAndSort = (rows) => {
|
|
547
|
+
const betterAuthRows = rows.map((r) => mapRowToBetterAuth(r));
|
|
548
|
+
if (!where?.length) return applySort(betterAuthRows);
|
|
549
|
+
const filtered = filterRowsByWhere(
|
|
550
|
+
betterAuthRows,
|
|
551
|
+
where
|
|
552
|
+
);
|
|
553
|
+
if (filtered.length !== betterAuthRows.length) {
|
|
554
|
+
const off = offset ?? 0;
|
|
555
|
+
const end = limit !== void 0 ? off + limit : void 0;
|
|
556
|
+
return applySort(filtered).slice(off, end);
|
|
557
|
+
}
|
|
558
|
+
return applySort(filtered);
|
|
559
|
+
};
|
|
560
|
+
const postFilterAndSlice = (rows) => {
|
|
561
|
+
const mappedSorted = mapAndSort(rows);
|
|
562
|
+
const off = offset ?? 0;
|
|
563
|
+
const end = limit !== void 0 ? off + limit : void 0;
|
|
564
|
+
return mappedSorted.slice(off, end);
|
|
565
|
+
};
|
|
566
|
+
if (first.error) {
|
|
567
|
+
if (isMissingColumnError(first.error)) {
|
|
568
|
+
const retry = await run(identityMapper);
|
|
569
|
+
if (retry.error) {
|
|
570
|
+
throw new Error(
|
|
571
|
+
`[AthenaAdapter] findMany on "${model}" failed: ${retry.error}`
|
|
572
|
+
);
|
|
573
|
+
}
|
|
574
|
+
const retryRows = pickRows(retry.result);
|
|
575
|
+
if (where?.length) {
|
|
576
|
+
const broad = await run(identityMapper, {
|
|
577
|
+
skipWhere: true,
|
|
578
|
+
limitOverride: Math.max((offset ?? 0) + (limit ?? 0) + 500, 5e3),
|
|
579
|
+
offsetOverride: 0
|
|
580
|
+
});
|
|
581
|
+
if (!broad.error) return postFilterAndSlice(pickRows(broad.result));
|
|
582
|
+
}
|
|
583
|
+
return mapAndSort(retryRows);
|
|
584
|
+
}
|
|
585
|
+
throw new Error(
|
|
586
|
+
`[AthenaAdapter] findMany on "${model}" failed: ${first.error}`
|
|
587
|
+
);
|
|
588
|
+
}
|
|
589
|
+
const firstRows = pickRows(first.result);
|
|
590
|
+
if (where?.length) {
|
|
591
|
+
const broad = await run(snakeMapper, {
|
|
592
|
+
skipWhere: true,
|
|
593
|
+
limitOverride: Math.max((offset ?? 0) + (limit ?? 0) + 500, 5e3),
|
|
594
|
+
offsetOverride: 0
|
|
595
|
+
});
|
|
596
|
+
if (!broad.error) return postFilterAndSlice(pickRows(broad.result));
|
|
597
|
+
}
|
|
598
|
+
return mapAndSort(firstRows);
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
// src/methods/count.ts
|
|
603
|
+
function countMethod(deps) {
|
|
604
|
+
const { ensureDbClient } = deps;
|
|
605
|
+
return async function count({
|
|
606
|
+
model,
|
|
607
|
+
where
|
|
608
|
+
}) {
|
|
609
|
+
const db = ensureDbClient();
|
|
610
|
+
const run = async (columnMapper) => {
|
|
611
|
+
let builder = db.from(model).select();
|
|
612
|
+
if (where) {
|
|
613
|
+
for (const clause of where) {
|
|
614
|
+
builder = applyWhere(
|
|
615
|
+
builder,
|
|
616
|
+
clause.field,
|
|
617
|
+
clause.operator,
|
|
618
|
+
clause.value,
|
|
619
|
+
columnMapper
|
|
620
|
+
);
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
const { data: result, error } = await builder;
|
|
624
|
+
return { result, error };
|
|
625
|
+
};
|
|
626
|
+
const first = await run(snakeMapper);
|
|
627
|
+
if (first.error) {
|
|
628
|
+
if (isMissingColumnError(first.error)) {
|
|
629
|
+
const retry = await run(identityMapper);
|
|
630
|
+
if (retry.error) {
|
|
631
|
+
throw new Error(
|
|
632
|
+
`[AthenaAdapter] count on "${model}" failed: ${retry.error}`
|
|
633
|
+
);
|
|
634
|
+
}
|
|
635
|
+
return Array.isArray(retry.result) ? retry.result.length : 0;
|
|
636
|
+
}
|
|
637
|
+
throw new Error(
|
|
638
|
+
`[AthenaAdapter] count on "${model}" failed: ${first.error}`
|
|
639
|
+
);
|
|
640
|
+
}
|
|
641
|
+
return Array.isArray(first.result) ? first.result.length : 0;
|
|
642
|
+
};
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
// src/index.ts
|
|
200
646
|
var athenaAdapter = (config) => {
|
|
201
647
|
let dbClient = null;
|
|
202
648
|
let lastDbConfigVersion = -1;
|
|
@@ -205,7 +651,8 @@ var athenaAdapter = (config) => {
|
|
|
205
651
|
if (shouldUseFixedConfig) {
|
|
206
652
|
if (!dbClient) {
|
|
207
653
|
dbClient = (0, import_athena.createClient)(config.url, config.apiKey, {
|
|
208
|
-
client: config.client
|
|
654
|
+
client: config.client,
|
|
655
|
+
...config.headers && { headers: config.headers }
|
|
209
656
|
});
|
|
210
657
|
}
|
|
211
658
|
return dbClient;
|
|
@@ -223,18 +670,21 @@ var athenaAdapter = (config) => {
|
|
|
223
670
|
);
|
|
224
671
|
}
|
|
225
672
|
if (!dbClient || version2 !== lastDbConfigVersion) {
|
|
226
|
-
dbClient = (0, import_athena.createClient)(url, apiKey, {
|
|
673
|
+
dbClient = (0, import_athena.createClient)(url, apiKey, {
|
|
674
|
+
client,
|
|
675
|
+
...config.headers && { headers: config.headers }
|
|
676
|
+
});
|
|
227
677
|
lastDbConfigVersion = version2;
|
|
228
678
|
}
|
|
229
679
|
return dbClient;
|
|
230
680
|
}
|
|
681
|
+
const deps = { ensureDbClient, headers: config.headers };
|
|
231
682
|
return (0, import_adapters.createAdapterFactory)({
|
|
232
683
|
config: {
|
|
233
684
|
adapterId: "athena",
|
|
234
685
|
adapterName: "Athena Adapter",
|
|
235
686
|
usePlural: config.usePlural ?? false,
|
|
236
687
|
debugLogs: config.debugLogs ?? false,
|
|
237
|
-
// Athena/Postgres supports all these natively
|
|
238
688
|
supportsJSON: true,
|
|
239
689
|
supportsDates: true,
|
|
240
690
|
supportsBooleans: true,
|
|
@@ -243,293 +693,14 @@ var athenaAdapter = (config) => {
|
|
|
243
693
|
},
|
|
244
694
|
adapter: () => {
|
|
245
695
|
return {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
const insertData = toDbRecord(data);
|
|
255
|
-
const { data: result, error } = await db.from(model).insert(insertData).select();
|
|
256
|
-
if (error) {
|
|
257
|
-
throw new Error(
|
|
258
|
-
`[AthenaAdapter] create on "${model}" failed: ${error}`
|
|
259
|
-
);
|
|
260
|
-
}
|
|
261
|
-
const row = Array.isArray(result) ? result[0] : result;
|
|
262
|
-
return mapRowToBetterAuth(row ?? insertData);
|
|
263
|
-
},
|
|
264
|
-
// ------------------------------------------------------------------
|
|
265
|
-
// UPDATE
|
|
266
|
-
// ------------------------------------------------------------------
|
|
267
|
-
update: async ({
|
|
268
|
-
model,
|
|
269
|
-
where,
|
|
270
|
-
update
|
|
271
|
-
}) => {
|
|
272
|
-
const db = ensureDbClient();
|
|
273
|
-
const updateData = toDbRecord(update);
|
|
274
|
-
let builder = db.from(model).update({ set: updateData });
|
|
275
|
-
for (const clause of where) {
|
|
276
|
-
builder = applyWhere(
|
|
277
|
-
builder,
|
|
278
|
-
clause.field,
|
|
279
|
-
clause.operator,
|
|
280
|
-
clause.value
|
|
281
|
-
);
|
|
282
|
-
}
|
|
283
|
-
const { data: result, error } = await builder.select();
|
|
284
|
-
if (error) {
|
|
285
|
-
throw new Error(
|
|
286
|
-
`[AthenaAdapter] update on "${model}" failed: ${error}`
|
|
287
|
-
);
|
|
288
|
-
}
|
|
289
|
-
const row = Array.isArray(result) ? result[0] : result;
|
|
290
|
-
return row ? mapRowToBetterAuth(row) : null;
|
|
291
|
-
},
|
|
292
|
-
// ------------------------------------------------------------------
|
|
293
|
-
// UPDATE MANY
|
|
294
|
-
// ------------------------------------------------------------------
|
|
295
|
-
updateMany: async ({
|
|
296
|
-
model,
|
|
297
|
-
where,
|
|
298
|
-
update
|
|
299
|
-
}) => {
|
|
300
|
-
const db = ensureDbClient();
|
|
301
|
-
const updateData = toDbRecord(update);
|
|
302
|
-
let builder = db.from(model).update({ set: updateData });
|
|
303
|
-
for (const clause of where) {
|
|
304
|
-
builder = applyWhere(
|
|
305
|
-
builder,
|
|
306
|
-
clause.field,
|
|
307
|
-
clause.operator,
|
|
308
|
-
clause.value
|
|
309
|
-
);
|
|
310
|
-
}
|
|
311
|
-
const { data: result, error } = await builder.select();
|
|
312
|
-
if (error) {
|
|
313
|
-
throw new Error(
|
|
314
|
-
`[AthenaAdapter] updateMany on "${model}" failed: ${error}`
|
|
315
|
-
);
|
|
316
|
-
}
|
|
317
|
-
return Array.isArray(result) ? result.length : result ? 1 : 0;
|
|
318
|
-
},
|
|
319
|
-
// ------------------------------------------------------------------
|
|
320
|
-
// DELETE
|
|
321
|
-
// ------------------------------------------------------------------
|
|
322
|
-
delete: async ({
|
|
323
|
-
model,
|
|
324
|
-
where
|
|
325
|
-
}) => {
|
|
326
|
-
const db = ensureDbClient();
|
|
327
|
-
let builder = db.from(model);
|
|
328
|
-
for (const clause of where) {
|
|
329
|
-
builder = applyWhere(
|
|
330
|
-
builder,
|
|
331
|
-
clause.field,
|
|
332
|
-
clause.operator,
|
|
333
|
-
clause.value
|
|
334
|
-
);
|
|
335
|
-
}
|
|
336
|
-
const { error } = await builder.delete();
|
|
337
|
-
if (error) {
|
|
338
|
-
throw new Error(
|
|
339
|
-
`[AthenaAdapter] delete on "${model}" failed: ${error}`
|
|
340
|
-
);
|
|
341
|
-
}
|
|
342
|
-
},
|
|
343
|
-
// ------------------------------------------------------------------
|
|
344
|
-
// DELETE MANY
|
|
345
|
-
// ------------------------------------------------------------------
|
|
346
|
-
deleteMany: async ({
|
|
347
|
-
model,
|
|
348
|
-
where
|
|
349
|
-
}) => {
|
|
350
|
-
const db = ensureDbClient();
|
|
351
|
-
let builder = db.from(model);
|
|
352
|
-
for (const clause of where) {
|
|
353
|
-
builder = applyWhere(
|
|
354
|
-
builder,
|
|
355
|
-
clause.field,
|
|
356
|
-
clause.operator,
|
|
357
|
-
clause.value
|
|
358
|
-
);
|
|
359
|
-
}
|
|
360
|
-
const { data: result, error } = await builder.delete().select();
|
|
361
|
-
if (error) {
|
|
362
|
-
throw new Error(
|
|
363
|
-
`[AthenaAdapter] deleteMany on "${model}" failed: ${error}`
|
|
364
|
-
);
|
|
365
|
-
}
|
|
366
|
-
return Array.isArray(result) ? result.length : result ? 1 : 0;
|
|
367
|
-
},
|
|
368
|
-
// ------------------------------------------------------------------
|
|
369
|
-
// FIND ONE
|
|
370
|
-
// ------------------------------------------------------------------
|
|
371
|
-
findOne: async ({
|
|
372
|
-
model,
|
|
373
|
-
where,
|
|
374
|
-
select
|
|
375
|
-
}) => {
|
|
376
|
-
const db = ensureDbClient();
|
|
377
|
-
const snakeMapper = (col) => hasUppercase(col) ? toSnakeCase(col) : col;
|
|
378
|
-
const identityMapper = (col) => col;
|
|
379
|
-
const run = async (columnMapper) => {
|
|
380
|
-
const columns = select && select.length > 0 ? select.map((c) => columnMapper(c)).join(", ") : void 0;
|
|
381
|
-
let builder = db.from(model).select(columns);
|
|
382
|
-
for (const clause of where) {
|
|
383
|
-
builder = applyWhere(
|
|
384
|
-
builder,
|
|
385
|
-
clause.field,
|
|
386
|
-
clause.operator,
|
|
387
|
-
clause.value,
|
|
388
|
-
columnMapper
|
|
389
|
-
);
|
|
390
|
-
}
|
|
391
|
-
const { data: result, error } = await builder.limit(1);
|
|
392
|
-
return { result, error };
|
|
393
|
-
};
|
|
394
|
-
const first = await run(snakeMapper);
|
|
395
|
-
if (first.error) {
|
|
396
|
-
if (isMissingColumnError(first.error)) {
|
|
397
|
-
const retry = await run(identityMapper);
|
|
398
|
-
if (retry.error) {
|
|
399
|
-
throw new Error(
|
|
400
|
-
`[AthenaAdapter] findOne on "${model}" failed: ${retry.error}`
|
|
401
|
-
);
|
|
402
|
-
}
|
|
403
|
-
const rows2 = Array.isArray(retry.result) ? retry.result : retry.result ? [retry.result] : [];
|
|
404
|
-
const row2 = rows2[0] ?? null;
|
|
405
|
-
return row2 ? mapRowToBetterAuth(row2) : null;
|
|
406
|
-
}
|
|
407
|
-
throw new Error(
|
|
408
|
-
`[AthenaAdapter] findOne on "${model}" failed: ${first.error}`
|
|
409
|
-
);
|
|
410
|
-
}
|
|
411
|
-
const rows = Array.isArray(first.result) ? first.result : first.result ? [first.result] : [];
|
|
412
|
-
const row = rows[0] ?? null;
|
|
413
|
-
return row ? mapRowToBetterAuth(row) : null;
|
|
414
|
-
},
|
|
415
|
-
// ------------------------------------------------------------------
|
|
416
|
-
// FIND MANY
|
|
417
|
-
// ------------------------------------------------------------------
|
|
418
|
-
findMany: async ({
|
|
419
|
-
model,
|
|
420
|
-
where,
|
|
421
|
-
limit,
|
|
422
|
-
sortBy,
|
|
423
|
-
offset,
|
|
424
|
-
select
|
|
425
|
-
}) => {
|
|
426
|
-
const db = ensureDbClient();
|
|
427
|
-
const snakeMapper = (col) => hasUppercase(col) ? toSnakeCase(col) : col;
|
|
428
|
-
const identityMapper = (col) => col;
|
|
429
|
-
const run = async (columnMapper) => {
|
|
430
|
-
const columns = select && select.length > 0 ? select.map((c) => columnMapper(c)).join(", ") : void 0;
|
|
431
|
-
let builder = db.from(model).select(columns);
|
|
432
|
-
if (where) {
|
|
433
|
-
for (const clause of where) {
|
|
434
|
-
builder = applyWhere(
|
|
435
|
-
builder,
|
|
436
|
-
clause.field,
|
|
437
|
-
clause.operator,
|
|
438
|
-
clause.value,
|
|
439
|
-
columnMapper
|
|
440
|
-
);
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
if (limit !== void 0) {
|
|
444
|
-
builder = builder.limit(limit);
|
|
445
|
-
}
|
|
446
|
-
if (offset !== void 0) {
|
|
447
|
-
builder = builder.offset(offset);
|
|
448
|
-
}
|
|
449
|
-
const { data: result, error } = await builder;
|
|
450
|
-
return { result, error };
|
|
451
|
-
};
|
|
452
|
-
const first = await run(snakeMapper);
|
|
453
|
-
const pickRows = (res) => Array.isArray(res) ? res : [];
|
|
454
|
-
const applySort = (rows) => {
|
|
455
|
-
if (!sortBy) return rows;
|
|
456
|
-
const sortField = sortBy.field;
|
|
457
|
-
rows.sort((a, b) => {
|
|
458
|
-
const aVal = a[sortField];
|
|
459
|
-
const bVal = b[sortField];
|
|
460
|
-
if (aVal == null && bVal == null) return 0;
|
|
461
|
-
if (aVal == null) return sortBy.direction === "asc" ? -1 : 1;
|
|
462
|
-
if (bVal == null) return sortBy.direction === "asc" ? 1 : -1;
|
|
463
|
-
const cmp = typeof aVal === "string" && typeof bVal === "string" ? aVal.localeCompare(bVal) : aVal < bVal ? -1 : aVal > bVal ? 1 : 0;
|
|
464
|
-
return sortBy.direction === "asc" ? cmp : -cmp;
|
|
465
|
-
});
|
|
466
|
-
return rows;
|
|
467
|
-
};
|
|
468
|
-
const mapAndSort = (rows) => {
|
|
469
|
-
const betterAuthRows = rows.map(
|
|
470
|
-
(r) => mapRowToBetterAuth(r)
|
|
471
|
-
);
|
|
472
|
-
return applySort(betterAuthRows);
|
|
473
|
-
};
|
|
474
|
-
if (first.error) {
|
|
475
|
-
if (isMissingColumnError(first.error)) {
|
|
476
|
-
const retry = await run(identityMapper);
|
|
477
|
-
if (retry.error) {
|
|
478
|
-
throw new Error(
|
|
479
|
-
`[AthenaAdapter] findMany on "${model}" failed: ${retry.error}`
|
|
480
|
-
);
|
|
481
|
-
}
|
|
482
|
-
return mapAndSort(pickRows(retry.result));
|
|
483
|
-
}
|
|
484
|
-
throw new Error(
|
|
485
|
-
`[AthenaAdapter] findMany on "${model}" failed: ${first.error}`
|
|
486
|
-
);
|
|
487
|
-
}
|
|
488
|
-
return mapAndSort(pickRows(first.result));
|
|
489
|
-
},
|
|
490
|
-
// ------------------------------------------------------------------
|
|
491
|
-
// COUNT
|
|
492
|
-
// ------------------------------------------------------------------
|
|
493
|
-
count: async ({
|
|
494
|
-
model,
|
|
495
|
-
where
|
|
496
|
-
}) => {
|
|
497
|
-
const db = ensureDbClient();
|
|
498
|
-
const snakeMapper = (col) => hasUppercase(col) ? toSnakeCase(col) : col;
|
|
499
|
-
const identityMapper = (col) => col;
|
|
500
|
-
const run = async (columnMapper) => {
|
|
501
|
-
let builder = db.from(model).select();
|
|
502
|
-
if (where) {
|
|
503
|
-
for (const clause of where) {
|
|
504
|
-
builder = applyWhere(
|
|
505
|
-
builder,
|
|
506
|
-
clause.field,
|
|
507
|
-
clause.operator,
|
|
508
|
-
clause.value,
|
|
509
|
-
columnMapper
|
|
510
|
-
);
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
const { data: result, error } = await builder;
|
|
514
|
-
return { result, error };
|
|
515
|
-
};
|
|
516
|
-
const first = await run(snakeMapper);
|
|
517
|
-
if (first.error) {
|
|
518
|
-
if (isMissingColumnError(first.error)) {
|
|
519
|
-
const retry = await run(identityMapper);
|
|
520
|
-
if (retry.error) {
|
|
521
|
-
throw new Error(
|
|
522
|
-
`[AthenaAdapter] count on "${model}" failed: ${retry.error}`
|
|
523
|
-
);
|
|
524
|
-
}
|
|
525
|
-
return Array.isArray(retry.result) ? retry.result.length : 0;
|
|
526
|
-
}
|
|
527
|
-
throw new Error(
|
|
528
|
-
`[AthenaAdapter] count on "${model}" failed: ${first.error}`
|
|
529
|
-
);
|
|
530
|
-
}
|
|
531
|
-
return Array.isArray(first.result) ? first.result.length : 0;
|
|
532
|
-
}
|
|
696
|
+
create: createMethod(deps),
|
|
697
|
+
update: updateMethod(deps),
|
|
698
|
+
updateMany: updateManyMethod(deps),
|
|
699
|
+
delete: deleteMethod(deps),
|
|
700
|
+
deleteMany: deleteManyMethod(deps),
|
|
701
|
+
findOne: findOneMethod(deps),
|
|
702
|
+
findMany: findManyMethod(deps),
|
|
703
|
+
count: countMethod(deps)
|
|
533
704
|
};
|
|
534
705
|
}
|
|
535
706
|
});
|