@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/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: "http://localhost:3000",
46
- apiKey: "",
47
- client: "better-auth"
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/index.ts
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
- function applyWhere(builder, field, operator, value, columnMapper = (col) => hasUppercase(col) ? toSnakeCase(col) : col) {
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, { client });
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
- // CREATE
248
- // ------------------------------------------------------------------
249
- create: async ({
250
- model,
251
- data
252
- }) => {
253
- const db = ensureDbClient();
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
  });