@centia-io/sdk 0.0.29 → 0.0.31

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.
@@ -358,8 +358,7 @@ var CodeFlow = class {
358
358
  params.delete("code");
359
359
  params.delete("state");
360
360
  const loc = window.location;
361
- const newUrl = loc.origin + loc.pathname + (params.size > 0 ? "?" + params.toString() : "");
362
- history.pushState(null, "", newUrl);
361
+ loc.origin + loc.pathname + (params.size > 0 ? "?" + params.toString() : "");
363
362
  return Promise.resolve(true);
364
363
  } catch (e) {
365
364
  throw new Error(e.message);
@@ -371,7 +370,7 @@ var CodeFlow = class {
371
370
  const { state, codeVerifier, codeChallenge } = await generatePkceChallenge();
372
371
  getStorage().setItem("state", state);
373
372
  getStorage().setItem("codeVerifier", codeVerifier);
374
- window.location = this.service.getAuthorizationCodeURL(codeChallenge, state);
373
+ window.location.assign(this.service.getAuthorizationCodeURL(codeChallenge, state));
375
374
  }
376
375
  signOut() {
377
376
  this.clear();
@@ -527,7 +526,8 @@ var Ws = class {
527
526
  const connect = () => {
528
527
  let queryString = `?token=` + accessToken;
529
528
  if (this.options?.rel) queryString = queryString + `&rel=` + this.options.rel;
530
- const ws = new this.options.wsClient(this.options.host + `/` + queryString);
529
+ const WSClass = this.options.wsClient;
530
+ const ws = new WSClass(this.options.host + `/` + queryString);
531
531
  ws.onopen = function() {
532
532
  console.log("WebSocket connected!");
533
533
  };
@@ -576,20 +576,62 @@ var Tables = class {
576
576
 
577
577
  //#endregion
578
578
  //#region src/Api.ts
579
- async function dispatch(name, args) {
579
+ function isPlainObject$1(v) {
580
+ return typeof v === "object" && v !== null && !Array.isArray(v);
581
+ }
582
+ function validateParamsForMethod(method, params) {
583
+ if (Array.isArray(params)) {
584
+ const badIndex = params.findIndex((p) => !isPlainObject$1(p));
585
+ if (badIndex !== -1) throw new TypeError(`createApi: Invalid argument at index ${badIndex} for RPC method "${method}". Expected a plain object.`);
586
+ return params;
587
+ }
588
+ if (params === void 0) return {};
589
+ if (!isPlainObject$1(params)) throw new TypeError(`createApi: Invalid argument for RPC method "${method}". Expected a plain object.`);
590
+ return params;
591
+ }
592
+ function extractDataFromResponse(method, res) {
593
+ if (!res || typeof res !== "object") throw new TypeError(`createApi: Invalid RPC response for method "${method}". Expected an object.`);
594
+ if (res.jsonrpc !== "2.0") throw new TypeError(`createApi: Invalid RPC response for method "${method}". Missing or invalid jsonrpc version.`);
595
+ const err = res.error;
596
+ if (err !== void 0) {
597
+ if (!err || typeof err !== "object") throw new TypeError(`createApi: Invalid RPC error for method "${method}". Expected 'error' to be an object.`);
598
+ const code = err.code;
599
+ const message = err.message;
600
+ const data$1 = err.data;
601
+ const codeIsNum = typeof code === "number" && Number.isFinite(code);
602
+ const details = typeof message === "string" && message.length > 0 ? message : "Unknown error";
603
+ const e = /* @__PURE__ */ new Error(`createApi: RPC error for method "${method}"${codeIsNum ? ` (${code})` : ""}: ${details}`);
604
+ e.code = code;
605
+ if (data$1 !== void 0) e.data = data$1;
606
+ e.method = method;
607
+ e.name = "JsonRpcError";
608
+ throw e;
609
+ }
610
+ const result = res.result;
611
+ if (!result || typeof result !== "object") throw new TypeError(`createApi: Invalid RPC response for method "${method}". Missing result object.`);
612
+ const data = result.data;
613
+ if (!Array.isArray(data)) throw new TypeError(`createApi: Invalid RPC response for method "${method}". Expected result.data to be an array.`);
614
+ return data;
615
+ }
616
+ async function dispatch(name, paramsLike) {
617
+ if (typeof name !== "string" || name.length === 0) throw new TypeError("createApi: RPC method name must be a non-empty string.");
618
+ const params = validateParamsForMethod(String(name), paramsLike);
580
619
  const rpc = new Rpc();
581
620
  const request = {
582
621
  jsonrpc: "2.0",
583
622
  method: name,
584
623
  id: 1,
585
- params: args
624
+ params
586
625
  };
587
- return (await rpc.call(request)).result.data;
626
+ const res = await rpc.call(request);
627
+ return extractDataFromResponse(String(name), res);
588
628
  }
589
629
  function createApi() {
590
630
  return new Proxy({}, { get(_target, prop) {
591
631
  if (typeof prop !== "string") return void 0;
592
- return (...args) => dispatch(prop, ...args);
632
+ return (...args) => {
633
+ return dispatch(prop, args.length === 0 ? {} : args.length === 1 ? args[0] : args);
634
+ };
593
635
  } });
594
636
  }
595
637
 
@@ -605,6 +647,764 @@ var SignUp = class {
605
647
  }
606
648
  };
607
649
 
650
+ //#endregion
651
+ //#region src/SqlBuilder.ts
652
+ function findTable(schema, name) {
653
+ const tbl = schema.tables.find((t) => t.name === name);
654
+ if (!tbl) throw new Error(`Table not found in schema: ${name}`);
655
+ return tbl;
656
+ }
657
+ function findColumn(table, name) {
658
+ const col = table.columns.find((c) => c.name === name);
659
+ if (!col) throw new Error(`Column not found in table ${table.name}: ${name}`);
660
+ return col;
661
+ }
662
+ function getPrimaryKeyColumns(table) {
663
+ const pk = (table.constraints || []).find((c) => c.constraint === "primary" && Array.isArray(c.columns) && c.columns.length > 0);
664
+ return pk ? pk.columns.map(String) : [];
665
+ }
666
+ function typeNameToHint(typname, isArray) {
667
+ if (!typname) return void 0;
668
+ const base = typname;
669
+ return isArray ? base + "[]" : base;
670
+ }
671
+ function addTypeHintForParam(typeHints, paramName, col, value) {
672
+ let isArr = col._is_array;
673
+ if (Array.isArray(value)) if (isArrayShapedGeomTypename(col._typname)) isArr = value.every(Array.isArray);
674
+ else isArr = true;
675
+ const hint = typeNameToHint(col._typname, isArr);
676
+ if (hint) typeHints[paramName] = hint;
677
+ }
678
+ function expectedScalarKind(typname) {
679
+ const t = typname.toLowerCase();
680
+ if (t === "int2" || t === "int4" || t === "int8" || t === "float4" || t === "float8") return "number";
681
+ if (t === "numeric" || t === "decimal") return "string";
682
+ if (t === "varchar" || t === "text" || t === "bpchar" || t === "char" || t === "date" || t === "time" || t === "timetz" || t === "timestamp" || t === "timestamptz") return "string";
683
+ if (t === "bool") return "boolean";
684
+ if (t === "json" || t === "jsonb") return "json";
685
+ if (t === "int4range" || t === "int8range" || t === "numrange" || t === "tsrange" || t === "tstzrange" || t === "daterange") return "range";
686
+ if (t === "interval") return "interval";
687
+ if (t === "point" || t === "line" || t === "lseg" || t === "box" || t === "path" || t === "polygon" || t === "circle") return "geom";
688
+ return "unknown";
689
+ }
690
+ function isArrayShapedGeomTypename(typname) {
691
+ const t = typname.toLowerCase();
692
+ return t === "path" || t === "polygon";
693
+ }
694
+ function isArrayShapedGeomScalarValue(col, value) {
695
+ if (!Array.isArray(value)) return false;
696
+ if (!isArrayShapedGeomTypename(col._typname)) return false;
697
+ return !value.every(Array.isArray);
698
+ }
699
+ function expectedRangeInnerKind(typname) {
700
+ const t = typname.toLowerCase();
701
+ if (t === "int4range" || t === "int8range") return "number";
702
+ if (t === "numrange" || t === "tsrange" || t === "tstzrange" || t === "daterange") return "string";
703
+ return "unknown";
704
+ }
705
+ function isPlainObject(v) {
706
+ return typeof v === "object" && v !== null && !Array.isArray(v);
707
+ }
708
+ function isFiniteNumber(n) {
709
+ return typeof n === "number" && Number.isFinite(n);
710
+ }
711
+ function isPointLike(v) {
712
+ if (!isPlainObject(v)) return false;
713
+ const x = v.x;
714
+ const y = v.y;
715
+ return isFiniteNumber(x) && isFiniteNumber(y);
716
+ }
717
+ function validateGeometryForColumn(col, value, context) {
718
+ const t = col._typname.toLowerCase();
719
+ if (t === "point") {
720
+ if (!isPointLike(value)) throw new Error(`Invalid value for ${context}. Expected Point { x: number, y: number }`);
721
+ return;
722
+ }
723
+ if (t === "line") {
724
+ if (!isPlainObject(value)) throw new Error(`Invalid value for ${context}. Expected Line { A: number, B: number, C: number }`);
725
+ const A = value.A, B = value.B, C = value.C;
726
+ if (!isFiniteNumber(A) || !isFiniteNumber(B) || !isFiniteNumber(C)) throw new Error(`Invalid Line for ${context}. A, B, C must be finite numbers`);
727
+ return;
728
+ }
729
+ if (t === "lseg" || t === "box") {
730
+ if (!isPlainObject(value)) throw new Error(`Invalid value for ${context}. Expected ${t.toUpperCase()} { start: Point, end: Point }`);
731
+ const start = value.start;
732
+ const end = value.end;
733
+ if (!isPointLike(start) || !isPointLike(end)) throw new Error(`Invalid ${t} for ${context}. 'start' and 'end' must be Point { x, y }`);
734
+ return;
735
+ }
736
+ if (t === "path") {
737
+ if (!Array.isArray(value) || value.length < 1) throw new Error(`Invalid value for ${context}. Expected Path [isClosed: boolean, ...points: Point[]]`);
738
+ const [isClosed, ...points] = value;
739
+ if (typeof isClosed !== "boolean") throw new Error(`Invalid Path for ${context}. First element must be boolean (isClosed)`);
740
+ for (let i = 0; i < points.length; i++) if (!isPointLike(points[i])) throw new Error(`Invalid Path for ${context}. Element at index ${i + 1} must be Point { x, y }`);
741
+ return;
742
+ }
743
+ if (t === "polygon") {
744
+ if (!Array.isArray(value)) throw new Error(`Invalid value for ${context}. Expected Polygon as Point[]`);
745
+ for (let i = 0; i < value.length; i++) if (!isPointLike(value[i])) throw new Error(`Invalid Polygon for ${context}. Element at index ${i} must be Point { x, y }`);
746
+ return;
747
+ }
748
+ if (t === "circle") {
749
+ if (!isPlainObject(value)) throw new Error(`Invalid value for ${context}. Expected Circle { center: Point, radius: number }`);
750
+ const center = value.center;
751
+ const radius = value.radius;
752
+ if (!isPointLike(center) || !isFiniteNumber(radius)) throw new Error(`Invalid Circle for ${context}. 'center' must be Point and 'radius' must be finite number`);
753
+ return;
754
+ }
755
+ }
756
+ function validateRangeForColumn(col, value, context) {
757
+ if (!isPlainObject(value)) throw new Error(`Invalid value for ${context}. Expected a range object for type ${col._typname}`);
758
+ const r = value;
759
+ const hasLower = Object.prototype.hasOwnProperty.call(r, "lower");
760
+ const hasUpper = Object.prototype.hasOwnProperty.call(r, "upper");
761
+ const hasLi = Object.prototype.hasOwnProperty.call(r, "lowerInclusive");
762
+ const hasUi = Object.prototype.hasOwnProperty.call(r, "upperInclusive");
763
+ if (!hasLower || !hasUpper || !hasLi || !hasUi) throw new Error(`Invalid range for ${context}. Required properties: lower, upper, lowerInclusive, upperInclusive`);
764
+ if (typeof r.lowerInclusive !== "boolean" || typeof r.upperInclusive !== "boolean") throw new Error(`Invalid range for ${context}. lowerInclusive and upperInclusive must be boolean`);
765
+ const inner = expectedRangeInnerKind(col._typname);
766
+ if (inner === "number") {
767
+ if (typeof r.lower !== "number" || !Number.isFinite(r.lower)) throw new Error(`Invalid range.lower for ${context}. Expected number for type ${col._typname}`);
768
+ if (typeof r.upper !== "number" || !Number.isFinite(r.upper)) throw new Error(`Invalid range.upper for ${context}. Expected number for type ${col._typname}`);
769
+ } else if (inner === "string") {
770
+ if (typeof r.lower !== "string") throw new Error(`Invalid range.lower for ${context}. Expected string for type ${col._typname}`);
771
+ if (typeof r.upper !== "string") throw new Error(`Invalid range.upper for ${context}. Expected string for type ${col._typname}`);
772
+ }
773
+ }
774
+ function validateIntervalForColumn(col, value, context) {
775
+ if (!isPlainObject(value)) throw new Error(`Invalid value for ${context}. Expected an interval object for type ${col._typname}`);
776
+ const v = value;
777
+ for (const k of [
778
+ "y",
779
+ "m",
780
+ "d",
781
+ "h",
782
+ "i",
783
+ "s"
784
+ ]) {
785
+ if (!Object.prototype.hasOwnProperty.call(v, k)) throw new Error(`Invalid interval for ${context}. Missing property '${k}'`);
786
+ const num = v[k];
787
+ if (typeof num !== "number" || !Number.isFinite(num)) throw new Error(`Invalid interval.${String(k)} for ${context}. Expected finite number`);
788
+ }
789
+ }
790
+ function isValidJsonLike(value) {
791
+ return value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean" || typeof value === "object" && value !== null;
792
+ }
793
+ function validateScalarForColumn(col, value, context) {
794
+ const kind = expectedScalarKind(col._typname);
795
+ if (kind === "unknown") return;
796
+ if (kind === "number") {
797
+ if (typeof value !== "number" || !Number.isFinite(value)) throw new Error(`Invalid value for ${context}. Expected number for type ${col._typname}, got ${typeof value}`);
798
+ return;
799
+ }
800
+ if (kind === "string") {
801
+ if (typeof value !== "string") throw new Error(`Invalid value for ${context}. Expected string for type ${col._typname}, got ${typeof value}`);
802
+ return;
803
+ }
804
+ if (kind === "boolean") {
805
+ if (typeof value !== "boolean") throw new Error(`Invalid value for ${context}. Expected boolean for type ${col._typname}, got ${typeof value}`);
806
+ return;
807
+ }
808
+ if (kind === "json") {
809
+ if (!isValidJsonLike(value)) throw new Error(`Invalid value for ${context}. Expected JSON-compatible value for type ${col._typname}`);
810
+ return;
811
+ }
812
+ if (kind === "range") {
813
+ validateRangeForColumn(col, value, context);
814
+ return;
815
+ }
816
+ if (kind === "interval") {
817
+ validateIntervalForColumn(col, value, context);
818
+ return;
819
+ }
820
+ if (kind === "geom") {
821
+ validateGeometryForColumn(col, value, context);
822
+ return;
823
+ }
824
+ }
825
+ function validateComparisonValue(col, key, value, op) {
826
+ if (value === void 0 || value === null) throw new Error(`Operator ${op} on column ${key} requires a non-null value. Use isnull/notnull for null checks.`);
827
+ if (col._is_array) {
828
+ if (!Array.isArray(value)) throw new Error(`Operator ${op} on array column ${key} requires an array value`);
829
+ for (const [i, v] of value.entries()) validateScalarForColumn(col, v, `column ${key}[${i}]`);
830
+ } else {
831
+ if (Array.isArray(value) && !isArrayShapedGeomScalarValue(col, value)) throw new Error(`Operator ${op} on scalar column ${key} cannot accept an array value`);
832
+ validateScalarForColumn(col, value, `column ${key}`);
833
+ }
834
+ }
835
+ function validateInArrayValues(col, key, values, op) {
836
+ if (!col._is_array) {
837
+ let idx = 0;
838
+ for (const v of values) {
839
+ validateScalarForColumn(col, v, `column ${key} (element ${idx})`);
840
+ idx++;
841
+ }
842
+ }
843
+ }
844
+ function findJoinOn(base, target) {
845
+ const bc = base.constraints || [];
846
+ const tc = target.constraints || [];
847
+ for (const c of bc) if (c.constraint === "foreign" && c.referenced_table === target.name && c.columns?.length && c.referenced_columns?.length && c.columns.length === c.referenced_columns.length) return c.columns.map((col, i) => ({
848
+ left: String(col),
849
+ right: String(c.referenced_columns[i])
850
+ }));
851
+ for (const c of tc) if (c.constraint === "foreign" && c.referenced_table === base.name && c.columns?.length && c.referenced_columns?.length && c.columns.length === c.referenced_columns.length) return c.referenced_columns.map((rcol, i) => ({
852
+ left: String(rcol),
853
+ right: String(c.columns[i])
854
+ }));
855
+ return null;
856
+ }
857
+ var TableQueryImpl = class {
858
+ constructor(schema, tableName) {
859
+ this.schema = schema;
860
+ this.table = findTable(schema, tableName);
861
+ }
862
+ select(cols) {
863
+ const table = this.table;
864
+ const schema = this.schema;
865
+ const selected = cols && cols.length ? cols : ["*"];
866
+ const state = {
867
+ table,
868
+ selected,
869
+ where: {},
870
+ orWhereGroups: [],
871
+ andOps: [],
872
+ orOpGroups: [],
873
+ order: [],
874
+ limit: void 0,
875
+ offset: void 0,
876
+ joins: [],
877
+ joinSelections: []
878
+ };
879
+ return new class {
880
+ constructor() {
881
+ this.s = state;
882
+ this.toSql = () => {
883
+ const params = {};
884
+ const type_hints = {};
885
+ let p = 0;
886
+ const parts = [];
887
+ const selectParts = [];
888
+ if (selected.length === 1 && selected[0] === "*") selectParts.push(`"${table.name}".*`);
889
+ else {
890
+ const sel = selected;
891
+ for (const c of sel) findColumn(table, String(c));
892
+ selectParts.push(sel.map((c) => `"${table.name}"."${c}"`).join(", "));
893
+ }
894
+ for (const js of state.joinSelections) if (js.selected.length === 1 && js.selected[0] === "*") selectParts.push(`"${js.target.name}".*`);
895
+ else {
896
+ const cols$1 = js.selected;
897
+ for (const c of cols$1) findColumn(js.target, String(c));
898
+ selectParts.push(cols$1.map((c) => `"${js.target.name}"."${c}"`).join(", "));
899
+ }
900
+ parts.push(`select ${selectParts.join(", ")} from "${schema.name}"."${table.name}"`);
901
+ for (const j of state.joins) {
902
+ const onExpr = j.on.map((p$1) => `"${table.name}"."${p$1.left}" = "${j.target.name}"."${p$1.right}"`).join(" and ");
903
+ parts.push(`${j.type} join "${schema.name}"."${j.target.name}" on ${onExpr}`);
904
+ }
905
+ const andParts = [];
906
+ for (const key in state.where) {
907
+ const value = state.where[key];
908
+ const col = findColumn(table, key);
909
+ p += 1;
910
+ const paramName = `${table.name}_${key}_${p}`;
911
+ if (value === null) {
912
+ if (!col.is_nullable) throw new Error(`Column ${table.name}.${key} is not nullable; cannot compare to null`);
913
+ andParts.push(`"${table.name}"."${key}" is null`);
914
+ } else if (Array.isArray(value) && !isArrayShapedGeomScalarValue(col, value)) {
915
+ validateInArrayValues(col, key, value, "in");
916
+ andParts.push(`"${table.name}"."${key}" = ANY(:${paramName})`);
917
+ params[paramName] = value;
918
+ addTypeHintForParam(type_hints, paramName, col, value);
919
+ } else {
920
+ validateScalarForColumn(col, value, `column ${key}`);
921
+ andParts.push(`"${table.name}"."${key}" = :${paramName}`);
922
+ params[paramName] = value;
923
+ addTypeHintForParam(type_hints, paramName, col, value);
924
+ }
925
+ }
926
+ for (const pred of state.andOps) {
927
+ const key = String(pred.col);
928
+ const op = String(pred.op);
929
+ const col = findColumn(table, key);
930
+ const qualified = `"${table.name}"."${key}"`;
931
+ if (op === "isnull" || op === "notnull") {
932
+ if (pred.value !== void 0) throw new Error(`Operator ${op} does not take a value for column ${key}`);
933
+ andParts.push(`${qualified} is ${op === "isnull" ? "null" : "not null"}`);
934
+ } else if (op === "in" || op === "notin") {
935
+ const val = pred.value;
936
+ if (!Array.isArray(val)) throw new Error(`Operator ${op} requires an array value for column ${key}`);
937
+ validateInArrayValues(col, key, val, op);
938
+ p += 1;
939
+ const paramName = `${table.name}_${key}_${p}`;
940
+ andParts.push(`${qualified} ${op === "in" ? "= ANY" : "!= ALL"}(:${paramName})`);
941
+ params[paramName] = val;
942
+ addTypeHintForParam(type_hints, paramName, col, val);
943
+ } else if (op === "like" || op === "ilike" || op === "notlike" || op === "notilike") {
944
+ const val = pred.value;
945
+ if (typeof val !== "string") throw new Error(`Operator ${op} requires a string value for column ${key}`);
946
+ p += 1;
947
+ const paramName = `${table.name}_${key}_${p}`;
948
+ const sqlOp = op === "like" ? "like" : op === "ilike" ? "ilike" : op === "notlike" ? "not like" : "not ilike";
949
+ andParts.push(`${qualified} ${sqlOp} :${paramName}`);
950
+ params[paramName] = val;
951
+ addTypeHintForParam(type_hints, paramName, col, val);
952
+ } else {
953
+ const val = pred.value;
954
+ if (val === void 0) throw new Error(`Operator ${op} requires a value for column ${key}`);
955
+ validateComparisonValue(col, key, val, op);
956
+ p += 1;
957
+ const paramName = `${table.name}_${key}_${p}`;
958
+ if (op === "=") andParts.push(`${qualified} = :${paramName}`);
959
+ else if (op === "!=") andParts.push(`${qualified} <> :${paramName}`);
960
+ else if (op === "<" || op === "<=" || op === ">" || op === ">=") andParts.push(`${qualified} ${op} :${paramName}`);
961
+ else throw new Error(`Unsupported operator: ${op}`);
962
+ params[paramName] = val;
963
+ addTypeHintForParam(type_hints, paramName, col, val);
964
+ }
965
+ }
966
+ const orGroupSql = [];
967
+ for (const group of state.orWhereGroups) {
968
+ const orParts = [];
969
+ for (const key in group) {
970
+ const value = group[key];
971
+ const col = findColumn(table, key);
972
+ p += 1;
973
+ const paramName = `${table.name}_${key}_${p}`;
974
+ if (value === null) {
975
+ if (!col.is_nullable) throw new Error(`Column ${table.name}.${key} is not nullable; cannot compare to null`);
976
+ orParts.push(`"${table.name}"."${key}" is null`);
977
+ } else if (Array.isArray(value) && !isArrayShapedGeomScalarValue(col, value)) {
978
+ validateInArrayValues(col, key, value, "in");
979
+ orParts.push(`"${table.name}"."${key}" = ANY(:${paramName})`);
980
+ params[paramName] = value;
981
+ addTypeHintForParam(type_hints, paramName, col, value);
982
+ } else {
983
+ validateScalarForColumn(col, value, `column ${key}`);
984
+ orParts.push(`"${table.name}"."${key}" = :${paramName}`);
985
+ params[paramName] = value;
986
+ addTypeHintForParam(type_hints, paramName, col, value);
987
+ }
988
+ }
989
+ if (orParts.length) orGroupSql.push("(" + orParts.join(" or ") + ")");
990
+ }
991
+ for (const group of state.orOpGroups) {
992
+ const orParts = [];
993
+ for (const pred of group) {
994
+ const key = String(pred.col);
995
+ const op = String(pred.op);
996
+ const col = findColumn(table, key);
997
+ const qualified = `"${table.name}"."${key}"`;
998
+ if (op === "isnull" || op === "notnull") {
999
+ if (pred.value !== void 0) throw new Error(`Operator ${op} does not take a value for column ${key}`);
1000
+ orParts.push(`${qualified} is ${op === "isnull" ? "null" : "not null"}`);
1001
+ } else if (op === "in" || op === "notin") {
1002
+ const val = pred.value;
1003
+ if (!Array.isArray(val)) throw new Error(`Operator ${op} requires an array value for column ${key}`);
1004
+ validateInArrayValues(col, key, val, op);
1005
+ p += 1;
1006
+ const paramName = `${table.name}_${key}_${p}`;
1007
+ orParts.push(`${qualified} ${op === "in" ? "= ANY" : "!= ALL"}(:${paramName})`);
1008
+ params[paramName] = val;
1009
+ addTypeHintForParam(type_hints, paramName, col, val);
1010
+ } else if (op === "like" || op === "ilike" || op === "notlike" || op === "notilike") {
1011
+ const val = pred.value;
1012
+ if (typeof val !== "string") throw new Error(`Operator ${op} requires a string value for column ${key}`);
1013
+ p += 1;
1014
+ const paramName = `${table.name}_${key}_${p}`;
1015
+ const sqlOp = op === "like" ? "like" : op === "ilike" ? "ilike" : op === "notlike" ? "not like" : "not ilike";
1016
+ orParts.push(`${qualified} ${sqlOp} :${paramName}`);
1017
+ params[paramName] = val;
1018
+ addTypeHintForParam(type_hints, paramName, col, val);
1019
+ } else {
1020
+ const val = pred.value;
1021
+ if (val === void 0) throw new Error(`Operator ${op} requires a value for column ${key}`);
1022
+ validateComparisonValue(col, key, val, op);
1023
+ p += 1;
1024
+ const paramName = `${table.name}_${key}_${p}`;
1025
+ if (op === "=") orParts.push(`${qualified} = :${paramName}`);
1026
+ else if (op === "!=") orParts.push(`${qualified} <> :${paramName}`);
1027
+ else if (op === "<" || op === "<=" || op === ">" || op === ">=") orParts.push(`${qualified} ${op} :${paramName}`);
1028
+ else throw new Error(`Unsupported operator: ${op}`);
1029
+ params[paramName] = val;
1030
+ addTypeHintForParam(type_hints, paramName, col, val);
1031
+ }
1032
+ }
1033
+ if (orParts.length) orGroupSql.push("(" + orParts.join(" or ") + ")");
1034
+ }
1035
+ if (orGroupSql.length) {
1036
+ const andSql = andParts.length ? `(${andParts.join(" and ")})` : "";
1037
+ const orSql = orGroupSql.join(" or ");
1038
+ const full = andSql ? `${andSql} or ${orSql}` : orSql;
1039
+ if (full.trim().length) parts.push("where " + full);
1040
+ } else if (andParts.length) parts.push("where " + andParts.join(" and "));
1041
+ if (state.order.length) {
1042
+ const orders = [];
1043
+ for (const o of state.order) orders.push(`"${table.name}"."${o.col}" ${o.dir}`);
1044
+ parts.push("order by " + orders.join(", "));
1045
+ }
1046
+ if (state.limit !== void 0) parts.push("limit " + state.limit);
1047
+ if (state.offset !== void 0) parts.push("offset " + state.offset);
1048
+ return {
1049
+ q: parts.join(" "),
1050
+ params,
1051
+ type_hints: Object.keys(type_hints).length ? type_hints : void 0
1052
+ };
1053
+ };
1054
+ }
1055
+ selectFrom(tableName, cols$1) {
1056
+ const jtName = String(tableName);
1057
+ const join = this.s.joins.find((j) => j.target.name === jtName);
1058
+ if (!join) throw new Error(`selectFrom('${jtName}') requires a prior join('${jtName}') call`);
1059
+ const sel = !cols$1 || cols$1.length === 0 ? ["*"] : cols$1.map(String);
1060
+ if (!(sel.length === 1 && sel[0] === "*")) for (const c of sel) findColumn(join.target, String(c));
1061
+ const existing = this.s.joinSelections.find((js) => js.target.name === jtName);
1062
+ if (existing) {
1063
+ if (existing.selected.includes("*")) return this;
1064
+ if (sel.length === 1 && sel[0] === "*") existing.selected = ["*"];
1065
+ else {
1066
+ const set = new Set(existing.selected);
1067
+ for (const c of sel) set.add(String(c));
1068
+ existing.selected = Array.from(set);
1069
+ }
1070
+ } else this.s.joinSelections.push({
1071
+ target: join.target,
1072
+ selected: sel
1073
+ });
1074
+ return this;
1075
+ }
1076
+ andWhere(where) {
1077
+ for (const k in where) this.s.where[k] = where[k];
1078
+ return this;
1079
+ }
1080
+ /** @deprecated Use andWhere() instead */
1081
+ where(where) {
1082
+ return this.andWhere(where);
1083
+ }
1084
+ orWhere(where) {
1085
+ this.s.orWhereGroups.push(where);
1086
+ return this;
1087
+ }
1088
+ wherePk(pk) {
1089
+ const pkCols = getPrimaryKeyColumns(table);
1090
+ if (!pkCols || pkCols.length === 0) throw new Error(`Table ${table.name} does not have a primary key`);
1091
+ if (pkCols.length === 1) {
1092
+ const colName = pkCols[0];
1093
+ const colDef = findColumn(table, colName);
1094
+ if (pk === null || pk === void 0) throw new Error(`wherePk on ${table.name} requires a non-null value for primary key column ${colName}`);
1095
+ if (Array.isArray(pk)) throw new Error(`wherePk on ${table.name} expects a scalar for primary key column ${colName}, not an array`);
1096
+ if (isPlainObject(pk)) throw new Error(`wherePk on ${table.name} expects a scalar for primary key column ${colName}`);
1097
+ validateScalarForColumn(colDef, pk, `primary key ${table.name}.${colName}`);
1098
+ this.s.where[colName] = pk;
1099
+ return this;
1100
+ } else {
1101
+ if (!isPlainObject(pk) || pk === null) throw new Error(`wherePk on ${table.name} requires an object with keys: ${pkCols.join(", ")}`);
1102
+ const obj = pk;
1103
+ for (const k of Object.keys(obj)) if (!pkCols.includes(k)) throw new Error(`wherePk received unknown key '${k}'. Expected keys: ${pkCols.join(", ")}`);
1104
+ for (const colName of pkCols) {
1105
+ if (!(colName in obj)) throw new Error(`wherePk missing key '${colName}'. Required keys: ${pkCols.join(", ")}`);
1106
+ const v = obj[colName];
1107
+ if (v === null || v === void 0) throw new Error(`wherePk on ${table.name} requires non-null values for all primary key columns (${pkCols.join(", ")})`);
1108
+ if (Array.isArray(v)) throw new Error(`wherePk on ${table.name} expects scalar values for primary key column ${colName}, not an array`);
1109
+ validateScalarForColumn(findColumn(table, colName), v, `primary key ${table.name}.${colName}`);
1110
+ this.s.where[colName] = v;
1111
+ }
1112
+ return this;
1113
+ }
1114
+ }
1115
+ andWhereOp(col, op, ...args) {
1116
+ const value = args[0];
1117
+ this.s.andOps.push({
1118
+ col,
1119
+ op,
1120
+ value
1121
+ });
1122
+ return this;
1123
+ }
1124
+ orWhereOp(col, op, ...args) {
1125
+ const value = args[0];
1126
+ this.s.orOpGroups.push([{
1127
+ col,
1128
+ op,
1129
+ value
1130
+ }]);
1131
+ return this;
1132
+ }
1133
+ andWhereOpGroup(predicates) {
1134
+ const group = predicates.map((p) => ({
1135
+ col: p[0],
1136
+ op: p[1],
1137
+ value: p[2]
1138
+ }));
1139
+ for (const g of group) this.s.andOps.push(g);
1140
+ return this;
1141
+ }
1142
+ orWhereOpGroup(predicates) {
1143
+ const group = predicates.map((p) => ({
1144
+ col: p[0],
1145
+ op: p[1],
1146
+ value: p[2]
1147
+ }));
1148
+ this.s.orOpGroups.push(group);
1149
+ return this;
1150
+ }
1151
+ orderBy(order) {
1152
+ this.s.order = [];
1153
+ const isValidDir = (d) => d === "asc" || d === "desc";
1154
+ if (typeof order === "string") {
1155
+ findColumn(table, String(order));
1156
+ this.s.order.push({
1157
+ col: order,
1158
+ dir: "asc"
1159
+ });
1160
+ } else for (const item of order) {
1161
+ const col = String(item[0]);
1162
+ const dir = String(item[1]);
1163
+ findColumn(table, col);
1164
+ if (!isValidDir(dir)) throw new Error(`Invalid order direction: ${dir}. Allowed: asc | desc`);
1165
+ this.s.order.push({
1166
+ col: item[0],
1167
+ dir
1168
+ });
1169
+ }
1170
+ return this;
1171
+ }
1172
+ limit(n) {
1173
+ if (typeof n !== "number" || !Number.isFinite(n) || !Number.isInteger(n) || n < 0) throw new Error(`Invalid limit: ${n}. Limit must be a non-negative integer`);
1174
+ this.s.limit = n;
1175
+ return this;
1176
+ }
1177
+ offset(n) {
1178
+ if (typeof n !== "number" || !Number.isFinite(n) || !Number.isInteger(n) || n < 0) throw new Error(`Invalid offset: ${n}. Offset must be a non-negative integer`);
1179
+ this.s.offset = n;
1180
+ return this;
1181
+ }
1182
+ join(tableName, type = "inner") {
1183
+ const target = findTable(schema, String(tableName));
1184
+ const pairs = findJoinOn(table, target);
1185
+ if (!pairs || !pairs.length) throw new Error(`No foreign key relation found between ${table.name} and ${target.name}`);
1186
+ const jt = String(type);
1187
+ if (jt !== "inner" && jt !== "left" && jt !== "right" && jt !== "full") throw new Error(`Invalid join type: ${jt}. Allowed: inner | left | right | full`);
1188
+ this.s.joins.push({
1189
+ type: jt,
1190
+ target,
1191
+ on: pairs
1192
+ });
1193
+ return this;
1194
+ }
1195
+ }();
1196
+ }
1197
+ insert(values) {
1198
+ const table = this.table;
1199
+ const schema = this.schema;
1200
+ const state = {
1201
+ values,
1202
+ returning: []
1203
+ };
1204
+ return new class {
1205
+ constructor() {
1206
+ this.returning = (cols) => {
1207
+ state.returning = cols || [];
1208
+ return this;
1209
+ };
1210
+ this.toSql = () => {
1211
+ const cols = [];
1212
+ const vals = [];
1213
+ const params = {};
1214
+ const type_hints = {};
1215
+ let p = 0;
1216
+ for (const key in state.values) {
1217
+ const value = state.values[key];
1218
+ const col = findColumn(table, key);
1219
+ p += 1;
1220
+ const paramName = `${table.name}_${key}_${p}`;
1221
+ cols.push(`"${key}"`);
1222
+ vals.push(`:${paramName}`);
1223
+ params[paramName] = value;
1224
+ addTypeHintForParam(type_hints, paramName, col, value);
1225
+ }
1226
+ const parts = [];
1227
+ parts.push(`insert into "${schema.name}"."${table.name}" (${cols.join(", ")}) values (${vals.join(", ")})`);
1228
+ if (state.returning.length) parts.push("returning " + state.returning.join(", "));
1229
+ return {
1230
+ q: parts.join(" "),
1231
+ params,
1232
+ type_hints: Object.keys(type_hints).length ? type_hints : void 0
1233
+ };
1234
+ };
1235
+ }
1236
+ }();
1237
+ }
1238
+ update(values) {
1239
+ const table = this.table;
1240
+ const schema = this.schema;
1241
+ const state = {
1242
+ values,
1243
+ where: {},
1244
+ returning: []
1245
+ };
1246
+ return new class {
1247
+ constructor() {
1248
+ this.where = (w) => {
1249
+ for (const k in w) state.where[k] = w[k];
1250
+ return this;
1251
+ };
1252
+ this.wherePk = (pk) => {
1253
+ const pkCols = getPrimaryKeyColumns(table);
1254
+ if (!pkCols || pkCols.length === 0) throw new Error(`Table ${table.name} does not have a primary key`);
1255
+ if (pkCols.length === 1) {
1256
+ const colName = pkCols[0];
1257
+ const colDef = findColumn(table, colName);
1258
+ if (pk === null || pk === void 0) throw new Error(`wherePk on ${table.name} requires a non-null value for primary key column ${colName}`);
1259
+ if (Array.isArray(pk)) throw new Error(`wherePk on ${table.name} expects a scalar for primary key column ${colName}, not an array`);
1260
+ if (isPlainObject(pk)) throw new Error(`wherePk on ${table.name} expects a scalar for primary key column ${colName}`);
1261
+ validateScalarForColumn(colDef, pk, `primary key ${table.name}.${colName}`);
1262
+ state.where[colName] = pk;
1263
+ } else {
1264
+ if (!isPlainObject(pk) || pk === null) throw new Error(`wherePk on ${table.name} requires an object with keys: ${pkCols.join(", ")}`);
1265
+ const obj = pk;
1266
+ for (const k of Object.keys(obj)) if (!pkCols.includes(k)) throw new Error(`wherePk received unknown key '${k}'. Expected keys: ${pkCols.join(", ")}`);
1267
+ for (const colName of pkCols) {
1268
+ if (!(colName in obj)) throw new Error(`wherePk missing key '${colName}'. Required keys: ${pkCols.join(", ")}`);
1269
+ const v = obj[colName];
1270
+ if (v === null || v === void 0) throw new Error(`wherePk on ${table.name} requires non-null values for all primary key columns (${pkCols.join(", ")})`);
1271
+ if (Array.isArray(v)) throw new Error(`wherePk on ${table.name} expects scalar values for primary key column ${colName}, not an array`);
1272
+ validateScalarForColumn(findColumn(table, colName), v, `primary key ${table.name}.${colName}`);
1273
+ state.where[colName] = v;
1274
+ }
1275
+ }
1276
+ return this;
1277
+ };
1278
+ this.returning = (cols) => {
1279
+ state.returning = cols || [];
1280
+ return this;
1281
+ };
1282
+ this.toSql = () => {
1283
+ const params = {};
1284
+ const type_hints = {};
1285
+ let p = 0;
1286
+ const setParts = [];
1287
+ for (const key in state.values) {
1288
+ const value = state.values[key];
1289
+ const col = findColumn(table, key);
1290
+ p += 1;
1291
+ const paramName = `${table.name}_${key}_${p}`;
1292
+ setParts.push(`"${key}" = :${paramName}`);
1293
+ params[paramName] = value;
1294
+ addTypeHintForParam(type_hints, paramName, col, value);
1295
+ }
1296
+ const whereClauses = [];
1297
+ for (const key in state.where) {
1298
+ const value = state.where[key];
1299
+ const col = findColumn(table, key);
1300
+ p += 1;
1301
+ const paramName = `${table.name}_${key}_${p}`;
1302
+ if (value === null) {
1303
+ if (!col.is_nullable) throw new Error(`Column ${table.name}.${key} is not nullable; cannot compare to null`);
1304
+ whereClauses.push(`"${key}" is null`);
1305
+ } else if (Array.isArray(value) && !isArrayShapedGeomScalarValue(col, value)) {
1306
+ validateInArrayValues(col, key, value, "in");
1307
+ whereClauses.push(`"${key}" = ANY(:${paramName})`);
1308
+ params[paramName] = value;
1309
+ addTypeHintForParam(type_hints, paramName, col, value);
1310
+ } else {
1311
+ validateScalarForColumn(col, value, `column ${key}`);
1312
+ whereClauses.push(`"${key}" = :${paramName}`);
1313
+ params[paramName] = value;
1314
+ addTypeHintForParam(type_hints, paramName, col, value);
1315
+ }
1316
+ }
1317
+ const parts = [];
1318
+ parts.push(`update "${schema.name}"."${table.name}" set ${setParts.join(", ")}`);
1319
+ if (whereClauses.length) parts.push("where " + whereClauses.join(" and "));
1320
+ if (state.returning.length) parts.push("returning " + state.returning.join(", "));
1321
+ return {
1322
+ q: parts.join(" "),
1323
+ params,
1324
+ type_hints: Object.keys(type_hints).length ? type_hints : void 0
1325
+ };
1326
+ };
1327
+ }
1328
+ }();
1329
+ }
1330
+ delete() {
1331
+ const table = this.table;
1332
+ const schema = this.schema;
1333
+ const state = {
1334
+ where: {},
1335
+ returning: []
1336
+ };
1337
+ return new class {
1338
+ constructor() {
1339
+ this.where = (w) => {
1340
+ for (const k in w) state.where[k] = w[k];
1341
+ return this;
1342
+ };
1343
+ this.wherePk = (pk) => {
1344
+ const pkCols = getPrimaryKeyColumns(table);
1345
+ if (!pkCols || pkCols.length === 0) throw new Error(`Table ${table.name} does not have a primary key`);
1346
+ if (pkCols.length === 1) {
1347
+ const col = pkCols[0];
1348
+ if (isPlainObject(pk)) throw new Error(`wherePk on ${table.name} expects a scalar for primary key column ${col}`);
1349
+ state.where[col] = pk;
1350
+ } else {
1351
+ if (!isPlainObject(pk)) throw new Error(`wherePk on ${table.name} requires an object with keys: ${pkCols.join(", ")}`);
1352
+ const obj = pk;
1353
+ for (const k of Object.keys(obj)) if (!pkCols.includes(k)) throw new Error(`wherePk received unknown key '${k}'. Expected keys: ${pkCols.join(", ")}`);
1354
+ for (const col of pkCols) {
1355
+ if (!(col in obj)) throw new Error(`wherePk missing key '${col}'. Required keys: ${pkCols.join(", ")}`);
1356
+ state.where[col] = obj[col];
1357
+ }
1358
+ }
1359
+ return this;
1360
+ };
1361
+ this.returning = (cols) => {
1362
+ state.returning = cols || [];
1363
+ return this;
1364
+ };
1365
+ this.toSql = () => {
1366
+ const params = {};
1367
+ const type_hints = {};
1368
+ let p = 0;
1369
+ const whereClauses = [];
1370
+ for (const key in state.where) {
1371
+ const value = state.where[key];
1372
+ const col = findColumn(table, key);
1373
+ p += 1;
1374
+ const paramName = `${table.name}_${key}_${p}`;
1375
+ if (value === null) {
1376
+ if (!col.is_nullable) throw new Error(`Column ${table.name}.${key} is not nullable; cannot compare to null`);
1377
+ whereClauses.push(`"${key}" is null`);
1378
+ } else if (Array.isArray(value)) {
1379
+ validateInArrayValues(col, key, value, "in");
1380
+ whereClauses.push(`"${key}" = ANY(:${paramName})`);
1381
+ params[paramName] = value;
1382
+ addTypeHintForParam(type_hints, paramName, col, value);
1383
+ } else {
1384
+ validateScalarForColumn(col, value, `column ${key}`);
1385
+ whereClauses.push(`"${key}" = :${paramName}`);
1386
+ params[paramName] = value;
1387
+ addTypeHintForParam(type_hints, paramName, col, value);
1388
+ }
1389
+ }
1390
+ const parts = [];
1391
+ parts.push(`delete from "${schema.name}"."${table.name}"`);
1392
+ if (whereClauses.length) parts.push("where " + whereClauses.join(" and "));
1393
+ if (state.returning.length) parts.push("returning " + state.returning.join(", "));
1394
+ return {
1395
+ q: parts.join(" "),
1396
+ params,
1397
+ type_hints: Object.keys(type_hints).length ? type_hints : void 0
1398
+ };
1399
+ };
1400
+ }
1401
+ }();
1402
+ }
1403
+ };
1404
+ function createSqlBuilder(schema) {
1405
+ return { table: (name) => new TableQueryImpl(schema, String(name)) };
1406
+ }
1407
+
608
1408
  //#endregion
609
1409
  exports.Claims = Claims;
610
1410
  exports.CodeFlow = CodeFlow;
@@ -619,4 +1419,5 @@ exports.Tables = Tables;
619
1419
  exports.Users = Users;
620
1420
  exports.Ws = Ws;
621
1421
  exports.createApi = createApi;
1422
+ exports.createSqlBuilder = createSqlBuilder;
622
1423
  });