@ragable/sdk 0.4.2 → 0.5.1
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.d.mts +165 -23
- package/dist/index.d.ts +165 -23
- package/dist/index.js +478 -38
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +469 -35
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -9,6 +9,7 @@ function bindFetch(custom) {
|
|
|
9
9
|
return f.call(globalThis, input, init);
|
|
10
10
|
};
|
|
11
11
|
}
|
|
12
|
+
var DEFAULT_RAGABLE_API_BASE = "https://ragable-341305259977.asia-southeast1.run.app/api";
|
|
12
13
|
var RagableError = class extends Error {
|
|
13
14
|
constructor(message, status, body) {
|
|
14
15
|
super(message);
|
|
@@ -40,7 +41,7 @@ var RagableRequestClient = class {
|
|
|
40
41
|
__publicField(this, "fetchImpl");
|
|
41
42
|
__publicField(this, "defaultHeaders");
|
|
42
43
|
this.apiKey = options.apiKey;
|
|
43
|
-
this.baseUrl = options.baseUrl ??
|
|
44
|
+
this.baseUrl = options.baseUrl ?? DEFAULT_RAGABLE_API_BASE;
|
|
44
45
|
this.fetchImpl = bindFetch(options.fetch);
|
|
45
46
|
this.defaultHeaders = options.headers;
|
|
46
47
|
}
|
|
@@ -358,6 +359,18 @@ function quoteIdent(name) {
|
|
|
358
359
|
assertIdent(name, "column");
|
|
359
360
|
return `"${name}"`;
|
|
360
361
|
}
|
|
362
|
+
function parseConflictColumns(onConflict) {
|
|
363
|
+
const parts = onConflict.split(",").map((s) => s.trim()).filter(Boolean);
|
|
364
|
+
if (parts.length === 0) {
|
|
365
|
+
throw new RagableError(
|
|
366
|
+
"upsert requires onConflict with at least one column (e.g. 'id' or 'org_id,user_id')",
|
|
367
|
+
400,
|
|
368
|
+
null
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
for (const p of parts) assertIdent(p, "onConflict");
|
|
372
|
+
return parts;
|
|
373
|
+
}
|
|
361
374
|
var OP_SQL = {
|
|
362
375
|
eq: "=",
|
|
363
376
|
neq: "<>",
|
|
@@ -440,7 +453,6 @@ var PostgrestSelectBuilder = class {
|
|
|
440
453
|
this._order = { column, ascending: options?.ascending !== false };
|
|
441
454
|
return this;
|
|
442
455
|
}
|
|
443
|
-
/** @param includeUserLimit when false, omit `.limit()` (for `.single()` / `.maybeSingle()`). */
|
|
444
456
|
buildSelectCore(params, includeUserLimit) {
|
|
445
457
|
const tbl = quoteIdent(this.table);
|
|
446
458
|
const { clause } = buildWhere(this.filters, params);
|
|
@@ -480,12 +492,7 @@ var PostgrestSelectBuilder = class {
|
|
|
480
492
|
params,
|
|
481
493
|
readOnly: true
|
|
482
494
|
});
|
|
483
|
-
if (res.rows.length === 0) {
|
|
484
|
-
throw new RagableError("JSON object requested, multiple (or no) rows returned", 406, {
|
|
485
|
-
code: "PGRST116"
|
|
486
|
-
});
|
|
487
|
-
}
|
|
488
|
-
if (res.rows.length > 1) {
|
|
495
|
+
if (res.rows.length === 0 || res.rows.length > 1) {
|
|
489
496
|
throw new RagableError("JSON object requested, multiple (or no) rows returned", 406, {
|
|
490
497
|
code: "PGRST116"
|
|
491
498
|
});
|
|
@@ -513,23 +520,70 @@ var PostgrestSelectBuilder = class {
|
|
|
513
520
|
});
|
|
514
521
|
}
|
|
515
522
|
};
|
|
516
|
-
var
|
|
523
|
+
var PostgrestInsertRootBuilder = class {
|
|
517
524
|
constructor(run, databaseInstanceId, table, rows) {
|
|
518
525
|
this.run = run;
|
|
519
526
|
this.databaseInstanceId = databaseInstanceId;
|
|
520
527
|
this.table = table;
|
|
521
528
|
this.rows = rows;
|
|
522
|
-
__publicField(this, "returning", "*");
|
|
523
529
|
assertIdent(table, "table");
|
|
524
530
|
}
|
|
531
|
+
/**
|
|
532
|
+
* Return inserted rows (Supabase: chain `.select()` to get data).
|
|
533
|
+
* @see https://supabase.com/docs/reference/javascript/insert
|
|
534
|
+
*/
|
|
525
535
|
select(columns = "*") {
|
|
526
|
-
|
|
527
|
-
|
|
536
|
+
return new PostgrestInsertReturningBuilder(
|
|
537
|
+
this.run,
|
|
538
|
+
this.databaseInstanceId,
|
|
539
|
+
this.table,
|
|
540
|
+
this.rows,
|
|
541
|
+
columns
|
|
542
|
+
);
|
|
528
543
|
}
|
|
529
544
|
then(onfulfilled, onrejected) {
|
|
530
|
-
return this.
|
|
545
|
+
return this.executeNoReturn().then(onfulfilled, onrejected);
|
|
531
546
|
}
|
|
532
|
-
async
|
|
547
|
+
async executeNoReturn() {
|
|
548
|
+
return asPostgrestResponse(async () => {
|
|
549
|
+
if (this.rows.length === 0) return null;
|
|
550
|
+
const keys = Object.keys(this.rows[0]);
|
|
551
|
+
for (const k of keys) assertIdent(k, "column");
|
|
552
|
+
const tbl = quoteIdent(this.table);
|
|
553
|
+
const params = [];
|
|
554
|
+
const valueGroups = [];
|
|
555
|
+
for (const row of this.rows) {
|
|
556
|
+
const placeholders = [];
|
|
557
|
+
for (const k of keys) {
|
|
558
|
+
params.push(row[k]);
|
|
559
|
+
placeholders.push(`$${params.length}`);
|
|
560
|
+
}
|
|
561
|
+
valueGroups.push(`(${placeholders.join(", ")})`);
|
|
562
|
+
}
|
|
563
|
+
const cols = keys.map(quoteIdent).join(", ");
|
|
564
|
+
const sql = `INSERT INTO ${tbl} (${cols}) VALUES ${valueGroups.join(", ")}`;
|
|
565
|
+
await this.run({
|
|
566
|
+
databaseInstanceId: this.databaseInstanceId,
|
|
567
|
+
sql,
|
|
568
|
+
params,
|
|
569
|
+
readOnly: false
|
|
570
|
+
});
|
|
571
|
+
return null;
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
};
|
|
575
|
+
var PostgrestInsertReturningBuilder = class {
|
|
576
|
+
constructor(run, databaseInstanceId, table, rows, returning) {
|
|
577
|
+
this.run = run;
|
|
578
|
+
this.databaseInstanceId = databaseInstanceId;
|
|
579
|
+
this.table = table;
|
|
580
|
+
this.rows = rows;
|
|
581
|
+
this.returning = returning;
|
|
582
|
+
}
|
|
583
|
+
then(onfulfilled, onrejected) {
|
|
584
|
+
return this.executeMany().then(onfulfilled, onrejected);
|
|
585
|
+
}
|
|
586
|
+
async executeMany() {
|
|
533
587
|
return asPostgrestResponse(async () => {
|
|
534
588
|
if (this.rows.length === 0) return [];
|
|
535
589
|
const keys = Object.keys(this.rows[0]);
|
|
@@ -556,29 +610,137 @@ var PostgrestInsertBuilder = class {
|
|
|
556
610
|
return res.rows;
|
|
557
611
|
});
|
|
558
612
|
}
|
|
613
|
+
async single() {
|
|
614
|
+
return asPostgrestResponse(async () => {
|
|
615
|
+
const { data, error } = await this.executeMany();
|
|
616
|
+
if (error) throw error;
|
|
617
|
+
const rows = data ?? [];
|
|
618
|
+
if (rows.length === 0 || rows.length > 1) {
|
|
619
|
+
throw new RagableError("JSON object requested, multiple (or no) rows returned", 406, {
|
|
620
|
+
code: "PGRST116"
|
|
621
|
+
});
|
|
622
|
+
}
|
|
623
|
+
return rows[0];
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
async maybeSingle() {
|
|
627
|
+
return asPostgrestResponse(async () => {
|
|
628
|
+
const { data, error } = await this.executeMany();
|
|
629
|
+
if (error) throw error;
|
|
630
|
+
const rows = data ?? [];
|
|
631
|
+
if (rows.length > 1) {
|
|
632
|
+
throw new RagableError("JSON object requested, multiple (or no) rows returned", 406, {
|
|
633
|
+
code: "PGRST116"
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
return rows[0] ?? null;
|
|
637
|
+
});
|
|
638
|
+
}
|
|
559
639
|
};
|
|
560
|
-
var
|
|
640
|
+
var PostgrestUpdateRootBuilder = class {
|
|
561
641
|
constructor(run, databaseInstanceId, table, patch) {
|
|
562
642
|
this.run = run;
|
|
563
643
|
this.databaseInstanceId = databaseInstanceId;
|
|
564
644
|
this.table = table;
|
|
565
645
|
this.patch = patch;
|
|
566
646
|
__publicField(this, "filters", []);
|
|
567
|
-
__publicField(this, "returning", "*");
|
|
568
647
|
assertIdent(table, "table");
|
|
569
648
|
}
|
|
570
649
|
eq(column, value) {
|
|
571
650
|
this.filters.push({ op: "eq", column, value });
|
|
572
651
|
return this;
|
|
573
652
|
}
|
|
574
|
-
|
|
575
|
-
this.
|
|
653
|
+
neq(column, value) {
|
|
654
|
+
this.filters.push({ op: "neq", column, value });
|
|
576
655
|
return this;
|
|
577
656
|
}
|
|
657
|
+
gt(column, value) {
|
|
658
|
+
this.filters.push({ op: "gt", column, value });
|
|
659
|
+
return this;
|
|
660
|
+
}
|
|
661
|
+
gte(column, value) {
|
|
662
|
+
this.filters.push({ op: "gte", column, value });
|
|
663
|
+
return this;
|
|
664
|
+
}
|
|
665
|
+
lt(column, value) {
|
|
666
|
+
this.filters.push({ op: "lt", column, value });
|
|
667
|
+
return this;
|
|
668
|
+
}
|
|
669
|
+
lte(column, value) {
|
|
670
|
+
this.filters.push({ op: "lte", column, value });
|
|
671
|
+
return this;
|
|
672
|
+
}
|
|
673
|
+
like(column, value) {
|
|
674
|
+
this.filters.push({ op: "like", column, value });
|
|
675
|
+
return this;
|
|
676
|
+
}
|
|
677
|
+
ilike(column, value) {
|
|
678
|
+
this.filters.push({ op: "ilike", column, value });
|
|
679
|
+
return this;
|
|
680
|
+
}
|
|
681
|
+
/**
|
|
682
|
+
* Return updated rows (Supabase: `.update().eq().select()`).
|
|
683
|
+
* @see https://supabase.com/docs/reference/javascript/update
|
|
684
|
+
*/
|
|
685
|
+
select(columns = "*") {
|
|
686
|
+
return new PostgrestUpdateReturningBuilder(
|
|
687
|
+
this.run,
|
|
688
|
+
this.databaseInstanceId,
|
|
689
|
+
this.table,
|
|
690
|
+
this.patch,
|
|
691
|
+
this.filters,
|
|
692
|
+
columns
|
|
693
|
+
);
|
|
694
|
+
}
|
|
695
|
+
then(onfulfilled, onrejected) {
|
|
696
|
+
return this.executeNoReturn().then(onfulfilled, onrejected);
|
|
697
|
+
}
|
|
698
|
+
async executeNoReturn() {
|
|
699
|
+
return asPostgrestResponse(async () => {
|
|
700
|
+
const keys = Object.keys(this.patch);
|
|
701
|
+
if (keys.length === 0) {
|
|
702
|
+
throw new RagableError("Empty update payload", 400, null);
|
|
703
|
+
}
|
|
704
|
+
for (const k of keys) assertIdent(k, "column");
|
|
705
|
+
if (this.filters.length === 0) {
|
|
706
|
+
throw new RagableError(
|
|
707
|
+
"UPDATE requires a filter (e.g. .eq('id', value)) \u2014 refusing unscoped update",
|
|
708
|
+
400,
|
|
709
|
+
null
|
|
710
|
+
);
|
|
711
|
+
}
|
|
712
|
+
const params = [];
|
|
713
|
+
const sets = [];
|
|
714
|
+
for (const k of keys) {
|
|
715
|
+
params.push(this.patch[k]);
|
|
716
|
+
sets.push(`${quoteIdent(k)} = $${params.length}`);
|
|
717
|
+
}
|
|
718
|
+
const { clause } = buildWhere(this.filters, params);
|
|
719
|
+
const tbl = quoteIdent(this.table);
|
|
720
|
+
const sql = `UPDATE ${tbl} SET ${sets.join(", ")}${clause}`;
|
|
721
|
+
await this.run({
|
|
722
|
+
databaseInstanceId: this.databaseInstanceId,
|
|
723
|
+
sql,
|
|
724
|
+
params,
|
|
725
|
+
readOnly: false
|
|
726
|
+
});
|
|
727
|
+
return null;
|
|
728
|
+
});
|
|
729
|
+
}
|
|
730
|
+
};
|
|
731
|
+
var PostgrestUpdateReturningBuilder = class {
|
|
732
|
+
constructor(run, databaseInstanceId, table, patch, filters, returning) {
|
|
733
|
+
this.run = run;
|
|
734
|
+
this.databaseInstanceId = databaseInstanceId;
|
|
735
|
+
this.table = table;
|
|
736
|
+
this.patch = patch;
|
|
737
|
+
this.filters = filters;
|
|
738
|
+
this.returning = returning;
|
|
739
|
+
}
|
|
578
740
|
then(onfulfilled, onrejected) {
|
|
579
|
-
return this.
|
|
741
|
+
return this.executeMany().then(onfulfilled, onrejected);
|
|
580
742
|
}
|
|
581
|
-
async
|
|
743
|
+
async executeMany() {
|
|
582
744
|
return asPostgrestResponse(async () => {
|
|
583
745
|
const keys = Object.keys(this.patch);
|
|
584
746
|
if (keys.length === 0) {
|
|
@@ -610,28 +772,124 @@ var PostgrestUpdateBuilder = class {
|
|
|
610
772
|
return res.rows;
|
|
611
773
|
});
|
|
612
774
|
}
|
|
775
|
+
async single() {
|
|
776
|
+
return asPostgrestResponse(async () => {
|
|
777
|
+
const { data, error } = await this.executeMany();
|
|
778
|
+
if (error) throw error;
|
|
779
|
+
const rows = data ?? [];
|
|
780
|
+
if (rows.length === 0 || rows.length > 1) {
|
|
781
|
+
throw new RagableError("JSON object requested, multiple (or no) rows returned", 406, {
|
|
782
|
+
code: "PGRST116"
|
|
783
|
+
});
|
|
784
|
+
}
|
|
785
|
+
return rows[0];
|
|
786
|
+
});
|
|
787
|
+
}
|
|
788
|
+
async maybeSingle() {
|
|
789
|
+
return asPostgrestResponse(async () => {
|
|
790
|
+
const { data, error } = await this.executeMany();
|
|
791
|
+
if (error) throw error;
|
|
792
|
+
const rows = data ?? [];
|
|
793
|
+
if (rows.length > 1) {
|
|
794
|
+
throw new RagableError("JSON object requested, multiple (or no) rows returned", 406, {
|
|
795
|
+
code: "PGRST116"
|
|
796
|
+
});
|
|
797
|
+
}
|
|
798
|
+
return rows[0] ?? null;
|
|
799
|
+
});
|
|
800
|
+
}
|
|
613
801
|
};
|
|
614
|
-
var
|
|
802
|
+
var PostgrestDeleteRootBuilder = class {
|
|
615
803
|
constructor(run, databaseInstanceId, table) {
|
|
616
804
|
this.run = run;
|
|
617
805
|
this.databaseInstanceId = databaseInstanceId;
|
|
618
806
|
this.table = table;
|
|
619
807
|
__publicField(this, "filters", []);
|
|
620
|
-
__publicField(this, "returning", "*");
|
|
621
808
|
assertIdent(table, "table");
|
|
622
809
|
}
|
|
623
810
|
eq(column, value) {
|
|
624
811
|
this.filters.push({ op: "eq", column, value });
|
|
625
812
|
return this;
|
|
626
813
|
}
|
|
627
|
-
|
|
628
|
-
this.
|
|
814
|
+
neq(column, value) {
|
|
815
|
+
this.filters.push({ op: "neq", column, value });
|
|
816
|
+
return this;
|
|
817
|
+
}
|
|
818
|
+
gt(column, value) {
|
|
819
|
+
this.filters.push({ op: "gt", column, value });
|
|
820
|
+
return this;
|
|
821
|
+
}
|
|
822
|
+
gte(column, value) {
|
|
823
|
+
this.filters.push({ op: "gte", column, value });
|
|
629
824
|
return this;
|
|
630
825
|
}
|
|
826
|
+
lt(column, value) {
|
|
827
|
+
this.filters.push({ op: "lt", column, value });
|
|
828
|
+
return this;
|
|
829
|
+
}
|
|
830
|
+
lte(column, value) {
|
|
831
|
+
this.filters.push({ op: "lte", column, value });
|
|
832
|
+
return this;
|
|
833
|
+
}
|
|
834
|
+
like(column, value) {
|
|
835
|
+
this.filters.push({ op: "like", column, value });
|
|
836
|
+
return this;
|
|
837
|
+
}
|
|
838
|
+
ilike(column, value) {
|
|
839
|
+
this.filters.push({ op: "ilike", column, value });
|
|
840
|
+
return this;
|
|
841
|
+
}
|
|
842
|
+
/**
|
|
843
|
+
* Return deleted rows (Supabase: `.delete().eq().select()`).
|
|
844
|
+
* @see https://supabase.com/docs/reference/javascript/delete
|
|
845
|
+
*/
|
|
846
|
+
select(columns = "*") {
|
|
847
|
+
return new PostgrestDeleteReturningBuilder(
|
|
848
|
+
this.run,
|
|
849
|
+
this.databaseInstanceId,
|
|
850
|
+
this.table,
|
|
851
|
+
this.filters,
|
|
852
|
+
columns
|
|
853
|
+
);
|
|
854
|
+
}
|
|
855
|
+
then(onfulfilled, onrejected) {
|
|
856
|
+
return this.executeNoReturn().then(onfulfilled, onrejected);
|
|
857
|
+
}
|
|
858
|
+
async executeNoReturn() {
|
|
859
|
+
return asPostgrestResponse(async () => {
|
|
860
|
+
if (this.filters.length === 0) {
|
|
861
|
+
throw new RagableError(
|
|
862
|
+
"DELETE requires a filter (e.g. .eq('id', value)) \u2014 refusing unscoped delete",
|
|
863
|
+
400,
|
|
864
|
+
null
|
|
865
|
+
);
|
|
866
|
+
}
|
|
867
|
+
const params = [];
|
|
868
|
+
const { clause } = buildWhere(this.filters, params);
|
|
869
|
+
const tbl = quoteIdent(this.table);
|
|
870
|
+
const sql = `DELETE FROM ${tbl}${clause}`;
|
|
871
|
+
await this.run({
|
|
872
|
+
databaseInstanceId: this.databaseInstanceId,
|
|
873
|
+
sql,
|
|
874
|
+
params,
|
|
875
|
+
readOnly: false
|
|
876
|
+
});
|
|
877
|
+
return null;
|
|
878
|
+
});
|
|
879
|
+
}
|
|
880
|
+
};
|
|
881
|
+
var PostgrestDeleteReturningBuilder = class {
|
|
882
|
+
constructor(run, databaseInstanceId, table, filters, returning) {
|
|
883
|
+
this.run = run;
|
|
884
|
+
this.databaseInstanceId = databaseInstanceId;
|
|
885
|
+
this.table = table;
|
|
886
|
+
this.filters = filters;
|
|
887
|
+
this.returning = returning;
|
|
888
|
+
}
|
|
631
889
|
then(onfulfilled, onrejected) {
|
|
632
|
-
return this.
|
|
890
|
+
return this.executeMany().then(onfulfilled, onrejected);
|
|
633
891
|
}
|
|
634
|
-
async
|
|
892
|
+
async executeMany() {
|
|
635
893
|
return asPostgrestResponse(async () => {
|
|
636
894
|
if (this.filters.length === 0) {
|
|
637
895
|
throw new RagableError(
|
|
@@ -653,6 +911,145 @@ var PostgrestDeleteBuilder = class {
|
|
|
653
911
|
return res.rows;
|
|
654
912
|
});
|
|
655
913
|
}
|
|
914
|
+
async single() {
|
|
915
|
+
return asPostgrestResponse(async () => {
|
|
916
|
+
const { data, error } = await this.executeMany();
|
|
917
|
+
if (error) throw error;
|
|
918
|
+
const rows = data ?? [];
|
|
919
|
+
if (rows.length === 0 || rows.length > 1) {
|
|
920
|
+
throw new RagableError("JSON object requested, multiple (or no) rows returned", 406, {
|
|
921
|
+
code: "PGRST116"
|
|
922
|
+
});
|
|
923
|
+
}
|
|
924
|
+
return rows[0];
|
|
925
|
+
});
|
|
926
|
+
}
|
|
927
|
+
async maybeSingle() {
|
|
928
|
+
return asPostgrestResponse(async () => {
|
|
929
|
+
const { data, error } = await this.executeMany();
|
|
930
|
+
if (error) throw error;
|
|
931
|
+
const rows = data ?? [];
|
|
932
|
+
if (rows.length > 1) {
|
|
933
|
+
throw new RagableError("JSON object requested, multiple (or no) rows returned", 406, {
|
|
934
|
+
code: "PGRST116"
|
|
935
|
+
});
|
|
936
|
+
}
|
|
937
|
+
return rows[0] ?? null;
|
|
938
|
+
});
|
|
939
|
+
}
|
|
940
|
+
};
|
|
941
|
+
var PostgrestUpsertRootBuilder = class {
|
|
942
|
+
constructor(run, databaseInstanceId, table, rows, onConflict, ignoreDuplicates) {
|
|
943
|
+
this.run = run;
|
|
944
|
+
this.databaseInstanceId = databaseInstanceId;
|
|
945
|
+
this.table = table;
|
|
946
|
+
this.rows = rows;
|
|
947
|
+
this.ignoreDuplicates = ignoreDuplicates;
|
|
948
|
+
__publicField(this, "conflictCols");
|
|
949
|
+
assertIdent(table, "table");
|
|
950
|
+
this.conflictCols = parseConflictColumns(onConflict);
|
|
951
|
+
}
|
|
952
|
+
/**
|
|
953
|
+
* Return upserted rows (Supabase: `.upsert().select()`).
|
|
954
|
+
* @see https://supabase.com/docs/reference/javascript/upsert
|
|
955
|
+
*/
|
|
956
|
+
select(columns = "*") {
|
|
957
|
+
return new PostgrestUpsertReturningBuilder(this, columns);
|
|
958
|
+
}
|
|
959
|
+
then(onfulfilled, onrejected) {
|
|
960
|
+
return this.executeNoReturn().then(onfulfilled, onrejected);
|
|
961
|
+
}
|
|
962
|
+
async executeNoReturn() {
|
|
963
|
+
return asPostgrestResponse(async () => {
|
|
964
|
+
await this.runUpsert(null);
|
|
965
|
+
return null;
|
|
966
|
+
});
|
|
967
|
+
}
|
|
968
|
+
async runUpsert(returning) {
|
|
969
|
+
if (this.rows.length === 0) {
|
|
970
|
+
return { command: "INSERT", rowCount: 0, truncated: false, rows: [] };
|
|
971
|
+
}
|
|
972
|
+
const keys = Object.keys(this.rows[0]);
|
|
973
|
+
for (const k of keys) assertIdent(k, "column");
|
|
974
|
+
const tbl = quoteIdent(this.table);
|
|
975
|
+
const conflictQuoted = this.conflictCols.map(quoteIdent).join(", ");
|
|
976
|
+
const params = [];
|
|
977
|
+
const valueGroups = [];
|
|
978
|
+
for (const row of this.rows) {
|
|
979
|
+
const placeholders = [];
|
|
980
|
+
for (const k of keys) {
|
|
981
|
+
params.push(row[k]);
|
|
982
|
+
placeholders.push(`$${params.length}`);
|
|
983
|
+
}
|
|
984
|
+
valueGroups.push(`(${placeholders.join(", ")})`);
|
|
985
|
+
}
|
|
986
|
+
const cols = keys.map(quoteIdent).join(", ");
|
|
987
|
+
let sql = `INSERT INTO ${tbl} (${cols}) VALUES ${valueGroups.join(", ")} ON CONFLICT (${conflictQuoted})`;
|
|
988
|
+
if (this.ignoreDuplicates) {
|
|
989
|
+
sql += " DO NOTHING";
|
|
990
|
+
} else {
|
|
991
|
+
const setParts = keys.filter((k) => !this.conflictCols.includes(k)).map((k) => `${quoteIdent(k)} = EXCLUDED.${quoteIdent(k)}`);
|
|
992
|
+
if (setParts.length === 0) {
|
|
993
|
+
sql += " DO NOTHING";
|
|
994
|
+
} else {
|
|
995
|
+
sql += ` DO UPDATE SET ${setParts.join(", ")}`;
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
if (returning) {
|
|
999
|
+
sql += ` RETURNING ${returning}`;
|
|
1000
|
+
}
|
|
1001
|
+
return this.run({
|
|
1002
|
+
databaseInstanceId: this.databaseInstanceId,
|
|
1003
|
+
sql,
|
|
1004
|
+
params,
|
|
1005
|
+
readOnly: false
|
|
1006
|
+
});
|
|
1007
|
+
}
|
|
1008
|
+
/** Used by returning builder */
|
|
1009
|
+
async runWithReturning(returning) {
|
|
1010
|
+
return this.runUpsert(returning);
|
|
1011
|
+
}
|
|
1012
|
+
};
|
|
1013
|
+
var PostgrestUpsertReturningBuilder = class {
|
|
1014
|
+
constructor(root, returning) {
|
|
1015
|
+
this.root = root;
|
|
1016
|
+
this.returning = returning;
|
|
1017
|
+
}
|
|
1018
|
+
then(onfulfilled, onrejected) {
|
|
1019
|
+
return this.executeMany().then(onfulfilled, onrejected);
|
|
1020
|
+
}
|
|
1021
|
+
async executeMany() {
|
|
1022
|
+
return asPostgrestResponse(async () => {
|
|
1023
|
+
const res = await this.root.runWithReturning(this.returning);
|
|
1024
|
+
return res.rows;
|
|
1025
|
+
});
|
|
1026
|
+
}
|
|
1027
|
+
async single() {
|
|
1028
|
+
return asPostgrestResponse(async () => {
|
|
1029
|
+
const { data, error } = await this.executeMany();
|
|
1030
|
+
if (error) throw error;
|
|
1031
|
+
const rows = data ?? [];
|
|
1032
|
+
if (rows.length === 0 || rows.length > 1) {
|
|
1033
|
+
throw new RagableError("JSON object requested, multiple (or no) rows returned", 406, {
|
|
1034
|
+
code: "PGRST116"
|
|
1035
|
+
});
|
|
1036
|
+
}
|
|
1037
|
+
return rows[0];
|
|
1038
|
+
});
|
|
1039
|
+
}
|
|
1040
|
+
async maybeSingle() {
|
|
1041
|
+
return asPostgrestResponse(async () => {
|
|
1042
|
+
const { data, error } = await this.executeMany();
|
|
1043
|
+
if (error) throw error;
|
|
1044
|
+
const rows = data ?? [];
|
|
1045
|
+
if (rows.length > 1) {
|
|
1046
|
+
throw new RagableError("JSON object requested, multiple (or no) rows returned", 406, {
|
|
1047
|
+
code: "PGRST116"
|
|
1048
|
+
});
|
|
1049
|
+
}
|
|
1050
|
+
return rows[0] ?? null;
|
|
1051
|
+
});
|
|
1052
|
+
}
|
|
656
1053
|
};
|
|
657
1054
|
var PostgrestTableApi = class {
|
|
658
1055
|
constructor(run, databaseInstanceId, table) {
|
|
@@ -670,7 +1067,7 @@ var PostgrestTableApi = class {
|
|
|
670
1067
|
}
|
|
671
1068
|
insert(values) {
|
|
672
1069
|
const rows = Array.isArray(values) ? values : [values];
|
|
673
|
-
return new
|
|
1070
|
+
return new PostgrestInsertRootBuilder(
|
|
674
1071
|
this.run,
|
|
675
1072
|
this.databaseInstanceId,
|
|
676
1073
|
this.table,
|
|
@@ -678,7 +1075,7 @@ var PostgrestTableApi = class {
|
|
|
678
1075
|
);
|
|
679
1076
|
}
|
|
680
1077
|
update(patch) {
|
|
681
|
-
return new
|
|
1078
|
+
return new PostgrestUpdateRootBuilder(
|
|
682
1079
|
this.run,
|
|
683
1080
|
this.databaseInstanceId,
|
|
684
1081
|
this.table,
|
|
@@ -686,17 +1083,33 @@ var PostgrestTableApi = class {
|
|
|
686
1083
|
);
|
|
687
1084
|
}
|
|
688
1085
|
delete() {
|
|
689
|
-
return new
|
|
1086
|
+
return new PostgrestDeleteRootBuilder(
|
|
690
1087
|
this.run,
|
|
691
1088
|
this.databaseInstanceId,
|
|
692
1089
|
this.table
|
|
693
1090
|
);
|
|
694
1091
|
}
|
|
1092
|
+
/**
|
|
1093
|
+
* `INSERT ... ON CONFLICT ... DO UPDATE` (or `DO NOTHING` with `ignoreDuplicates`).
|
|
1094
|
+
* @see https://supabase.com/docs/reference/javascript/upsert
|
|
1095
|
+
*/
|
|
1096
|
+
upsert(values, options) {
|
|
1097
|
+
const rows = Array.isArray(values) ? values : [values];
|
|
1098
|
+
return new PostgrestUpsertRootBuilder(
|
|
1099
|
+
this.run,
|
|
1100
|
+
this.databaseInstanceId,
|
|
1101
|
+
this.table,
|
|
1102
|
+
rows,
|
|
1103
|
+
options.onConflict,
|
|
1104
|
+
options.ignoreDuplicates === true
|
|
1105
|
+
);
|
|
1106
|
+
}
|
|
695
1107
|
};
|
|
696
1108
|
|
|
697
1109
|
// src/browser.ts
|
|
698
1110
|
function normalizeBrowserApiBase(baseUrl) {
|
|
699
|
-
|
|
1111
|
+
const trimmed = (baseUrl ?? DEFAULT_RAGABLE_API_BASE).trim().replace(/\/+$/, "");
|
|
1112
|
+
return trimmed.endsWith("/api") ? trimmed : `${trimmed}/api`;
|
|
700
1113
|
}
|
|
701
1114
|
function requireAuthGroupId(options) {
|
|
702
1115
|
const id = options.authGroupId?.trim();
|
|
@@ -720,6 +1133,20 @@ async function requireAccessToken(options) {
|
|
|
720
1133
|
}
|
|
721
1134
|
return token.trim();
|
|
722
1135
|
}
|
|
1136
|
+
async function resolveDatabaseAuthBearer(options) {
|
|
1137
|
+
const mode = options.dataAuth ?? "user";
|
|
1138
|
+
if (mode === "user") {
|
|
1139
|
+
return requireAccessToken(options);
|
|
1140
|
+
}
|
|
1141
|
+
const fromGetter = options.getDataStaticKey ? await options.getDataStaticKey() : null;
|
|
1142
|
+
const key = (fromGetter?.trim() || options.dataStaticKey?.trim()) ?? "";
|
|
1143
|
+
if (!key) {
|
|
1144
|
+
throw new Error(
|
|
1145
|
+
mode === "publicAnon" ? "dataAuth publicAnon requires getDataStaticKey or dataStaticKey (rotate key in dashboard)" : "dataAuth admin requires getDataStaticKey or dataStaticKey (server-side only; rotate in dashboard)"
|
|
1146
|
+
);
|
|
1147
|
+
}
|
|
1148
|
+
return key;
|
|
1149
|
+
}
|
|
723
1150
|
async function parseJsonOrThrow(response) {
|
|
724
1151
|
const payload = await parseMaybeJsonBody(response);
|
|
725
1152
|
if (!response.ok) {
|
|
@@ -889,7 +1316,7 @@ var RagableBrowserDatabaseClient = class {
|
|
|
889
1316
|
}
|
|
890
1317
|
async query(params) {
|
|
891
1318
|
const gid = requireAuthGroupId(this.options);
|
|
892
|
-
const token = await
|
|
1319
|
+
const token = await resolveDatabaseAuthBearer(this.options);
|
|
893
1320
|
const databaseInstanceId = params.databaseInstanceId?.trim() || this.options.databaseInstanceId?.trim();
|
|
894
1321
|
if (!databaseInstanceId) {
|
|
895
1322
|
throw new Error(
|
|
@@ -899,6 +1326,7 @@ var RagableBrowserDatabaseClient = class {
|
|
|
899
1326
|
const headers = this.baseHeaders();
|
|
900
1327
|
headers.set("Authorization", `Bearer ${token}`);
|
|
901
1328
|
headers.set("Content-Type", "application/json");
|
|
1329
|
+
const readOnly = (this.options.dataAuth ?? "user") === "publicAnon" ? true : params.readOnly !== false;
|
|
902
1330
|
const response = await this.fetchImpl(
|
|
903
1331
|
this.toUrl(`/auth-groups/${gid}/data/query`),
|
|
904
1332
|
{
|
|
@@ -908,7 +1336,7 @@ var RagableBrowserDatabaseClient = class {
|
|
|
908
1336
|
databaseInstanceId,
|
|
909
1337
|
sql: params.sql,
|
|
910
1338
|
...params.params !== void 0 ? { params: params.params } : {},
|
|
911
|
-
|
|
1339
|
+
readOnly,
|
|
912
1340
|
...params.timeoutMs !== void 0 ? { timeoutMs: params.timeoutMs } : {},
|
|
913
1341
|
...params.rowLimit !== void 0 ? { rowLimit: params.rowLimit } : {}
|
|
914
1342
|
})
|
|
@@ -1083,11 +1511,17 @@ function createRagableServerClient(options) {
|
|
|
1083
1511
|
}
|
|
1084
1512
|
export {
|
|
1085
1513
|
AgentsClient,
|
|
1086
|
-
|
|
1087
|
-
|
|
1514
|
+
DEFAULT_RAGABLE_API_BASE,
|
|
1515
|
+
PostgrestDeleteReturningBuilder,
|
|
1516
|
+
PostgrestDeleteRootBuilder,
|
|
1517
|
+
PostgrestInsertReturningBuilder,
|
|
1518
|
+
PostgrestInsertRootBuilder,
|
|
1088
1519
|
PostgrestSelectBuilder,
|
|
1089
1520
|
PostgrestTableApi,
|
|
1090
|
-
|
|
1521
|
+
PostgrestUpdateReturningBuilder,
|
|
1522
|
+
PostgrestUpdateRootBuilder,
|
|
1523
|
+
PostgrestUpsertReturningBuilder,
|
|
1524
|
+
PostgrestUpsertRootBuilder,
|
|
1091
1525
|
Ragable,
|
|
1092
1526
|
RagableBrowser,
|
|
1093
1527
|
RagableBrowserAgentsClient,
|