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