@centia-io/sdk 0.0.41 → 0.0.43

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.
@@ -5,1065 +5,1007 @@
5
5
  })(this, function(exports) {
6
6
 
7
7
  //#region src/util/jwt-decode.ts
8
- var InvalidTokenError = class extends Error {};
9
- InvalidTokenError.prototype.name = "InvalidTokenError";
10
- function b64DecodeUnicode(str) {
11
- return decodeURIComponent(atob(str).replace(/(.)/g, (m, p) => {
12
- let code = p.charCodeAt(0).toString(16).toUpperCase();
13
- if (code.length < 2) code = "0" + code;
14
- return "%" + code;
15
- }));
16
- }
17
- function base64UrlDecode(str) {
18
- let output = str.replace(/-/g, "+").replace(/_/g, "/");
19
- switch (output.length % 4) {
20
- case 0: break;
21
- case 2:
22
- output += "==";
23
- break;
24
- case 3:
25
- output += "=";
26
- break;
27
- default: throw new Error("base64 string is not of the correct length");
28
- }
29
- try {
30
- return b64DecodeUnicode(output);
31
- } catch (err) {
32
- return atob(output);
33
- }
8
+ var InvalidTokenError = class extends Error {};
9
+ InvalidTokenError.prototype.name = "InvalidTokenError";
10
+ function b64DecodeUnicode(str) {
11
+ return decodeURIComponent(atob(str).replace(/(.)/g, (m, p) => {
12
+ let code = p.charCodeAt(0).toString(16).toUpperCase();
13
+ if (code.length < 2) code = "0" + code;
14
+ return "%" + code;
15
+ }));
16
+ }
17
+ function base64UrlDecode(str) {
18
+ let output = str.replace(/-/g, "+").replace(/_/g, "/");
19
+ switch (output.length % 4) {
20
+ case 0: break;
21
+ case 2:
22
+ output += "==";
23
+ break;
24
+ case 3:
25
+ output += "=";
26
+ break;
27
+ default: throw new Error("base64 string is not of the correct length");
34
28
  }
35
- function jwtDecode(token, options) {
36
- if (typeof token !== "string") throw new InvalidTokenError("Invalid token specified: must be a string");
37
- options ||= {};
38
- const pos = options.header === true ? 0 : 1;
39
- const part = token.split(".")[pos];
40
- if (typeof part !== "string") throw new InvalidTokenError(`Invalid token specified: missing part #${pos + 1}`);
41
- let decoded;
42
- try {
43
- decoded = base64UrlDecode(part);
44
- } catch (e) {
45
- throw new InvalidTokenError(`Invalid token specified: invalid base64 for part #${pos + 1} (${e.message})`);
46
- }
47
- try {
48
- return JSON.parse(decoded);
49
- } catch (e) {
50
- throw new InvalidTokenError(`Invalid token specified: invalid json for part #${pos + 1} (${e.message})`);
51
- }
29
+ try {
30
+ return b64DecodeUnicode(output);
31
+ } catch (err) {
32
+ return atob(output);
33
+ }
34
+ }
35
+ function jwtDecode(token, options) {
36
+ if (typeof token !== "string") throw new InvalidTokenError("Invalid token specified: must be a string");
37
+ options ||= {};
38
+ const pos = options.header === true ? 0 : 1;
39
+ const part = token.split(".")[pos];
40
+ if (typeof part !== "string") throw new InvalidTokenError(`Invalid token specified: missing part #${pos + 1}`);
41
+ let decoded;
42
+ try {
43
+ decoded = base64UrlDecode(part);
44
+ } catch (e) {
45
+ throw new InvalidTokenError(`Invalid token specified: invalid base64 for part #${pos + 1} (${e.message})`);
52
46
  }
47
+ try {
48
+ return JSON.parse(decoded);
49
+ } catch (e) {
50
+ throw new InvalidTokenError(`Invalid token specified: invalid json for part #${pos + 1} (${e.message})`);
51
+ }
52
+ }
53
53
 
54
54
  //#endregion
55
55
  //#region src/util/storage.ts
56
- var MemoryStorage = class {
57
- constructor() {
58
- this.store = /* @__PURE__ */ new Map();
59
- }
60
- getItem(key) {
61
- return this.store.has(key) ? this.store.get(key) : null;
62
- }
63
- setItem(key, value) {
64
- this.store.set(key, String(value));
65
- }
66
- removeItem(key) {
67
- this.store.delete(key);
68
- }
69
- };
70
- let cached = null;
71
- function getStorage() {
72
- if (cached) return cached;
73
- try {
74
- const g$1 = typeof globalThis !== "undefined" ? globalThis : window;
75
- if (g$1 && g$1.localStorage && typeof g$1.localStorage.getItem === "function") {
76
- cached = g$1.localStorage;
77
- return cached;
78
- }
79
- } catch (e) {}
80
- const g = typeof globalThis !== "undefined" ? globalThis : {};
81
- if (!g.__gc2_memory_storage) g.__gc2_memory_storage = new MemoryStorage();
82
- cached = g.__gc2_memory_storage;
83
- return cached;
56
+ var MemoryStorage = class {
57
+ constructor() {
58
+ this.store = /* @__PURE__ */ new Map();
59
+ }
60
+ getItem(key) {
61
+ return this.store.has(key) ? this.store.get(key) : null;
62
+ }
63
+ setItem(key, value) {
64
+ this.store.set(key, String(value));
84
65
  }
66
+ removeItem(key) {
67
+ this.store.delete(key);
68
+ }
69
+ };
70
+ let cached = null;
71
+ function getStorage() {
72
+ if (cached) return cached;
73
+ try {
74
+ const g$1 = typeof globalThis !== "undefined" ? globalThis : window;
75
+ if (g$1 && g$1.localStorage && typeof g$1.localStorage.getItem === "function") {
76
+ cached = g$1.localStorage;
77
+ return cached;
78
+ }
79
+ } catch (e) {}
80
+ const g = typeof globalThis !== "undefined" ? globalThis : {};
81
+ if (!g.__gc2_memory_storage) g.__gc2_memory_storage = new MemoryStorage();
82
+ cached = g.__gc2_memory_storage;
83
+ return cached;
84
+ }
85
85
 
86
86
  //#endregion
87
87
  //#region src/util/utils.ts
88
- /**
89
- * @author Martin Høgh <mh@mapcentia.com>
90
- * @copyright 2013-2026 MapCentia ApS
91
- * @license https://opensource.org/license/mit The MIT License
92
- *
93
- */
94
- const generatePkceChallenge = async () => {
95
- const generateRandomString = () => {
96
- const array = new Uint32Array(28);
97
- crypto.getRandomValues(array);
98
- return Array.from(array, (dec) => ("0" + dec.toString(16)).substr(-2)).join("");
99
- };
100
- const sha256 = (plain) => {
101
- const data = new TextEncoder().encode(plain);
102
- return crypto.subtle.digest("SHA-256", data);
103
- };
104
- const base64urlEncode = (str) => {
105
- return btoa(String.fromCharCode.apply(null, [...new Uint8Array(str)])).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
106
- };
107
- async function pkceChallengeFromVerifier(v) {
108
- return base64urlEncode(await sha256(v));
109
- }
110
- const { state, codeVerifier } = {
111
- state: generateRandomString(),
112
- codeVerifier: generateRandomString()
113
- };
114
- return {
115
- state,
116
- codeVerifier,
117
- codeChallenge: await pkceChallengeFromVerifier(codeVerifier)
118
- };
119
- };
120
- const isTokenExpired = (token) => {
121
- let isJwtExpired = false;
122
- const { exp } = jwtDecode(token);
123
- const currentTime = (/* @__PURE__ */ new Date()).getTime() / 1e3;
124
- if (exp) {
125
- if (currentTime > exp) isJwtExpired = true;
126
- }
127
- return isJwtExpired;
88
+ const generatePkceChallenge = async () => {
89
+ const generateRandomString = () => {
90
+ const array = new Uint32Array(28);
91
+ crypto.getRandomValues(array);
92
+ return Array.from(array, (dec) => ("0" + dec.toString(16)).substr(-2)).join("");
128
93
  };
129
- const claims = (token) => {
130
- return jwtDecode(token);
94
+ const sha256 = (plain) => {
95
+ const data = new TextEncoder().encode(plain);
96
+ return crypto.subtle.digest("SHA-256", data);
131
97
  };
132
- const isLogin = async (gc2) => {
133
- const { accessToken, refreshToken } = getTokens();
134
- if (!accessToken && !refreshToken) return false;
135
- if (!accessToken || accessToken && isTokenExpired(accessToken)) {
136
- if (refreshToken && isTokenExpired(refreshToken)) {
137
- clearTokens();
138
- clearOptions();
139
- throw new Error("Refresh token has expired. Please login again.");
140
- }
141
- if (refreshToken) try {
142
- const data = await gc2.getRefreshToken(refreshToken);
143
- setTokens({
144
- accessToken: data.access_token,
145
- refreshToken,
146
- idToken: data?.id_token
147
- });
148
- console.log("Access token refreshed");
149
- } catch (e) {
150
- throw new Error("Could not get refresh token.");
151
- }
152
- }
153
- return true;
154
- };
155
- const setTokens = (tokens) => {
156
- getStorage().setItem("gc2_tokens", JSON.stringify({
157
- "accessToken": tokens.accessToken,
158
- "refreshToken": tokens.refreshToken,
159
- "idToken": tokens?.idToken || ""
160
- }));
98
+ const base64urlEncode = (str) => {
99
+ return btoa(String.fromCharCode.apply(null, [...new Uint8Array(str)])).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
161
100
  };
162
- const getTokens = () => {
163
- const str = getStorage().getItem("gc2_tokens");
164
- const tokens = str ? JSON.parse(str) : {};
165
- return {
166
- accessToken: tokens?.accessToken || "",
167
- refreshToken: tokens?.refreshToken || "",
168
- idToken: tokens?.idToken || ""
169
- };
170
- };
171
- const setOptions = (options) => {
172
- getStorage().setItem("gc2_options", JSON.stringify({
173
- "clientId": options.clientId,
174
- "host": options.host,
175
- "redirectUri": options.redirectUri,
176
- "clientSecret": options.clientSecret || null
177
- }));
178
- };
179
- const getOptions = () => {
180
- const str = getStorage().getItem("gc2_options");
181
- const options = str ? JSON.parse(str) : {};
182
- return {
183
- clientId: options?.clientId || "",
184
- host: options?.host || "",
185
- redirectUri: options?.redirectUri || ""
186
- };
187
- };
188
- const clearTokens = () => {
189
- getStorage().removeItem("gc2_tokens");
101
+ async function pkceChallengeFromVerifier(v) {
102
+ return base64urlEncode(await sha256(v));
103
+ }
104
+ const { state, codeVerifier } = {
105
+ state: generateRandomString(),
106
+ codeVerifier: generateRandomString()
190
107
  };
191
- const clearOptions = () => {
192
- getStorage().removeItem("gc2_options");
108
+ return {
109
+ state,
110
+ codeVerifier,
111
+ codeChallenge: await pkceChallengeFromVerifier(codeVerifier)
193
112
  };
194
- const getNonce = () => {
195
- return getStorage().getItem("gc2_nonce");
113
+ };
114
+ const isTokenExpired = (token) => {
115
+ let isJwtExpired = false;
116
+ const { exp } = jwtDecode(token);
117
+ const currentTime = (/* @__PURE__ */ new Date()).getTime() / 1e3;
118
+ if (exp) {
119
+ if (currentTime > exp) isJwtExpired = true;
120
+ }
121
+ return isJwtExpired;
122
+ };
123
+ const claims = (token) => {
124
+ return jwtDecode(token);
125
+ };
126
+ const isLogin = async (gc2) => {
127
+ const { accessToken, refreshToken } = getTokens();
128
+ if (!accessToken && !refreshToken) return false;
129
+ if (!accessToken || accessToken && isTokenExpired(accessToken)) {
130
+ if (refreshToken && isTokenExpired(refreshToken)) {
131
+ clearTokens();
132
+ clearOptions();
133
+ throw new Error("Refresh token has expired. Please login again.");
134
+ }
135
+ if (refreshToken) try {
136
+ const data = await gc2.getRefreshToken(refreshToken);
137
+ setTokens({
138
+ accessToken: data.access_token,
139
+ refreshToken,
140
+ idToken: data?.id_token
141
+ });
142
+ console.log("Access token refreshed");
143
+ } catch (e) {
144
+ throw new Error("Could not get refresh token.");
145
+ }
146
+ }
147
+ return true;
148
+ };
149
+ const setTokens = (tokens) => {
150
+ getStorage().setItem("gc2_tokens", JSON.stringify({
151
+ "accessToken": tokens.accessToken,
152
+ "refreshToken": tokens.refreshToken,
153
+ "idToken": tokens?.idToken || ""
154
+ }));
155
+ };
156
+ const getTokens = () => {
157
+ const str = getStorage().getItem("gc2_tokens");
158
+ const tokens = str ? JSON.parse(str) : {};
159
+ return {
160
+ accessToken: tokens?.accessToken || "",
161
+ refreshToken: tokens?.refreshToken || "",
162
+ idToken: tokens?.idToken || ""
196
163
  };
197
- const clearNonce = () => {
198
- getStorage().removeItem("gc2_nonce");
164
+ };
165
+ const setOptions = (options) => {
166
+ getStorage().setItem("gc2_options", JSON.stringify({
167
+ "clientId": options.clientId,
168
+ "host": options.host,
169
+ "redirectUri": options.redirectUri
170
+ }));
171
+ };
172
+ const getOptions = () => {
173
+ const str = getStorage().getItem("gc2_options");
174
+ const options = str ? JSON.parse(str) : {};
175
+ return {
176
+ clientId: options?.clientId || "",
177
+ host: options?.host || "",
178
+ redirectUri: options?.redirectUri || ""
199
179
  };
180
+ };
181
+ const clearTokens = () => {
182
+ getStorage().removeItem("gc2_tokens");
183
+ };
184
+ const clearOptions = () => {
185
+ getStorage().removeItem("gc2_options");
186
+ };
187
+ const getNonce = () => {
188
+ return getStorage().getItem("gc2_nonce");
189
+ };
190
+ const clearNonce = () => {
191
+ getStorage().removeItem("gc2_nonce");
192
+ };
200
193
 
201
194
  //#endregion
202
195
  //#region src/services/gc2.services.ts
203
- /**
204
- * @author Martin Høgh <mh@mapcentia.com>
205
- * @copyright 2013-2026 MapCentia ApS
206
- * @license https://opensource.org/license/mit The MIT License
207
- *
208
- */
209
- var Gc2Service = class {
210
- constructor(options) {
211
- this.options = options;
212
- this.host = options.host;
213
- }
214
- isCodeFlowOptions(options) {
215
- return "redirectUri" in options;
216
- }
217
- isPasswordFlowOptions(options) {
218
- return "username" in options;
219
- }
220
- isSignUpOptions(options) {
221
- return "parentDb" in options;
222
- }
223
- buildUrl(path) {
224
- if (path.startsWith("http://") || path.startsWith("https://")) return path;
225
- return `${this.host}${path}`;
226
- }
227
- async request(url, method, body, contentType = "application/json") {
228
- const headers = { "Content-Type": contentType };
229
- let payload;
230
- if (contentType === "application/json") payload = JSON.stringify(body);
231
- else payload = new URLSearchParams(body).toString();
232
- const response = await fetch(url, {
233
- method,
234
- headers,
235
- body: payload
236
- });
237
- if (!response.ok) {
238
- const errText = await response.text();
239
- throw new Error(`HTTP error ${response.status}: ${errText}`);
240
- }
241
- return response.json();
242
- }
243
- async getDeviceCode() {
244
- const path = this.options.deviceUri ?? `${this.host}/api/v4/oauth/device`;
245
- return this.request(this.buildUrl(path), "POST", { client_id: this.options.clientId });
246
- }
247
- async pollToken(deviceCode, interval) {
248
- const path = this.options.tokenUri ?? `${this.host}/api/v4/oauth`;
249
- const getToken = async () => {
250
- try {
251
- return await this.request(this.buildUrl(path), "POST", {
252
- client_id: this.options.clientId,
253
- device_code: deviceCode,
254
- grant_type: "device_code"
255
- });
256
- } catch (e) {
257
- const err = JSON.parse(e.message.split(": ")[1]);
258
- if (err.error === "authorization_pending") return null;
259
- return err.error_description;
260
- }
261
- };
262
- let response = await getToken();
263
- while (response === null) {
264
- await new Promise((resolve) => setTimeout(resolve, interval * 1100));
265
- response = await getToken();
196
+ var Gc2Service = class {
197
+ constructor(options) {
198
+ this.options = options;
199
+ this.host = options.host;
200
+ }
201
+ isCodeFlowOptions(options) {
202
+ return "redirectUri" in options;
203
+ }
204
+ isPasswordFlowOptions(options) {
205
+ return "username" in options;
206
+ }
207
+ isSignUpOptions(options) {
208
+ return "parentDb" in options;
209
+ }
210
+ buildUrl(path) {
211
+ if (path.startsWith("http://") || path.startsWith("https://")) return path;
212
+ return `${this.host}${path}`;
213
+ }
214
+ async request(url, method, body, contentType = "application/json") {
215
+ const headers = { "Content-Type": contentType };
216
+ let payload;
217
+ if (contentType === "application/json") payload = JSON.stringify(body);
218
+ else payload = new URLSearchParams(body).toString();
219
+ const response = await fetch(url, {
220
+ method,
221
+ headers,
222
+ body: payload
223
+ });
224
+ if (!response.ok) {
225
+ const errText = await response.text();
226
+ throw new Error(`HTTP error ${response.status}: ${errText}`);
227
+ }
228
+ return response.json();
229
+ }
230
+ async getDeviceCode() {
231
+ const path = this.options.deviceUri ?? `${this.host}/api/v4/oauth/device`;
232
+ return this.request(this.buildUrl(path), "POST", { client_id: this.options.clientId });
233
+ }
234
+ async pollToken(deviceCode, interval) {
235
+ const path = this.options.tokenUri ?? `${this.host}/api/v4/oauth`;
236
+ const getToken = async () => {
237
+ try {
238
+ return await this.request(this.buildUrl(path), "POST", {
239
+ client_id: this.options.clientId,
240
+ device_code: deviceCode,
241
+ grant_type: "device_code"
242
+ });
243
+ } catch (e) {
244
+ const err = JSON.parse(e.message.split(": ")[1]);
245
+ if (err.error === "authorization_pending") return null;
246
+ return err.error_description;
266
247
  }
267
- if (typeof response === "string") throw new Error(response);
268
- return response;
269
- }
270
- getAuthorizationCodeURL(codeChallenge, state) {
271
- let redirectUri;
272
- if (this.isCodeFlowOptions(this.options)) redirectUri = this.options.redirectUri;
273
- else throw new Error("CodeFlow options required for this operation");
274
- const base = this.options.authUri ?? `${this.host}/auth/`;
275
- const params = new URLSearchParams();
276
- const nonce = getNonce();
277
- params.set("response_type", "code");
278
- params.set("client_id", this.options.clientId);
279
- params.set("redirect_uri", redirectUri);
280
- params.set("state", state);
281
- params.set("code_challenge", codeChallenge);
282
- params.set("code_challenge_method", "S256");
283
- if (nonce) params.set("nonce", nonce);
284
- if (this.options.scope) params.set("scope", this.options.scope);
285
- return `${base}?${params.toString()}`;
286
- }
287
- getSignUpURL() {
288
- if (!this.isSignUpOptions(this.options)) throw new Error("CodeFlow options required for this operation");
289
- const base = this.options.authUri ?? `${this.host}/signup/`;
290
- const params = new URLSearchParams();
291
- params.set("client_id", this.options.clientId);
292
- params.set("parentdb", this.options.parentDb);
293
- params.set("redirect_uri", this.options.redirectUri);
294
- return `${base}?${params.toString()}`;
295
- }
296
- async getAuthorizationCodeToken(code, codeVerifier) {
297
- let redirectUri;
298
- if (this.isCodeFlowOptions(this.options)) redirectUri = this.options.redirectUri;
299
- else throw new Error("CodeFlow options required for this operation");
300
- const path = this.options.tokenUri ?? `${this.host}/api/v4/oauth`;
301
- return this.request(this.buildUrl(path), "POST", {
302
- client_id: this.options.clientId,
303
- redirect_uri: redirectUri,
304
- grant_type: "authorization_code",
305
- code,
306
- code_verifier: codeVerifier
307
- }, "application/x-www-form-urlencoded");
308
- }
309
- async getPasswordToken() {
310
- let username, password, database;
311
- if (this.isPasswordFlowOptions(this.options)) {
312
- username = this.options.username;
313
- password = this.options.password;
314
- database = this.options.database;
315
- } else throw new Error("PasswordFlow options required for this operation");
316
- const path = `${this.host}/api/v4/oauth`;
317
- return this.request(this.buildUrl(path), "POST", {
318
- client_id: this.options.clientId,
319
- grant_type: "password",
320
- username,
321
- password,
322
- database
323
- });
324
- }
325
- async getRefreshToken(token) {
326
- const path = this.options.tokenUri ?? `${this.host}/api/v4/oauth`;
327
- return this.request(this.buildUrl(path), "POST", {
328
- client_id: this.options.clientId,
329
- grant_type: "refresh_token",
330
- refresh_token: token
331
- });
332
- }
333
- getSignOutURL() {
334
- let redirectUri;
335
- if (this.isCodeFlowOptions(this.options)) redirectUri = this.options.redirectUri;
336
- else throw new Error("CodeFlow options required for this operation");
337
- const params = new URLSearchParams({ redirect_uri: redirectUri });
338
- return this.options.logoutUri ?? `${this.host}/signout?${params.toString()}`;
248
+ };
249
+ let response = await getToken();
250
+ while (response === null) {
251
+ await new Promise((resolve) => setTimeout(resolve, interval * 1100));
252
+ response = await getToken();
339
253
  }
340
- };
254
+ if (typeof response === "string") throw new Error(response);
255
+ return response;
256
+ }
257
+ getAuthorizationCodeURL(codeChallenge, state) {
258
+ let redirectUri;
259
+ if (this.isCodeFlowOptions(this.options)) redirectUri = this.options.redirectUri;
260
+ else throw new Error("CodeFlow options required for this operation");
261
+ const base = this.options.authUri ?? `${this.host}/auth/`;
262
+ const params = new URLSearchParams();
263
+ const nonce = getNonce();
264
+ params.set("response_type", "code");
265
+ params.set("client_id", this.options.clientId);
266
+ params.set("redirect_uri", redirectUri);
267
+ params.set("state", state);
268
+ params.set("code_challenge", codeChallenge);
269
+ params.set("code_challenge_method", "S256");
270
+ if (nonce) params.set("nonce", nonce);
271
+ if (this.options.scope) params.set("scope", this.options.scope);
272
+ return `${base}?${params.toString()}`;
273
+ }
274
+ getSignUpURL() {
275
+ if (!this.isSignUpOptions(this.options)) throw new Error("CodeFlow options required for this operation");
276
+ const base = this.options.authUri ?? `${this.host}/signup/`;
277
+ const params = new URLSearchParams();
278
+ params.set("client_id", this.options.clientId);
279
+ params.set("parentdb", this.options.parentDb);
280
+ params.set("redirect_uri", this.options.redirectUri);
281
+ return `${base}?${params.toString()}`;
282
+ }
283
+ async getAuthorizationCodeToken(code, codeVerifier) {
284
+ let redirectUri;
285
+ if (this.isCodeFlowOptions(this.options)) redirectUri = this.options.redirectUri;
286
+ else throw new Error("CodeFlow options required for this operation");
287
+ const path = this.options.tokenUri ?? `${this.host}/api/v4/oauth`;
288
+ return this.request(this.buildUrl(path), "POST", {
289
+ client_id: this.options.clientId,
290
+ redirect_uri: redirectUri,
291
+ grant_type: "authorization_code",
292
+ code,
293
+ code_verifier: codeVerifier
294
+ }, "application/x-www-form-urlencoded");
295
+ }
296
+ async getPasswordToken() {
297
+ let username, password, database;
298
+ if (this.isPasswordFlowOptions(this.options)) {
299
+ username = this.options.username;
300
+ password = this.options.password;
301
+ database = this.options.database;
302
+ } else throw new Error("PasswordFlow options required for this operation");
303
+ const path = `${this.host}/api/v4/oauth`;
304
+ return this.request(this.buildUrl(path), "POST", {
305
+ client_id: this.options.clientId,
306
+ grant_type: "password",
307
+ username,
308
+ password,
309
+ database
310
+ });
311
+ }
312
+ async getRefreshToken(token) {
313
+ const path = this.options.tokenUri ?? `${this.host}/api/v4/oauth`;
314
+ return this.request(this.buildUrl(path), "POST", {
315
+ client_id: this.options.clientId,
316
+ grant_type: "refresh_token",
317
+ refresh_token: token
318
+ });
319
+ }
320
+ getSignOutURL() {
321
+ let redirectUri;
322
+ if (this.isCodeFlowOptions(this.options)) redirectUri = this.options.redirectUri;
323
+ else throw new Error("CodeFlow options required for this operation");
324
+ const params = new URLSearchParams({ redirect_uri: redirectUri });
325
+ return this.options.logoutUri ?? `${this.host}/signout?${params.toString()}`;
326
+ }
327
+ };
341
328
 
342
329
  //#endregion
343
330
  //#region src/CodeFlow.ts
344
- /**
345
- * @author Martin Høgh <mh@mapcentia.com>
346
- * @copyright 2013-2026 MapCentia ApS
347
- * @license https://opensource.org/license/mit The MIT License
348
- *
349
- */
350
- var CodeFlow = class {
351
- constructor(options) {
352
- this.options = options;
353
- this.service = new Gc2Service(options);
354
- }
355
- async redirectHandle() {
356
- const url = window.location.search;
357
- const queryParams = new URLSearchParams(url);
358
- if (queryParams.get("error")) throw new Error(`Failed to redirect: ${url}`);
359
- const code = queryParams.get("code");
360
- if (code) {
361
- if (queryParams.get("state") !== getStorage().getItem("state")) throw new Error("Possible CSRF attack. Aborting login!");
362
- try {
363
- const { access_token, refresh_token, id_token } = await this.service.getAuthorizationCodeToken(code, getStorage().getItem("codeVerifier"));
364
- setTokens({
365
- accessToken: access_token,
366
- refreshToken: refresh_token,
367
- idToken: id_token
368
- });
369
- setOptions({
370
- clientId: this.options.clientId,
371
- host: this.options.host,
372
- redirectUri: this.options.redirectUri
373
- });
374
- getStorage().removeItem("state");
375
- getStorage().removeItem("codeVerifier");
376
- const params = new URLSearchParams(window.location.search);
377
- params.delete("code");
378
- params.delete("state");
379
- const loc = window.location;
380
- const newUrl = loc.origin + loc.pathname + (params.size > 0 ? "?" + params.toString() : "");
381
- history.pushState(null, "", newUrl);
382
- return Promise.resolve(true);
383
- } catch (e) {
384
- throw new Error(e.message);
385
- }
331
+ var CodeFlow = class {
332
+ constructor(options) {
333
+ this.options = options;
334
+ this.service = new Gc2Service(options);
335
+ }
336
+ async redirectHandle() {
337
+ const url = window.location.search;
338
+ const queryParams = new URLSearchParams(url);
339
+ if (queryParams.get("error")) throw new Error(`Failed to redirect: ${url}`);
340
+ const code = queryParams.get("code");
341
+ if (code) {
342
+ if (queryParams.get("state") !== getStorage().getItem("state")) throw new Error("Possible CSRF attack. Aborting login!");
343
+ try {
344
+ const { access_token, refresh_token, id_token } = await this.service.getAuthorizationCodeToken(code, getStorage().getItem("codeVerifier"));
345
+ setTokens({
346
+ accessToken: access_token,
347
+ refreshToken: refresh_token,
348
+ idToken: id_token
349
+ });
350
+ setOptions({
351
+ clientId: this.options.clientId,
352
+ host: this.options.host,
353
+ redirectUri: this.options.redirectUri
354
+ });
355
+ getStorage().removeItem("state");
356
+ getStorage().removeItem("codeVerifier");
357
+ const params = new URLSearchParams(window.location.search);
358
+ params.delete("code");
359
+ params.delete("state");
360
+ const loc = window.location;
361
+ const newUrl = loc.origin + loc.pathname + (params.size > 0 ? "?" + params.toString() : "");
362
+ history.pushState(null, "", newUrl);
363
+ return Promise.resolve(true);
364
+ } catch (e) {
365
+ throw new Error(e.message);
386
366
  }
387
- return await isLogin(this.service);
388
- }
389
- async signIn() {
390
- const { state, codeVerifier, codeChallenge } = await generatePkceChallenge();
391
- getStorage().setItem("state", state);
392
- getStorage().setItem("codeVerifier", codeVerifier);
393
- window.location.assign(this.service.getAuthorizationCodeURL(codeChallenge, state));
394
367
  }
395
- signOut() {
396
- this.clear();
397
- window.location.assign(this.service.getSignOutURL());
398
- }
399
- clear() {
400
- clearTokens();
401
- clearOptions();
402
- clearNonce();
403
- }
404
- };
368
+ return await isLogin(this.service);
369
+ }
370
+ async signIn() {
371
+ const { state, codeVerifier, codeChallenge } = await generatePkceChallenge();
372
+ getStorage().setItem("state", state);
373
+ getStorage().setItem("codeVerifier", codeVerifier);
374
+ window.location.assign(this.service.getAuthorizationCodeURL(codeChallenge, state));
375
+ }
376
+ signOut() {
377
+ this.clear();
378
+ window.location.assign(this.service.getSignOutURL());
379
+ }
380
+ clear() {
381
+ clearTokens();
382
+ clearOptions();
383
+ clearNonce();
384
+ }
385
+ };
405
386
 
406
387
  //#endregion
407
388
  //#region src/PasswordFlow.ts
408
- /**
409
- * @author Martin Høgh <mh@mapcentia.com>
410
- * @copyright 2013-2026 MapCentia ApS
411
- * @license https://opensource.org/license/mit The MIT License
412
- *
413
- */
414
- var PasswordFlow = class {
415
- constructor(options) {
416
- this.options = options;
417
- this.service = new Gc2Service(options);
418
- }
419
- async signIn() {
420
- const { access_token, refresh_token } = await this.service.getPasswordToken();
421
- setTokens({
422
- accessToken: access_token,
423
- refreshToken: refresh_token
424
- });
425
- setOptions({
426
- clientId: this.options.clientId,
427
- host: this.options.host,
428
- redirectUri: "",
429
- clientSecret: this.options.clientSecret
430
- });
431
- }
432
- signOut() {
433
- this.clear();
434
- }
435
- clear() {
436
- clearTokens();
437
- clearOptions();
438
- clearNonce();
439
- }
440
- };
389
+ var PasswordFlow = class {
390
+ constructor(options) {
391
+ this.options = options;
392
+ this.service = new Gc2Service(options);
393
+ }
394
+ async signIn() {
395
+ const { access_token, refresh_token } = await this.service.getPasswordToken();
396
+ setTokens({
397
+ accessToken: access_token,
398
+ refreshToken: refresh_token
399
+ });
400
+ setOptions({
401
+ clientId: this.options.clientId,
402
+ host: this.options.host,
403
+ redirectUri: ""
404
+ });
405
+ }
406
+ signOut() {
407
+ this.clear();
408
+ }
409
+ clear() {
410
+ clearTokens();
411
+ clearOptions();
412
+ clearNonce();
413
+ }
414
+ };
441
415
 
442
416
  //#endregion
443
417
  //#region src/util/request-headers.ts
444
- /**
445
- * @author Martin Høgh <mh@mapcentia.com>
446
- * @copyright 2013-2026 MapCentia ApS
447
- * @license https://opensource.org/license/mit The MIT License
448
- *
449
- */
450
- const getHeaders = async (contentType = "application/json") => {
451
- if (!await isLogin(new Gc2Service(getOptions()))) return Promise.reject("Is not logged in");
452
- const { accessToken } = getTokens();
453
- const headers = {
454
- Accept: "application/json",
455
- Cookie: "XDEBUG_SESSION=XDEBUG_ECLIPSE",
456
- Authorization: accessToken ? "Bearer " + accessToken : null
457
- };
458
- if (contentType) headers["Content-Type"] = contentType;
459
- return headers;
418
+ const getHeaders = async (contentType = "application/json") => {
419
+ if (!await isLogin(new Gc2Service(getOptions()))) return Promise.reject("Is not logged in");
420
+ const { accessToken } = getTokens();
421
+ const headers = {
422
+ Accept: "application/json",
423
+ Cookie: "XDEBUG_SESSION=XDEBUG_ECLIPSE",
424
+ Authorization: accessToken ? "Bearer " + accessToken : null
460
425
  };
461
- var request_headers_default = getHeaders;
426
+ if (contentType) headers["Content-Type"] = contentType;
427
+ return headers;
428
+ };
429
+ var request_headers_default = getHeaders;
462
430
 
463
431
  //#endregion
464
432
  //#region src/util/make-request.ts
465
- /**
466
- * @author Martin Høgh <mh@mapcentia.com>
467
- * @copyright 2013-2026 MapCentia ApS
468
- * @license https://opensource.org/license/mit The MIT License
469
- *
470
- */
471
- const make = async (version, resource, method, payload, contentType = "application/json") => {
472
- const options = getOptions();
473
- let request = {
474
- method,
475
- headers: await request_headers_default(contentType),
476
- redirect: "manual"
477
- };
478
- if (payload) request.body = contentType === "application/json" ? JSON.stringify(payload) : payload;
479
- if (version !== null) return await fetch(options.host + `/api/v${version}/${resource}`, request);
480
- else return await fetch(options.host + `/api/${resource}`, request);
433
+ const make = async (version, resource, method, payload, contentType = "application/json") => {
434
+ const options = getOptions();
435
+ let request = {
436
+ method,
437
+ headers: await request_headers_default(contentType),
438
+ redirect: "manual"
481
439
  };
482
- var make_request_default = make;
440
+ if (payload) request.body = contentType === "application/json" ? JSON.stringify(payload) : payload;
441
+ return await fetch(options.host + `/api/v${version}/${resource}`, request);
442
+ };
443
+ var make_request_default = make;
483
444
 
484
445
  //#endregion
485
446
  //#region src/util/get-response.ts
486
- /**
487
- * @author Martin Høgh <mh@mapcentia.com>
488
- * @copyright 2013-2026 MapCentia ApS
489
- * @license https://opensource.org/license/mit The MIT License
490
- *
491
- */
492
- const get = async (response, expectedCode) => {
493
- let res = null;
494
- let bodyText = "";
495
- try {
496
- bodyText = await response.text();
497
- } catch (e) {}
498
- if (bodyText) try {
499
- res = JSON.parse(bodyText);
500
- } catch (e) {}
501
- if (response.status !== expectedCode) {
502
- const msg = res && (res.message || res.error) || bodyText || `Unexpected status ${response.status}`;
503
- throw new Error(msg);
504
- }
505
- return res;
506
- };
507
- var get_response_default = get;
447
+ const get = async (response, expectedCode) => {
448
+ let res = null;
449
+ let bodyText = "";
450
+ try {
451
+ bodyText = await response.text();
452
+ } catch (e) {}
453
+ if (bodyText) try {
454
+ res = JSON.parse(bodyText);
455
+ } catch (e) {}
456
+ if (response.status !== expectedCode) {
457
+ const msg = res && (res.message || res.error) || bodyText || `Unexpected status ${response.status}`;
458
+ throw new Error(msg);
459
+ }
460
+ return res;
461
+ };
462
+ var get_response_default = get;
508
463
 
509
464
  //#endregion
510
465
  //#region src/Sql.ts
511
- /**
512
- * @author Martin Høgh <mh@mapcentia.com>
513
- * @copyright 2013-2026 MapCentia ApS
514
- * @license https://opensource.org/license/mit The MIT License
515
- *
516
- */
517
- var Sql = class {
518
- async exec(request) {
519
- return await get_response_default(await make_request_default("4", `sql`, "POST", request), 200);
520
- }
521
- };
466
+ var Sql = class {
467
+ async exec(request) {
468
+ return await get_response_default(await make_request_default("4", `sql`, "POST", request), 200);
469
+ }
470
+ };
522
471
 
523
472
  //#endregion
524
473
  //#region src/Rpc.ts
525
- /**
526
- * @author Martin Høgh <mh@mapcentia.com>
527
- * @copyright 2013-2026 MapCentia ApS
528
- * @license https://opensource.org/license/mit The MIT License
529
- *
530
- */
531
- var Rpc = class {
532
- async call(request) {
533
- return await get_response_default(await make_request_default("4", `call`, "POST", request), 200);
534
- }
535
- };
536
-
537
- //#endregion
538
- //#region src/GraphQL.ts
539
- /**
540
- * @author Martin Høgh <mh@mapcentia.com>
541
- * @copyright 2013-2026 MapCentia ApS
542
- * @license https://opensource.org/license/mit The MIT License
543
- *
544
- */
545
- var GraphQL = class {
546
- async request(request) {
547
- return await get_response_default(await make_request_default(null, `graphql/schema/public`, "POST", request), 200);
548
- }
549
- };
474
+ var Rpc = class {
475
+ async call(request) {
476
+ return await get_response_default(await make_request_default("4", `call`, "POST", request), 200);
477
+ }
478
+ };
550
479
 
551
480
  //#endregion
552
481
  //#region src/Meta.ts
553
- /**
554
- * @author Martin Høgh <mh@mapcentia.com>
555
- * @copyright 2013-2026 MapCentia ApS
556
- * @license https://opensource.org/license/mit The MIT License
557
- *
558
- */
559
- var Meta = class {
560
- async query(rel) {
561
- return await get_response_default(await make_request_default("3", `meta/${rel}`, "GET", null), 200);
562
- }
563
- };
482
+ var Meta = class {
483
+ async query(rel) {
484
+ return await get_response_default(await make_request_default("3", `meta/${rel}`, "GET", null), 200);
485
+ }
486
+ };
564
487
 
565
488
  //#endregion
566
489
  //#region src/Status.ts
567
- /**
568
- * @author Martin Høgh <mh@mapcentia.com>
569
- * @copyright 2013-2026 MapCentia ApS
570
- * @license https://opensource.org/license/mit The MIT License
571
- *
572
- */
573
- var Status = class {
574
- isAuth() {
575
- const tokens = getTokens();
576
- return !(!tokens.accessToken && !tokens.refreshToken);
577
- }
578
- getTokens() {
579
- return getTokens();
580
- }
581
- };
490
+ var Status = class {
491
+ isAuth() {
492
+ const tokens = getTokens();
493
+ return !(!tokens.accessToken && !tokens.refreshToken);
494
+ }
495
+ getTokens() {
496
+ return getTokens();
497
+ }
498
+ };
582
499
 
583
500
  //#endregion
584
501
  //#region src/Claims.ts
585
- /**
586
- * @author Martin Høgh <mh@mapcentia.com>
587
- * @copyright 2013-2026 MapCentia ApS
588
- * @license https://opensource.org/license/mit The MIT License
589
- *
590
- */
591
- var Claims = class {
592
- get() {
593
- const tokens = getTokens().accessToken;
594
- return claims(tokens);
595
- }
596
- };
502
+ var Claims = class {
503
+ get() {
504
+ const tokens = getTokens().accessToken;
505
+ return claims(tokens);
506
+ }
507
+ };
597
508
 
598
509
  //#endregion
599
510
  //#region src/Users.ts
600
- /**
601
- * @author Martin Høgh <mh@mapcentia.com>
602
- * @copyright 2013-2026 MapCentia ApS
603
- * @license https://opensource.org/license/mit The MIT License
604
- *
605
- */
606
- var Users = class {
607
- async get(user) {
608
- return await get_response_default(await make_request_default("4", `users/${user}`, "GET", null), 200);
609
- }
610
- };
511
+ var Users = class {
512
+ async get(user) {
513
+ return await get_response_default(await make_request_default("4", `users/${user}`, "GET", null), 200);
514
+ }
515
+ };
611
516
 
612
517
  //#endregion
613
518
  //#region src/Ws.ts
614
- /**
615
- * @author Martin Høgh <mh@mapcentia.com>
616
- * @copyright 2013-2026 MapCentia ApS
617
- * @license https://opensource.org/license/mit The MIT License
618
- *
619
- */
620
- var Ws = class {
621
- constructor(options) {
622
- this.options = options;
623
- this.options.wsClient = this.options?.wsClient ?? WebSocket;
624
- }
625
- connect() {
626
- const me = this;
627
- const { accessToken } = getTokens();
628
- const connect = () => {
629
- let queryString = `?token=` + accessToken;
630
- if (this.options?.rel) queryString = queryString + `&rel=` + this.options.rel;
631
- const WSClass = this.options.wsClient;
632
- const ws = new WSClass(this.options.host + `/` + queryString);
633
- ws.onopen = function() {
634
- console.log("WebSocket connected!");
635
- };
636
- ws.onmessage = function(event) {
637
- me.options.callBack(event.data);
638
- };
639
- ws.onclose = function(event) {
640
- if (accessToken !== "") {
641
- console.log("WebSocket closed, reconnecting in 3 seconds...", event.reason);
642
- setTimeout(connect, 3e3);
643
- }
644
- };
645
- ws.onerror = function(err) {
646
- console.error("WebSocket error observed:", err);
647
- ws.close();
648
- };
519
+ var Ws = class {
520
+ constructor(options) {
521
+ this.options = options;
522
+ this.options.wsClient = this.options?.wsClient ?? WebSocket;
523
+ }
524
+ connect() {
525
+ const me = this;
526
+ const { accessToken } = getTokens();
527
+ const connect = () => {
528
+ let queryString = `?token=` + accessToken;
529
+ if (this.options?.rel) queryString = queryString + `&rel=` + this.options.rel;
530
+ const WSClass = this.options.wsClient;
531
+ const ws = new WSClass(this.options.host + `/` + queryString);
532
+ ws.onopen = function() {
533
+ console.log("WebSocket connected!");
649
534
  };
650
- if (accessToken !== "") connect();
651
- }
652
- };
535
+ ws.onmessage = function(event) {
536
+ me.options.callBack(event.data);
537
+ };
538
+ ws.onclose = function(event) {
539
+ if (accessToken !== "") {
540
+ console.log("WebSocket closed, reconnecting in 3 seconds...", event.reason);
541
+ setTimeout(connect, 3e3);
542
+ }
543
+ };
544
+ ws.onerror = function(err) {
545
+ console.error("WebSocket error observed:", err);
546
+ ws.close();
547
+ };
548
+ };
549
+ if (accessToken !== "") connect();
550
+ }
551
+ };
653
552
 
654
553
  //#endregion
655
554
  //#region src/Stats.ts
656
- /**
657
- * @author Martin Høgh <mh@mapcentia.com>
658
- * @copyright 2013-2026 MapCentia ApS
659
- * @license https://opensource.org/license/mit The MIT License
660
- *
661
- */
662
- var Stats = class {
663
- async get() {
664
- return await get_response_default(await make_request_default("4", `stats`, "GET", null), 200);
665
- }
666
- };
555
+ var Stats = class {
556
+ async get() {
557
+ return await get_response_default(await make_request_default("4", `stats`, "GET", null), 200);
558
+ }
559
+ };
667
560
 
668
561
  //#endregion
669
562
  //#region src/Tables.ts
670
- /**
671
- * @author Martin Høgh <mh@mapcentia.com>
672
- * @copyright 2013-2026 MapCentia ApS
673
- * @license https://opensource.org/license/mit The MIT License
674
- *
675
- */
676
- var Tables = class {
677
- async get(schema, table) {
678
- return await get_response_default(await make_request_default("4", `schemas/${encodeURIComponent(schema)}/tables/${encodeURIComponent(table)}`, "GET", null), 200);
679
- }
680
- async create(schema, table, payload) {
681
- return await get_response_default(await make_request_default("4", `schemas/${encodeURIComponent(schema)}/tables/${encodeURIComponent(table)}`, "POST", payload), 200);
682
- }
683
- async patch(schema, table, payload) {
684
- return await get_response_default(await make_request_default("4", `schemas/${encodeURIComponent(schema)}/tables/${encodeURIComponent(table)}`, "PATCH", payload), 200);
685
- }
686
- async delete(schema, table) {
687
- return await get_response_default(await make_request_default("4", `schemas/${encodeURIComponent(schema)}/tables/${encodeURIComponent(table)}`, "DELETE", null), 204);
688
- }
689
- };
563
+ var Tables = class {
564
+ async get(schema, table) {
565
+ return await get_response_default(await make_request_default("4", `schemas/${encodeURIComponent(schema)}/tables/${encodeURIComponent(table)}`, "GET", null), 200);
566
+ }
567
+ async create(schema, table, payload) {
568
+ return await get_response_default(await make_request_default("4", `schemas/${encodeURIComponent(schema)}/tables/${encodeURIComponent(table)}`, "POST", payload), 200);
569
+ }
570
+ async patch(schema, table, payload) {
571
+ return await get_response_default(await make_request_default("4", `schemas/${encodeURIComponent(schema)}/tables/${encodeURIComponent(table)}`, "PATCH", payload), 200);
572
+ }
573
+ async delete(schema, table) {
574
+ return await get_response_default(await make_request_default("4", `schemas/${encodeURIComponent(schema)}/tables/${encodeURIComponent(table)}`, "DELETE", null), 204);
575
+ }
576
+ };
690
577
 
691
578
  //#endregion
692
579
  //#region src/Api.ts
693
- /**
694
- * @author Martin Høgh <mh@mapcentia.com>
695
- * @copyright 2013-2026 MapCentia ApS
696
- * @license https://opensource.org/license/mit The MIT License
697
- *
698
- */
699
- function isPlainObject$1(v) {
700
- return typeof v === "object" && v !== null && !Array.isArray(v);
701
- }
702
- function validateParamsForMethod(method, params) {
703
- if (Array.isArray(params)) {
704
- const badIndex = params.findIndex((p) => !isPlainObject$1(p));
705
- if (badIndex !== -1) throw new TypeError(`createApi: Invalid argument at index ${badIndex} for RPC method "${method}". Expected a plain object.`);
706
- return params;
707
- }
708
- if (params === void 0) return {};
709
- if (!isPlainObject$1(params)) throw new TypeError(`createApi: Invalid argument for RPC method "${method}". Expected a plain object.`);
580
+ function isPlainObject$1(v) {
581
+ return typeof v === "object" && v !== null && !Array.isArray(v);
582
+ }
583
+ function validateParamsForMethod(method, params) {
584
+ if (Array.isArray(params)) {
585
+ const badIndex = params.findIndex((p) => !isPlainObject$1(p));
586
+ if (badIndex !== -1) throw new TypeError(`createApi: Invalid argument at index ${badIndex} for RPC method "${method}". Expected a plain object.`);
710
587
  return params;
711
588
  }
712
- function extractDataFromResponse(method, res) {
713
- if (!res || typeof res !== "object") throw new TypeError(`createApi: Invalid RPC response for method "${method}". Expected an object.`);
714
- if (res.jsonrpc !== "2.0") throw new TypeError(`createApi: Invalid RPC response for method "${method}". Missing or invalid jsonrpc version.`);
715
- const err = res.error;
716
- if (err !== void 0) {
717
- if (!err || typeof err !== "object") throw new TypeError(`createApi: Invalid RPC error for method "${method}". Expected 'error' to be an object.`);
718
- const code = err.code;
719
- const message = err.message;
720
- const data$1 = err.data;
721
- const codeIsNum = typeof code === "number" && Number.isFinite(code);
722
- const details = typeof message === "string" && message.length > 0 ? message : "Unknown error";
723
- const e = /* @__PURE__ */ new Error(`createApi: RPC error for method "${method}"${codeIsNum ? ` (${code})` : ""}: ${details}`);
724
- e.code = code;
725
- if (data$1 !== void 0) e.data = data$1;
726
- e.method = method;
727
- e.name = "JsonRpcError";
728
- throw e;
729
- }
730
- const result = res.result;
731
- if (!result || typeof result !== "object") throw new TypeError(`createApi: Invalid RPC response for method "${method}". Missing result object.`);
732
- const data = result.data;
733
- if (!Array.isArray(data)) throw new TypeError(`createApi: Invalid RPC response for method "${method}". Expected result.data to be an array.`);
734
- return data;
735
- }
736
- async function dispatch(name, paramsLike) {
737
- if (typeof name !== "string" || name.length === 0) throw new TypeError("createApi: RPC method name must be a non-empty string.");
738
- const params = validateParamsForMethod(String(name), paramsLike);
739
- const rpc = new Rpc();
740
- const request = {
741
- jsonrpc: "2.0",
742
- method: name,
743
- id: 1,
744
- params
745
- };
746
- const res = await rpc.call(request);
747
- return extractDataFromResponse(String(name), res);
748
- }
749
- function createApi() {
750
- return new Proxy({}, { get(_target, prop) {
751
- if (typeof prop !== "string") return void 0;
752
- return (...args) => {
753
- return dispatch(prop, args.length === 0 ? {} : args.length === 1 ? args[0] : args);
754
- };
755
- } });
589
+ if (params === void 0) return {};
590
+ if (!isPlainObject$1(params)) throw new TypeError(`createApi: Invalid argument for RPC method "${method}". Expected a plain object.`);
591
+ return params;
592
+ }
593
+ function extractDataFromResponse(method, res) {
594
+ if (!res || typeof res !== "object") throw new TypeError(`createApi: Invalid RPC response for method "${method}". Expected an object.`);
595
+ if (res.jsonrpc !== "2.0") throw new TypeError(`createApi: Invalid RPC response for method "${method}". Missing or invalid jsonrpc version.`);
596
+ const err = res.error;
597
+ if (err !== void 0) {
598
+ if (!err || typeof err !== "object") throw new TypeError(`createApi: Invalid RPC error for method "${method}". Expected 'error' to be an object.`);
599
+ const code = err.code;
600
+ const message = err.message;
601
+ const data$1 = err.data;
602
+ const codeIsNum = typeof code === "number" && Number.isFinite(code);
603
+ const details = typeof message === "string" && message.length > 0 ? message : "Unknown error";
604
+ const e = /* @__PURE__ */ new Error(`createApi: RPC error for method "${method}"${codeIsNum ? ` (${code})` : ""}: ${details}`);
605
+ e.code = code;
606
+ if (data$1 !== void 0) e.data = data$1;
607
+ e.method = method;
608
+ e.name = "JsonRpcError";
609
+ throw e;
756
610
  }
611
+ const result = res.result;
612
+ if (!result || typeof result !== "object") throw new TypeError(`createApi: Invalid RPC response for method "${method}". Missing result object.`);
613
+ const data = result.data;
614
+ if (!Array.isArray(data)) throw new TypeError(`createApi: Invalid RPC response for method "${method}". Expected result.data to be an array.`);
615
+ return data;
616
+ }
617
+ async function dispatch(name, paramsLike) {
618
+ if (typeof name !== "string" || name.length === 0) throw new TypeError("createApi: RPC method name must be a non-empty string.");
619
+ const params = validateParamsForMethod(String(name), paramsLike);
620
+ const rpc = new Rpc();
621
+ const request = {
622
+ jsonrpc: "2.0",
623
+ method: name,
624
+ id: 1,
625
+ params
626
+ };
627
+ const res = await rpc.call(request);
628
+ return extractDataFromResponse(String(name), res);
629
+ }
630
+ function createApi() {
631
+ return new Proxy({}, { get(_target, prop) {
632
+ if (typeof prop !== "string") return void 0;
633
+ return (...args) => {
634
+ return dispatch(prop, args.length === 0 ? {} : args.length === 1 ? args[0] : args);
635
+ };
636
+ } });
637
+ }
757
638
 
758
639
  //#endregion
759
640
  //#region src/SignUp.ts
760
- /**
761
- * @author Martin Høgh <mh@mapcentia.com>
762
- * @copyright 2013-2026 MapCentia ApS
763
- * @license https://opensource.org/license/mit The MIT License
764
- *
765
- */
766
- var SignUp = class {
767
- constructor(options) {
768
- this.options = options;
769
- this.service = new Gc2Service(options);
770
- }
771
- async signUp() {
772
- window.location.assign(this.service.getSignUpURL());
773
- }
774
- };
641
+ var SignUp = class {
642
+ constructor(options) {
643
+ this.options = options;
644
+ this.service = new Gc2Service(options);
645
+ }
646
+ async signUp() {
647
+ window.location.assign(this.service.getSignUpURL());
648
+ }
649
+ };
775
650
 
776
651
  //#endregion
777
652
  //#region src/SqlBuilder.ts
778
- function findTable(schema, name) {
779
- const tbl = schema.tables.find((t) => t.name === name);
780
- if (!tbl) throw new Error(`Table not found in schema: ${name}`);
781
- return tbl;
782
- }
783
- function findColumn(table, name) {
784
- const col = table.columns.find((c) => c.name === name);
785
- if (!col) throw new Error(`Column not found in table ${table.name}: ${name}`);
786
- return col;
787
- }
788
- function getPrimaryKeyColumns(table) {
789
- const pk = (table.constraints || []).find((c) => c.constraint === "primary" && Array.isArray(c.columns) && c.columns.length > 0);
790
- return pk ? pk.columns.map(String) : [];
791
- }
792
- function typeNameToHint(typname, isArray) {
793
- if (!typname) return void 0;
794
- const base = typname;
795
- return isArray ? base + "[]" : base;
796
- }
797
- function addTypeHintForParam(typeHints, paramName, col, value) {
798
- let isArr = col._is_array;
799
- if (Array.isArray(value)) if (isArrayShapedGeomTypename(col._typname)) isArr = value.every(Array.isArray);
800
- else isArr = true;
801
- const hint = typeNameToHint(col._typname, isArr);
802
- if (hint) typeHints[paramName] = hint;
803
- }
804
- function expectedScalarKind(typname) {
805
- const t = typname.toLowerCase();
806
- if (t === "int2" || t === "int4" || t === "int8" || t === "float4" || t === "float8") return "number";
807
- if (t === "numeric" || t === "decimal") return "string";
808
- if (t === "varchar" || t === "text" || t === "bpchar" || t === "char" || t === "date" || t === "time" || t === "timetz" || t === "timestamp" || t === "timestamptz") return "string";
809
- if (t === "bool") return "boolean";
810
- if (t === "json" || t === "jsonb") return "json";
811
- if (t === "int4range" || t === "int8range" || t === "numrange" || t === "tsrange" || t === "tstzrange" || t === "daterange") return "range";
812
- if (t === "interval") return "interval";
813
- if (t === "point" || t === "line" || t === "lseg" || t === "box" || t === "path" || t === "polygon" || t === "circle") return "geom";
814
- return "unknown";
815
- }
816
- function isArrayShapedGeomTypename(typname) {
817
- const t = typname.toLowerCase();
818
- return t === "path" || t === "polygon";
819
- }
820
- function isArrayShapedGeomScalarValue(col, value) {
821
- if (!Array.isArray(value)) return false;
822
- if (!isArrayShapedGeomTypename(col._typname)) return false;
823
- return !value.every(Array.isArray);
824
- }
825
- function expectedRangeInnerKind(typname) {
826
- const t = typname.toLowerCase();
827
- if (t === "int4range" || t === "int8range") return "number";
828
- if (t === "numrange" || t === "tsrange" || t === "tstzrange" || t === "daterange") return "string";
829
- return "unknown";
830
- }
831
- function isPlainObject(v) {
832
- return typeof v === "object" && v !== null && !Array.isArray(v);
833
- }
834
- function isFiniteNumber(n) {
835
- return typeof n === "number" && Number.isFinite(n);
836
- }
837
- function isPointLike(v) {
838
- if (!isPlainObject(v)) return false;
839
- const x = v.x;
840
- const y = v.y;
841
- return isFiniteNumber(x) && isFiniteNumber(y);
842
- }
843
- function validateGeometryForColumn(col, value, context) {
844
- const t = col._typname.toLowerCase();
845
- if (t === "point") {
846
- if (!isPointLike(value)) throw new Error(`Invalid value for ${context}. Expected Point { x: number, y: number }`);
847
- return;
848
- }
849
- if (t === "line") {
850
- if (!isPlainObject(value)) throw new Error(`Invalid value for ${context}. Expected Line { A: number, B: number, C: number }`);
851
- const A = value.A, B = value.B, C = value.C;
852
- if (!isFiniteNumber(A) || !isFiniteNumber(B) || !isFiniteNumber(C)) throw new Error(`Invalid Line for ${context}. A, B, C must be finite numbers`);
853
- return;
854
- }
855
- if (t === "lseg" || t === "box") {
856
- if (!isPlainObject(value)) throw new Error(`Invalid value for ${context}. Expected ${t.toUpperCase()} { start: Point, end: Point }`);
857
- const start = value.start;
858
- const end = value.end;
859
- if (!isPointLike(start) || !isPointLike(end)) throw new Error(`Invalid ${t} for ${context}. 'start' and 'end' must be Point { x, y }`);
860
- return;
861
- }
862
- if (t === "path") {
863
- if (!Array.isArray(value) || value.length < 1) throw new Error(`Invalid value for ${context}. Expected Path [isClosed: boolean, ...points: Point[]]`);
864
- const [isClosed, ...points] = value;
865
- if (typeof isClosed !== "boolean") throw new Error(`Invalid Path for ${context}. First element must be boolean (isClosed)`);
866
- 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 }`);
867
- return;
868
- }
869
- if (t === "polygon") {
870
- if (!Array.isArray(value)) throw new Error(`Invalid value for ${context}. Expected Polygon as Point[]`);
871
- 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 }`);
872
- return;
873
- }
874
- if (t === "circle") {
875
- if (!isPlainObject(value)) throw new Error(`Invalid value for ${context}. Expected Circle { center: Point, radius: number }`);
876
- const center = value.center;
877
- const radius = value.radius;
878
- if (!isPointLike(center) || !isFiniteNumber(radius)) throw new Error(`Invalid Circle for ${context}. 'center' must be Point and 'radius' must be finite number`);
879
- return;
880
- }
653
+ function findTable(schema, name) {
654
+ const tbl = schema.tables.find((t) => t.name === name);
655
+ if (!tbl) throw new Error(`Table not found in schema: ${name}`);
656
+ return tbl;
657
+ }
658
+ function findColumn(table, name) {
659
+ const col = table.columns.find((c) => c.name === name);
660
+ if (!col) throw new Error(`Column not found in table ${table.name}: ${name}`);
661
+ return col;
662
+ }
663
+ function getPrimaryKeyColumns(table) {
664
+ const pk = (table.constraints || []).find((c) => c.constraint === "primary" && Array.isArray(c.columns) && c.columns.length > 0);
665
+ return pk ? pk.columns.map(String) : [];
666
+ }
667
+ function typeNameToHint(typname, isArray) {
668
+ if (!typname) return void 0;
669
+ const base = typname;
670
+ return isArray ? base + "[]" : base;
671
+ }
672
+ function addTypeHintForParam(typeHints, paramName, col, value) {
673
+ let isArr = col._is_array;
674
+ if (Array.isArray(value)) if (isArrayShapedGeomTypename(col._typname)) isArr = value.every(Array.isArray);
675
+ else isArr = true;
676
+ const hint = typeNameToHint(col._typname, isArr);
677
+ if (hint) typeHints[paramName] = hint;
678
+ }
679
+ function expectedScalarKind(typname) {
680
+ const t = typname.toLowerCase();
681
+ if (t === "int2" || t === "int4" || t === "int8" || t === "float4" || t === "float8") return "number";
682
+ if (t === "numeric" || t === "decimal") return "string";
683
+ if (t === "varchar" || t === "text" || t === "bpchar" || t === "char" || t === "date" || t === "time" || t === "timetz" || t === "timestamp" || t === "timestamptz") return "string";
684
+ if (t === "bool") return "boolean";
685
+ if (t === "json" || t === "jsonb") return "json";
686
+ if (t === "int4range" || t === "int8range" || t === "numrange" || t === "tsrange" || t === "tstzrange" || t === "daterange") return "range";
687
+ if (t === "interval") return "interval";
688
+ if (t === "point" || t === "line" || t === "lseg" || t === "box" || t === "path" || t === "polygon" || t === "circle") return "geom";
689
+ return "unknown";
690
+ }
691
+ function isArrayShapedGeomTypename(typname) {
692
+ const t = typname.toLowerCase();
693
+ return t === "path" || t === "polygon";
694
+ }
695
+ function isArrayShapedGeomScalarValue(col, value) {
696
+ if (!Array.isArray(value)) return false;
697
+ if (!isArrayShapedGeomTypename(col._typname)) return false;
698
+ return !value.every(Array.isArray);
699
+ }
700
+ function expectedRangeInnerKind(typname) {
701
+ const t = typname.toLowerCase();
702
+ if (t === "int4range" || t === "int8range") return "number";
703
+ if (t === "numrange" || t === "tsrange" || t === "tstzrange" || t === "daterange") return "string";
704
+ return "unknown";
705
+ }
706
+ function isPlainObject(v) {
707
+ return typeof v === "object" && v !== null && !Array.isArray(v);
708
+ }
709
+ function isFiniteNumber(n) {
710
+ return typeof n === "number" && Number.isFinite(n);
711
+ }
712
+ function isPointLike(v) {
713
+ if (!isPlainObject(v)) return false;
714
+ const x = v.x;
715
+ const y = v.y;
716
+ return isFiniteNumber(x) && isFiniteNumber(y);
717
+ }
718
+ function validateGeometryForColumn(col, value, context) {
719
+ const t = col._typname.toLowerCase();
720
+ if (t === "point") {
721
+ if (!isPointLike(value)) throw new Error(`Invalid value for ${context}. Expected Point { x: number, y: number }`);
722
+ return;
881
723
  }
882
- function validateRangeForColumn(col, value, context) {
883
- if (!isPlainObject(value)) throw new Error(`Invalid value for ${context}. Expected a range object for type ${col._typname}`);
884
- const r = value;
885
- const hasLower = Object.prototype.hasOwnProperty.call(r, "lower");
886
- const hasUpper = Object.prototype.hasOwnProperty.call(r, "upper");
887
- const hasLi = Object.prototype.hasOwnProperty.call(r, "lowerInclusive");
888
- const hasUi = Object.prototype.hasOwnProperty.call(r, "upperInclusive");
889
- if (!hasLower || !hasUpper || !hasLi || !hasUi) throw new Error(`Invalid range for ${context}. Required properties: lower, upper, lowerInclusive, upperInclusive`);
890
- if (typeof r.lowerInclusive !== "boolean" || typeof r.upperInclusive !== "boolean") throw new Error(`Invalid range for ${context}. lowerInclusive and upperInclusive must be boolean`);
891
- const inner = expectedRangeInnerKind(col._typname);
892
- if (inner === "number") {
893
- if (typeof r.lower !== "number" || !Number.isFinite(r.lower)) throw new Error(`Invalid range.lower for ${context}. Expected number for type ${col._typname}`);
894
- if (typeof r.upper !== "number" || !Number.isFinite(r.upper)) throw new Error(`Invalid range.upper for ${context}. Expected number for type ${col._typname}`);
895
- } else if (inner === "string") {
896
- if (typeof r.lower !== "string") throw new Error(`Invalid range.lower for ${context}. Expected string for type ${col._typname}`);
897
- if (typeof r.upper !== "string") throw new Error(`Invalid range.upper for ${context}. Expected string for type ${col._typname}`);
898
- }
724
+ if (t === "line") {
725
+ if (!isPlainObject(value)) throw new Error(`Invalid value for ${context}. Expected Line { A: number, B: number, C: number }`);
726
+ const A = value.A, B = value.B, C = value.C;
727
+ if (!isFiniteNumber(A) || !isFiniteNumber(B) || !isFiniteNumber(C)) throw new Error(`Invalid Line for ${context}. A, B, C must be finite numbers`);
728
+ return;
899
729
  }
900
- function validateIntervalForColumn(col, value, context) {
901
- if (!isPlainObject(value)) throw new Error(`Invalid value for ${context}. Expected an interval object for type ${col._typname}`);
902
- const v = value;
903
- for (const k of [
904
- "y",
905
- "m",
906
- "d",
907
- "h",
908
- "i",
909
- "s"
910
- ]) {
911
- if (!Object.prototype.hasOwnProperty.call(v, k)) throw new Error(`Invalid interval for ${context}. Missing property '${k}'`);
912
- const num = v[k];
913
- if (typeof num !== "number" || !Number.isFinite(num)) throw new Error(`Invalid interval.${String(k)} for ${context}. Expected finite number`);
914
- }
730
+ if (t === "lseg" || t === "box") {
731
+ if (!isPlainObject(value)) throw new Error(`Invalid value for ${context}. Expected ${t.toUpperCase()} { start: Point, end: Point }`);
732
+ const start = value.start;
733
+ const end = value.end;
734
+ if (!isPointLike(start) || !isPointLike(end)) throw new Error(`Invalid ${t} for ${context}. 'start' and 'end' must be Point { x, y }`);
735
+ return;
915
736
  }
916
- function isValidJsonLike(value) {
917
- return value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean" || typeof value === "object" && value !== null;
737
+ if (t === "path") {
738
+ if (!Array.isArray(value) || value.length < 1) throw new Error(`Invalid value for ${context}. Expected Path [isClosed: boolean, ...points: Point[]]`);
739
+ const [isClosed, ...points] = value;
740
+ if (typeof isClosed !== "boolean") throw new Error(`Invalid Path for ${context}. First element must be boolean (isClosed)`);
741
+ 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 }`);
742
+ return;
918
743
  }
919
- function validateScalarForColumn(col, value, context) {
920
- const kind = expectedScalarKind(col._typname);
921
- if (kind === "unknown") return;
922
- if (kind === "number") {
923
- if (typeof value !== "number" || !Number.isFinite(value)) throw new Error(`Invalid value for ${context}. Expected number for type ${col._typname}, got ${typeof value}`);
924
- return;
925
- }
926
- if (kind === "string") {
927
- if (typeof value !== "string") throw new Error(`Invalid value for ${context}. Expected string for type ${col._typname}, got ${typeof value}`);
928
- return;
929
- }
930
- if (kind === "boolean") {
931
- if (typeof value !== "boolean") throw new Error(`Invalid value for ${context}. Expected boolean for type ${col._typname}, got ${typeof value}`);
932
- return;
933
- }
934
- if (kind === "json") {
935
- if (!isValidJsonLike(value)) throw new Error(`Invalid value for ${context}. Expected JSON-compatible value for type ${col._typname}`);
936
- return;
937
- }
938
- if (kind === "range") {
939
- validateRangeForColumn(col, value, context);
940
- return;
941
- }
942
- if (kind === "interval") {
943
- validateIntervalForColumn(col, value, context);
944
- return;
945
- }
946
- if (kind === "geom") {
947
- validateGeometryForColumn(col, value, context);
948
- return;
949
- }
744
+ if (t === "polygon") {
745
+ if (!Array.isArray(value)) throw new Error(`Invalid value for ${context}. Expected Polygon as Point[]`);
746
+ 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 }`);
747
+ return;
950
748
  }
951
- function validateComparisonValue(col, key, value, op) {
952
- 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.`);
953
- if (col._is_array) {
954
- if (!Array.isArray(value)) throw new Error(`Operator ${op} on array column ${key} requires an array value`);
955
- for (const [i, v] of value.entries()) validateScalarForColumn(col, v, `column ${key}[${i}]`);
956
- } else {
957
- if (Array.isArray(value) && !isArrayShapedGeomScalarValue(col, value)) throw new Error(`Operator ${op} on scalar column ${key} cannot accept an array value`);
958
- validateScalarForColumn(col, value, `column ${key}`);
959
- }
749
+ if (t === "circle") {
750
+ if (!isPlainObject(value)) throw new Error(`Invalid value for ${context}. Expected Circle { center: Point, radius: number }`);
751
+ const center = value.center;
752
+ const radius = value.radius;
753
+ if (!isPointLike(center) || !isFiniteNumber(radius)) throw new Error(`Invalid Circle for ${context}. 'center' must be Point and 'radius' must be finite number`);
754
+ return;
960
755
  }
961
- function validateInArrayValues(col, key, values, op) {
962
- if (!col._is_array) {
963
- let idx = 0;
964
- for (const v of values) {
965
- validateScalarForColumn(col, v, `column ${key} (element ${idx})`);
966
- idx++;
967
- }
968
- }
756
+ }
757
+ function validateRangeForColumn(col, value, context) {
758
+ if (!isPlainObject(value)) throw new Error(`Invalid value for ${context}. Expected a range object for type ${col._typname}`);
759
+ const r = value;
760
+ const hasLower = Object.prototype.hasOwnProperty.call(r, "lower");
761
+ const hasUpper = Object.prototype.hasOwnProperty.call(r, "upper");
762
+ const hasLi = Object.prototype.hasOwnProperty.call(r, "lowerInclusive");
763
+ const hasUi = Object.prototype.hasOwnProperty.call(r, "upperInclusive");
764
+ if (!hasLower || !hasUpper || !hasLi || !hasUi) throw new Error(`Invalid range for ${context}. Required properties: lower, upper, lowerInclusive, upperInclusive`);
765
+ if (typeof r.lowerInclusive !== "boolean" || typeof r.upperInclusive !== "boolean") throw new Error(`Invalid range for ${context}. lowerInclusive and upperInclusive must be boolean`);
766
+ const inner = expectedRangeInnerKind(col._typname);
767
+ if (inner === "number") {
768
+ if (typeof r.lower !== "number" || !Number.isFinite(r.lower)) throw new Error(`Invalid range.lower for ${context}. Expected number for type ${col._typname}`);
769
+ if (typeof r.upper !== "number" || !Number.isFinite(r.upper)) throw new Error(`Invalid range.upper for ${context}. Expected number for type ${col._typname}`);
770
+ } else if (inner === "string") {
771
+ if (typeof r.lower !== "string") throw new Error(`Invalid range.lower for ${context}. Expected string for type ${col._typname}`);
772
+ if (typeof r.upper !== "string") throw new Error(`Invalid range.upper for ${context}. Expected string for type ${col._typname}`);
773
+ }
774
+ }
775
+ function validateIntervalForColumn(col, value, context) {
776
+ if (!isPlainObject(value)) throw new Error(`Invalid value for ${context}. Expected an interval object for type ${col._typname}`);
777
+ const v = value;
778
+ for (const k of [
779
+ "y",
780
+ "m",
781
+ "d",
782
+ "h",
783
+ "i",
784
+ "s"
785
+ ]) {
786
+ if (!Object.prototype.hasOwnProperty.call(v, k)) throw new Error(`Invalid interval for ${context}. Missing property '${k}'`);
787
+ const num = v[k];
788
+ if (typeof num !== "number" || !Number.isFinite(num)) throw new Error(`Invalid interval.${String(k)} for ${context}. Expected finite number`);
789
+ }
790
+ }
791
+ function isValidJsonLike(value) {
792
+ return value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean" || typeof value === "object" && value !== null;
793
+ }
794
+ function validateScalarForColumn(col, value, context) {
795
+ const kind = expectedScalarKind(col._typname);
796
+ if (kind === "unknown") return;
797
+ if (kind === "number") {
798
+ if (typeof value !== "number" || !Number.isFinite(value)) throw new Error(`Invalid value for ${context}. Expected number for type ${col._typname}, got ${typeof value}`);
799
+ return;
800
+ }
801
+ if (kind === "string") {
802
+ if (typeof value !== "string") throw new Error(`Invalid value for ${context}. Expected string for type ${col._typname}, got ${typeof value}`);
803
+ return;
969
804
  }
970
- function findJoinOn(base, target) {
971
- const bc = base.constraints || [];
972
- const tc = target.constraints || [];
973
- 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) => ({
974
- left: String(col),
975
- right: String(c.referenced_columns[i])
976
- }));
977
- 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) => ({
978
- left: String(rcol),
979
- right: String(c.columns[i])
980
- }));
981
- return null;
982
- }
983
- var TableQueryImpl = class {
984
- constructor(schema, tableName) {
985
- this.schema = schema;
986
- this.table = findTable(schema, tableName);
805
+ if (kind === "boolean") {
806
+ if (typeof value !== "boolean") throw new Error(`Invalid value for ${context}. Expected boolean for type ${col._typname}, got ${typeof value}`);
807
+ return;
808
+ }
809
+ if (kind === "json") {
810
+ if (!isValidJsonLike(value)) throw new Error(`Invalid value for ${context}. Expected JSON-compatible value for type ${col._typname}`);
811
+ return;
812
+ }
813
+ if (kind === "range") {
814
+ validateRangeForColumn(col, value, context);
815
+ return;
816
+ }
817
+ if (kind === "interval") {
818
+ validateIntervalForColumn(col, value, context);
819
+ return;
820
+ }
821
+ if (kind === "geom") {
822
+ validateGeometryForColumn(col, value, context);
823
+ return;
824
+ }
825
+ }
826
+ function validateComparisonValue(col, key, value, op) {
827
+ 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.`);
828
+ if (col._is_array) {
829
+ if (!Array.isArray(value)) throw new Error(`Operator ${op} on array column ${key} requires an array value`);
830
+ for (const [i, v] of value.entries()) validateScalarForColumn(col, v, `column ${key}[${i}]`);
831
+ } else {
832
+ if (Array.isArray(value) && !isArrayShapedGeomScalarValue(col, value)) throw new Error(`Operator ${op} on scalar column ${key} cannot accept an array value`);
833
+ validateScalarForColumn(col, value, `column ${key}`);
834
+ }
835
+ }
836
+ function validateInArrayValues(col, key, values, op) {
837
+ if (!col._is_array) {
838
+ let idx = 0;
839
+ for (const v of values) {
840
+ validateScalarForColumn(col, v, `column ${key} (element ${idx})`);
841
+ idx++;
987
842
  }
988
- select(cols) {
989
- const table = this.table;
990
- const schema = this.schema;
991
- const selected = cols && cols.length ? cols : ["*"];
992
- const state = {
993
- table,
994
- selected,
995
- where: {},
996
- orWhereGroups: [],
997
- andOps: [],
998
- orOpGroups: [],
999
- order: [],
1000
- limit: void 0,
1001
- offset: void 0,
1002
- joins: [],
1003
- joinSelections: []
1004
- };
1005
- return new class {
1006
- constructor() {
1007
- this.s = state;
1008
- this.toSql = () => {
1009
- const params = {};
1010
- const type_hints = {};
1011
- let p = 0;
1012
- const parts = [];
1013
- const selectParts = [];
1014
- if (selected.length === 1 && selected[0] === "*") selectParts.push(`"${table.name}".*`);
1015
- else {
1016
- const sel = selected;
1017
- for (const c of sel) findColumn(table, String(c));
1018
- selectParts.push(sel.map((c) => `"${table.name}"."${c}"`).join(", "));
1019
- }
1020
- for (const js of state.joinSelections) if (js.selected.length === 1 && js.selected[0] === "*") selectParts.push(`"${js.target.name}".*`);
1021
- else {
1022
- const cols$1 = js.selected;
1023
- for (const c of cols$1) findColumn(js.target, String(c));
1024
- selectParts.push(cols$1.map((c) => `"${js.target.name}"."${c}"`).join(", "));
843
+ }
844
+ }
845
+ function findJoinOn(base, target) {
846
+ const bc = base.constraints || [];
847
+ const tc = target.constraints || [];
848
+ 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) => ({
849
+ left: String(col),
850
+ right: String(c.referenced_columns[i])
851
+ }));
852
+ 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) => ({
853
+ left: String(rcol),
854
+ right: String(c.columns[i])
855
+ }));
856
+ return null;
857
+ }
858
+ var TableQueryImpl = class {
859
+ constructor(schema, tableName) {
860
+ this.schema = schema;
861
+ this.table = findTable(schema, tableName);
862
+ }
863
+ select(cols) {
864
+ const table = this.table;
865
+ const schema = this.schema;
866
+ const selected = cols && cols.length ? cols : ["*"];
867
+ const state = {
868
+ table,
869
+ selected,
870
+ where: {},
871
+ orWhereGroups: [],
872
+ andOps: [],
873
+ orOpGroups: [],
874
+ order: [],
875
+ limit: void 0,
876
+ offset: void 0,
877
+ joins: [],
878
+ joinSelections: []
879
+ };
880
+ return new class {
881
+ constructor() {
882
+ this.s = state;
883
+ this.toSql = () => {
884
+ const params = {};
885
+ const type_hints = {};
886
+ let p = 0;
887
+ const parts = [];
888
+ const selectParts = [];
889
+ if (selected.length === 1 && selected[0] === "*") selectParts.push(`"${table.name}".*`);
890
+ else {
891
+ const sel = selected;
892
+ for (const c of sel) findColumn(table, String(c));
893
+ selectParts.push(sel.map((c) => `"${table.name}"."${c}"`).join(", "));
894
+ }
895
+ for (const js of state.joinSelections) if (js.selected.length === 1 && js.selected[0] === "*") selectParts.push(`"${js.target.name}".*`);
896
+ else {
897
+ const cols$1 = js.selected;
898
+ for (const c of cols$1) findColumn(js.target, String(c));
899
+ selectParts.push(cols$1.map((c) => `"${js.target.name}"."${c}"`).join(", "));
900
+ }
901
+ parts.push(`select ${selectParts.join(", ")} from "${schema.name}"."${table.name}"`);
902
+ for (const j of state.joins) {
903
+ const onExpr = j.on.map((p$1) => `"${j.source.name}"."${p$1.left}" = "${j.target.name}"."${p$1.right}"`).join(" and ");
904
+ parts.push(`${j.type} join "${schema.name}"."${j.target.name}" on ${onExpr}`);
905
+ }
906
+ const andParts = [];
907
+ for (const key in state.where) {
908
+ const value = state.where[key];
909
+ const col = findColumn(table, key);
910
+ p += 1;
911
+ const paramName = `${table.name}_${key}_${p}`;
912
+ if (value === null) {
913
+ if (!col.is_nullable) throw new Error(`Column ${table.name}.${key} is not nullable; cannot compare to null`);
914
+ andParts.push(`"${table.name}"."${key}" is null`);
915
+ } else if (Array.isArray(value) && !isArrayShapedGeomScalarValue(col, value)) {
916
+ validateInArrayValues(col, key, value, "in");
917
+ andParts.push(`"${table.name}"."${key}" = ANY(:${paramName})`);
918
+ params[paramName] = value;
919
+ addTypeHintForParam(type_hints, paramName, col, value);
920
+ } else {
921
+ validateScalarForColumn(col, value, `column ${key}`);
922
+ andParts.push(`"${table.name}"."${key}" = :${paramName}`);
923
+ params[paramName] = value;
924
+ addTypeHintForParam(type_hints, paramName, col, value);
1025
925
  }
1026
- parts.push(`select ${selectParts.join(", ")} from "${schema.name}"."${table.name}"`);
1027
- for (const j of state.joins) {
1028
- const onExpr = j.on.map((p$1) => `"${j.source.name}"."${p$1.left}" = "${j.target.name}"."${p$1.right}"`).join(" and ");
1029
- parts.push(`${j.type} join "${schema.name}"."${j.target.name}" on ${onExpr}`);
926
+ }
927
+ for (const pred of state.andOps) {
928
+ const key = String(pred.col);
929
+ const op = String(pred.op);
930
+ const col = findColumn(table, key);
931
+ const qualified = `"${table.name}"."${key}"`;
932
+ if (op === "isnull" || op === "notnull") {
933
+ if (pred.value !== void 0) throw new Error(`Operator ${op} does not take a value for column ${key}`);
934
+ andParts.push(`${qualified} is ${op === "isnull" ? "null" : "not null"}`);
935
+ } else if (op === "in" || op === "notin") {
936
+ const val = pred.value;
937
+ if (!Array.isArray(val)) throw new Error(`Operator ${op} requires an array value for column ${key}`);
938
+ validateInArrayValues(col, key, val, op);
939
+ p += 1;
940
+ const paramName = `${table.name}_${key}_${p}`;
941
+ andParts.push(`${qualified} ${op === "in" ? "= ANY" : "!= ALL"}(:${paramName})`);
942
+ params[paramName] = val;
943
+ addTypeHintForParam(type_hints, paramName, col, val);
944
+ } else if (op === "like" || op === "ilike" || op === "notlike" || op === "notilike") {
945
+ const val = pred.value;
946
+ if (typeof val !== "string") throw new Error(`Operator ${op} requires a string value for column ${key}`);
947
+ p += 1;
948
+ const paramName = `${table.name}_${key}_${p}`;
949
+ const sqlOp = op === "like" ? "like" : op === "ilike" ? "ilike" : op === "notlike" ? "not like" : "not ilike";
950
+ andParts.push(`${qualified} ${sqlOp} :${paramName}`);
951
+ params[paramName] = val;
952
+ addTypeHintForParam(type_hints, paramName, col, val);
953
+ } else {
954
+ const val = pred.value;
955
+ if (val === void 0) throw new Error(`Operator ${op} requires a value for column ${key}`);
956
+ validateComparisonValue(col, key, val, op);
957
+ p += 1;
958
+ const paramName = `${table.name}_${key}_${p}`;
959
+ if (op === "=") andParts.push(`${qualified} = :${paramName}`);
960
+ else if (op === "!=") andParts.push(`${qualified} <> :${paramName}`);
961
+ else if (op === "<" || op === "<=" || op === ">" || op === ">=") andParts.push(`${qualified} ${op} :${paramName}`);
962
+ else throw new Error(`Unsupported operator: ${op}`);
963
+ params[paramName] = val;
964
+ addTypeHintForParam(type_hints, paramName, col, val);
1030
965
  }
1031
- const andParts = [];
1032
- for (const key in state.where) {
1033
- const value = state.where[key];
966
+ }
967
+ const orGroupSql = [];
968
+ for (const group of state.orWhereGroups) {
969
+ const orParts = [];
970
+ for (const key in group) {
971
+ const value = group[key];
1034
972
  const col = findColumn(table, key);
1035
973
  p += 1;
1036
974
  const paramName = `${table.name}_${key}_${p}`;
1037
975
  if (value === null) {
1038
976
  if (!col.is_nullable) throw new Error(`Column ${table.name}.${key} is not nullable; cannot compare to null`);
1039
- andParts.push(`"${table.name}"."${key}" is null`);
977
+ orParts.push(`"${table.name}"."${key}" is null`);
1040
978
  } else if (Array.isArray(value) && !isArrayShapedGeomScalarValue(col, value)) {
1041
979
  validateInArrayValues(col, key, value, "in");
1042
- andParts.push(`"${table.name}"."${key}" = ANY(:${paramName})`);
980
+ orParts.push(`"${table.name}"."${key}" = ANY(:${paramName})`);
1043
981
  params[paramName] = value;
1044
982
  addTypeHintForParam(type_hints, paramName, col, value);
1045
983
  } else {
1046
984
  validateScalarForColumn(col, value, `column ${key}`);
1047
- andParts.push(`"${table.name}"."${key}" = :${paramName}`);
985
+ orParts.push(`"${table.name}"."${key}" = :${paramName}`);
1048
986
  params[paramName] = value;
1049
987
  addTypeHintForParam(type_hints, paramName, col, value);
1050
988
  }
1051
989
  }
1052
- for (const pred of state.andOps) {
990
+ if (orParts.length) orGroupSql.push("(" + orParts.join(" or ") + ")");
991
+ }
992
+ for (const group of state.orOpGroups) {
993
+ const orParts = [];
994
+ for (const pred of group) {
1053
995
  const key = String(pred.col);
1054
996
  const op = String(pred.op);
1055
997
  const col = findColumn(table, key);
1056
998
  const qualified = `"${table.name}"."${key}"`;
1057
999
  if (op === "isnull" || op === "notnull") {
1058
1000
  if (pred.value !== void 0) throw new Error(`Operator ${op} does not take a value for column ${key}`);
1059
- andParts.push(`${qualified} is ${op === "isnull" ? "null" : "not null"}`);
1001
+ orParts.push(`${qualified} is ${op === "isnull" ? "null" : "not null"}`);
1060
1002
  } else if (op === "in" || op === "notin") {
1061
1003
  const val = pred.value;
1062
1004
  if (!Array.isArray(val)) throw new Error(`Operator ${op} requires an array value for column ${key}`);
1063
1005
  validateInArrayValues(col, key, val, op);
1064
1006
  p += 1;
1065
1007
  const paramName = `${table.name}_${key}_${p}`;
1066
- andParts.push(`${qualified} ${op === "in" ? "= ANY" : "!= ALL"}(:${paramName})`);
1008
+ orParts.push(`${qualified} ${op === "in" ? "= ANY" : "!= ALL"}(:${paramName})`);
1067
1009
  params[paramName] = val;
1068
1010
  addTypeHintForParam(type_hints, paramName, col, val);
1069
1011
  } else if (op === "like" || op === "ilike" || op === "notlike" || op === "notilike") {
@@ -1072,7 +1014,7 @@
1072
1014
  p += 1;
1073
1015
  const paramName = `${table.name}_${key}_${p}`;
1074
1016
  const sqlOp = op === "like" ? "like" : op === "ilike" ? "ilike" : op === "notlike" ? "not like" : "not ilike";
1075
- andParts.push(`${qualified} ${sqlOp} :${paramName}`);
1017
+ orParts.push(`${qualified} ${sqlOp} :${paramName}`);
1076
1018
  params[paramName] = val;
1077
1019
  addTypeHintForParam(type_hints, paramName, col, val);
1078
1020
  } else {
@@ -1081,137 +1023,252 @@
1081
1023
  validateComparisonValue(col, key, val, op);
1082
1024
  p += 1;
1083
1025
  const paramName = `${table.name}_${key}_${p}`;
1084
- if (op === "=") andParts.push(`${qualified} = :${paramName}`);
1085
- else if (op === "!=") andParts.push(`${qualified} <> :${paramName}`);
1086
- else if (op === "<" || op === "<=" || op === ">" || op === ">=") andParts.push(`${qualified} ${op} :${paramName}`);
1026
+ if (op === "=") orParts.push(`${qualified} = :${paramName}`);
1027
+ else if (op === "!=") orParts.push(`${qualified} <> :${paramName}`);
1028
+ else if (op === "<" || op === "<=" || op === ">" || op === ">=") orParts.push(`${qualified} ${op} :${paramName}`);
1087
1029
  else throw new Error(`Unsupported operator: ${op}`);
1088
1030
  params[paramName] = val;
1089
1031
  addTypeHintForParam(type_hints, paramName, col, val);
1090
1032
  }
1091
1033
  }
1092
- const orGroupSql = [];
1093
- for (const group of state.orWhereGroups) {
1094
- const orParts = [];
1095
- for (const key in group) {
1096
- const value = group[key];
1097
- const col = findColumn(table, key);
1098
- p += 1;
1099
- const paramName = `${table.name}_${key}_${p}`;
1100
- if (value === null) {
1101
- if (!col.is_nullable) throw new Error(`Column ${table.name}.${key} is not nullable; cannot compare to null`);
1102
- orParts.push(`"${table.name}"."${key}" is null`);
1103
- } else if (Array.isArray(value) && !isArrayShapedGeomScalarValue(col, value)) {
1104
- validateInArrayValues(col, key, value, "in");
1105
- orParts.push(`"${table.name}"."${key}" = ANY(:${paramName})`);
1106
- params[paramName] = value;
1107
- addTypeHintForParam(type_hints, paramName, col, value);
1108
- } else {
1109
- validateScalarForColumn(col, value, `column ${key}`);
1110
- orParts.push(`"${table.name}"."${key}" = :${paramName}`);
1111
- params[paramName] = value;
1112
- addTypeHintForParam(type_hints, paramName, col, value);
1113
- }
1114
- }
1115
- if (orParts.length) orGroupSql.push("(" + orParts.join(" or ") + ")");
1116
- }
1117
- for (const group of state.orOpGroups) {
1118
- const orParts = [];
1119
- for (const pred of group) {
1120
- const key = String(pred.col);
1121
- const op = String(pred.op);
1122
- const col = findColumn(table, key);
1123
- const qualified = `"${table.name}"."${key}"`;
1124
- if (op === "isnull" || op === "notnull") {
1125
- if (pred.value !== void 0) throw new Error(`Operator ${op} does not take a value for column ${key}`);
1126
- orParts.push(`${qualified} is ${op === "isnull" ? "null" : "not null"}`);
1127
- } else if (op === "in" || op === "notin") {
1128
- const val = pred.value;
1129
- if (!Array.isArray(val)) throw new Error(`Operator ${op} requires an array value for column ${key}`);
1130
- validateInArrayValues(col, key, val, op);
1131
- p += 1;
1132
- const paramName = `${table.name}_${key}_${p}`;
1133
- orParts.push(`${qualified} ${op === "in" ? "= ANY" : "!= ALL"}(:${paramName})`);
1134
- params[paramName] = val;
1135
- addTypeHintForParam(type_hints, paramName, col, val);
1136
- } else if (op === "like" || op === "ilike" || op === "notlike" || op === "notilike") {
1137
- const val = pred.value;
1138
- if (typeof val !== "string") throw new Error(`Operator ${op} requires a string value for column ${key}`);
1139
- p += 1;
1140
- const paramName = `${table.name}_${key}_${p}`;
1141
- const sqlOp = op === "like" ? "like" : op === "ilike" ? "ilike" : op === "notlike" ? "not like" : "not ilike";
1142
- orParts.push(`${qualified} ${sqlOp} :${paramName}`);
1143
- params[paramName] = val;
1144
- addTypeHintForParam(type_hints, paramName, col, val);
1145
- } else {
1146
- const val = pred.value;
1147
- if (val === void 0) throw new Error(`Operator ${op} requires a value for column ${key}`);
1148
- validateComparisonValue(col, key, val, op);
1149
- p += 1;
1150
- const paramName = `${table.name}_${key}_${p}`;
1151
- if (op === "=") orParts.push(`${qualified} = :${paramName}`);
1152
- else if (op === "!=") orParts.push(`${qualified} <> :${paramName}`);
1153
- else if (op === "<" || op === "<=" || op === ">" || op === ">=") orParts.push(`${qualified} ${op} :${paramName}`);
1154
- else throw new Error(`Unsupported operator: ${op}`);
1155
- params[paramName] = val;
1156
- addTypeHintForParam(type_hints, paramName, col, val);
1157
- }
1158
- }
1159
- if (orParts.length) orGroupSql.push("(" + orParts.join(" or ") + ")");
1160
- }
1161
- if (orGroupSql.length) {
1162
- const andSql = andParts.length ? `(${andParts.join(" and ")})` : "";
1163
- const orSql = orGroupSql.join(" or ");
1164
- const full = andSql ? `${andSql} or ${orSql}` : orSql;
1165
- if (full.trim().length) parts.push("where " + full);
1166
- } else if (andParts.length) parts.push("where " + andParts.join(" and "));
1167
- if (state.order.length) {
1168
- const orders = [];
1169
- for (const o of state.order) orders.push(`"${table.name}"."${o.col}" ${o.dir}`);
1170
- parts.push("order by " + orders.join(", "));
1171
- }
1172
- if (state.limit !== void 0) parts.push("limit " + state.limit);
1173
- if (state.offset !== void 0) parts.push("offset " + state.offset);
1174
- return {
1175
- q: parts.join(" "),
1176
- params: Object.keys(params).length > 0 ? params : void 0,
1177
- type_hints: Object.keys(type_hints).length ? type_hints : void 0
1178
- };
1034
+ if (orParts.length) orGroupSql.push("(" + orParts.join(" or ") + ")");
1035
+ }
1036
+ if (orGroupSql.length) {
1037
+ const andSql = andParts.length ? `(${andParts.join(" and ")})` : "";
1038
+ const orSql = orGroupSql.join(" or ");
1039
+ const full = andSql ? `${andSql} or ${orSql}` : orSql;
1040
+ if (full.trim().length) parts.push("where " + full);
1041
+ } else if (andParts.length) parts.push("where " + andParts.join(" and "));
1042
+ if (state.order.length) {
1043
+ const orders = [];
1044
+ for (const o of state.order) orders.push(`"${table.name}"."${o.col}" ${o.dir}`);
1045
+ parts.push("order by " + orders.join(", "));
1046
+ }
1047
+ if (state.limit !== void 0) parts.push("limit " + state.limit);
1048
+ if (state.offset !== void 0) parts.push("offset " + state.offset);
1049
+ return {
1050
+ q: parts.join(" "),
1051
+ params: Object.keys(params).length > 0 ? params : void 0,
1052
+ type_hints: Object.keys(type_hints).length ? type_hints : void 0
1179
1053
  };
1054
+ };
1055
+ }
1056
+ selectFrom(tableName, cols$1) {
1057
+ const jtName = String(tableName);
1058
+ const join = this.s.joins.find((j) => j.target.name === jtName);
1059
+ if (!join) throw new Error(`selectFrom('${jtName}') requires a prior join('${jtName}') call`);
1060
+ const sel = !cols$1 || cols$1.length === 0 ? ["*"] : cols$1.map(String);
1061
+ if (!(sel.length === 1 && sel[0] === "*")) for (const c of sel) findColumn(join.target, String(c));
1062
+ const existing = this.s.joinSelections.find((js) => js.target.name === jtName);
1063
+ if (existing) {
1064
+ if (existing.selected.includes("*")) return this;
1065
+ if (sel.length === 1 && sel[0] === "*") existing.selected = ["*"];
1066
+ else {
1067
+ const set = new Set(existing.selected);
1068
+ for (const c of sel) set.add(String(c));
1069
+ existing.selected = Array.from(set);
1070
+ }
1071
+ } else this.s.joinSelections.push({
1072
+ target: join.target,
1073
+ selected: sel
1074
+ });
1075
+ return this;
1076
+ }
1077
+ andWhere(where) {
1078
+ for (const k in where) this.s.where[k] = where[k];
1079
+ return this;
1080
+ }
1081
+ /** @deprecated Use andWhere() instead */
1082
+ where(where) {
1083
+ return this.andWhere(where);
1084
+ }
1085
+ orWhere(where) {
1086
+ this.s.orWhereGroups.push(where);
1087
+ return this;
1088
+ }
1089
+ wherePk(pk) {
1090
+ const pkCols = getPrimaryKeyColumns(table);
1091
+ if (!pkCols || pkCols.length === 0) throw new Error(`Table ${table.name} does not have a primary key`);
1092
+ if (pkCols.length === 1) {
1093
+ const colName = pkCols[0];
1094
+ const colDef = findColumn(table, colName);
1095
+ if (pk === null || pk === void 0) throw new Error(`wherePk on ${table.name} requires a non-null value for primary key column ${colName}`);
1096
+ if (Array.isArray(pk)) throw new Error(`wherePk on ${table.name} expects a scalar for primary key column ${colName}, not an array`);
1097
+ if (isPlainObject(pk)) throw new Error(`wherePk on ${table.name} expects a scalar for primary key column ${colName}`);
1098
+ validateScalarForColumn(colDef, pk, `primary key ${table.name}.${colName}`);
1099
+ this.s.where[colName] = pk;
1100
+ return this;
1101
+ } else {
1102
+ if (!isPlainObject(pk) || pk === null) throw new Error(`wherePk on ${table.name} requires an object with keys: ${pkCols.join(", ")}`);
1103
+ const obj = pk;
1104
+ for (const k of Object.keys(obj)) if (!pkCols.includes(k)) throw new Error(`wherePk received unknown key '${k}'. Expected keys: ${pkCols.join(", ")}`);
1105
+ for (const colName of pkCols) {
1106
+ if (!(colName in obj)) throw new Error(`wherePk missing key '${colName}'. Required keys: ${pkCols.join(", ")}`);
1107
+ const v = obj[colName];
1108
+ if (v === null || v === void 0) throw new Error(`wherePk on ${table.name} requires non-null values for all primary key columns (${pkCols.join(", ")})`);
1109
+ if (Array.isArray(v)) throw new Error(`wherePk on ${table.name} expects scalar values for primary key column ${colName}, not an array`);
1110
+ validateScalarForColumn(findColumn(table, colName), v, `primary key ${table.name}.${colName}`);
1111
+ this.s.where[colName] = v;
1112
+ }
1113
+ return this;
1180
1114
  }
1181
- selectFrom(tableName, cols$1) {
1182
- const jtName = String(tableName);
1183
- const join = this.s.joins.find((j) => j.target.name === jtName);
1184
- if (!join) throw new Error(`selectFrom('${jtName}') requires a prior join('${jtName}') call`);
1185
- const sel = !cols$1 || cols$1.length === 0 ? ["*"] : cols$1.map(String);
1186
- if (!(sel.length === 1 && sel[0] === "*")) for (const c of sel) findColumn(join.target, String(c));
1187
- const existing = this.s.joinSelections.find((js) => js.target.name === jtName);
1188
- if (existing) {
1189
- if (existing.selected.includes("*")) return this;
1190
- if (sel.length === 1 && sel[0] === "*") existing.selected = ["*"];
1191
- else {
1192
- const set = new Set(existing.selected);
1193
- for (const c of sel) set.add(String(c));
1194
- existing.selected = Array.from(set);
1195
- }
1196
- } else this.s.joinSelections.push({
1197
- target: join.target,
1198
- selected: sel
1115
+ }
1116
+ andWhereOp(col, op, ...args) {
1117
+ const value = args[0];
1118
+ this.s.andOps.push({
1119
+ col,
1120
+ op,
1121
+ value
1122
+ });
1123
+ return this;
1124
+ }
1125
+ orWhereOp(col, op, ...args) {
1126
+ const value = args[0];
1127
+ this.s.orOpGroups.push([{
1128
+ col,
1129
+ op,
1130
+ value
1131
+ }]);
1132
+ return this;
1133
+ }
1134
+ andWhereOpGroup(predicates) {
1135
+ const group = predicates.map((p) => ({
1136
+ col: p[0],
1137
+ op: p[1],
1138
+ value: p[2]
1139
+ }));
1140
+ for (const g of group) this.s.andOps.push(g);
1141
+ return this;
1142
+ }
1143
+ orWhereOpGroup(predicates) {
1144
+ const group = predicates.map((p) => ({
1145
+ col: p[0],
1146
+ op: p[1],
1147
+ value: p[2]
1148
+ }));
1149
+ this.s.orOpGroups.push(group);
1150
+ return this;
1151
+ }
1152
+ orderBy(order) {
1153
+ this.s.order = [];
1154
+ const isValidDir = (d) => d === "asc" || d === "desc";
1155
+ if (typeof order === "string") {
1156
+ findColumn(table, String(order));
1157
+ this.s.order.push({
1158
+ col: order,
1159
+ dir: "asc"
1160
+ });
1161
+ } else for (const item of order) {
1162
+ const col = String(item[0]);
1163
+ const dir = String(item[1]);
1164
+ findColumn(table, col);
1165
+ if (!isValidDir(dir)) throw new Error(`Invalid order direction: ${dir}. Allowed: asc | desc`);
1166
+ this.s.order.push({
1167
+ col: item[0],
1168
+ dir
1199
1169
  });
1200
- return this;
1201
1170
  }
1202
- andWhere(where) {
1203
- for (const k in where) this.s.where[k] = where[k];
1204
- return this;
1171
+ return this;
1172
+ }
1173
+ limit(n) {
1174
+ 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`);
1175
+ this.s.limit = n;
1176
+ return this;
1177
+ }
1178
+ offset(n) {
1179
+ 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`);
1180
+ this.s.offset = n;
1181
+ return this;
1182
+ }
1183
+ join(tableName, type = "inner") {
1184
+ const target = findTable(schema, String(tableName));
1185
+ const sources = [];
1186
+ for (let i = this.s.joins.length - 1; i >= 0; i--) {
1187
+ const src = this.s.joins[i].target;
1188
+ if (!sources.some((s) => s.name === src.name)) sources.push(src);
1205
1189
  }
1206
- /** @deprecated Use andWhere() instead */
1207
- where(where) {
1208
- return this.andWhere(where);
1190
+ if (!sources.some((s) => s.name === table.name)) sources.push(table);
1191
+ let pickedSource = null;
1192
+ let pairs = null;
1193
+ for (const src of sources) {
1194
+ const p = findJoinOn(src, target);
1195
+ if (p && p.length) {
1196
+ pickedSource = src;
1197
+ pairs = p;
1198
+ break;
1199
+ }
1209
1200
  }
1210
- orWhere(where) {
1211
- this.s.orWhereGroups.push(where);
1212
- return this;
1201
+ if (!pairs || !pickedSource) {
1202
+ const candidates = sources.map((s) => s.name).join(", ");
1203
+ throw new Error(`No foreign key relation found between any of [${candidates}] and ${target.name}`);
1204
+ }
1205
+ const jt = String(type);
1206
+ if (jt !== "inner" && jt !== "left" && jt !== "right" && jt !== "full") throw new Error(`Invalid join type: ${jt}. Allowed: inner | left | right | full`);
1207
+ this.s.joins.push({
1208
+ type: jt,
1209
+ source: pickedSource,
1210
+ target,
1211
+ on: pairs
1212
+ });
1213
+ return this;
1214
+ }
1215
+ }();
1216
+ }
1217
+ insert(values) {
1218
+ const table = this.table;
1219
+ const schema = this.schema;
1220
+ const state = {
1221
+ values,
1222
+ returning: []
1223
+ };
1224
+ return new class {
1225
+ returning(cols) {
1226
+ state.returning = cols || [];
1227
+ return this;
1228
+ }
1229
+ toSql() {
1230
+ const colsArr = [];
1231
+ const vals = [];
1232
+ const params = {};
1233
+ const type_hints = {};
1234
+ let p = 0;
1235
+ for (const key in state.values) {
1236
+ const value = state.values[key];
1237
+ const col = findColumn(table, key);
1238
+ p += 1;
1239
+ const paramName = `${table.name}_${key}_${p}`;
1240
+ colsArr.push(`"${key}"`);
1241
+ vals.push(`:${paramName}`);
1242
+ params[paramName] = value;
1243
+ addTypeHintForParam(type_hints, paramName, col, value);
1213
1244
  }
1214
- wherePk(pk) {
1245
+ const parts = [];
1246
+ parts.push(`insert into "${schema.name}"."${table.name}" (${colsArr.join(", ")}) values (${vals.join(", ")})`);
1247
+ if (state.returning.length) parts.push("returning " + state.returning.join(", "));
1248
+ const req = {
1249
+ q: parts.join(" "),
1250
+ params: Object.keys(params).length > 0 ? params : void 0,
1251
+ type_hints: Object.keys(type_hints).length ? type_hints : void 0
1252
+ };
1253
+ return state.returning.length ? req : req;
1254
+ }
1255
+ }();
1256
+ }
1257
+ update(values) {
1258
+ const table = this.table;
1259
+ const schema = this.schema;
1260
+ const state = {
1261
+ values,
1262
+ where: {},
1263
+ returning: []
1264
+ };
1265
+ return new class {
1266
+ constructor() {
1267
+ this.where = (w) => {
1268
+ for (const k in w) state.where[k] = w[k];
1269
+ return this;
1270
+ };
1271
+ this.wherePk = (pk) => {
1215
1272
  const pkCols = getPrimaryKeyColumns(table);
1216
1273
  if (!pkCols || pkCols.length === 0) throw new Error(`Table ${table.name} does not have a primary key`);
1217
1274
  if (pkCols.length === 1) {
@@ -1221,8 +1278,7 @@
1221
1278
  if (Array.isArray(pk)) throw new Error(`wherePk on ${table.name} expects a scalar for primary key column ${colName}, not an array`);
1222
1279
  if (isPlainObject(pk)) throw new Error(`wherePk on ${table.name} expects a scalar for primary key column ${colName}`);
1223
1280
  validateScalarForColumn(colDef, pk, `primary key ${table.name}.${colName}`);
1224
- this.s.where[colName] = pk;
1225
- return this;
1281
+ state.where[colName] = pk;
1226
1282
  } else {
1227
1283
  if (!isPlainObject(pk) || pk === null) throw new Error(`wherePk on ${table.name} requires an object with keys: ${pkCols.join(", ")}`);
1228
1284
  const obj = pk;
@@ -1233,336 +1289,146 @@
1233
1289
  if (v === null || v === void 0) throw new Error(`wherePk on ${table.name} requires non-null values for all primary key columns (${pkCols.join(", ")})`);
1234
1290
  if (Array.isArray(v)) throw new Error(`wherePk on ${table.name} expects scalar values for primary key column ${colName}, not an array`);
1235
1291
  validateScalarForColumn(findColumn(table, colName), v, `primary key ${table.name}.${colName}`);
1236
- this.s.where[colName] = v;
1292
+ state.where[colName] = v;
1237
1293
  }
1238
- return this;
1239
1294
  }
1240
- }
1241
- andWhereOp(col, op, ...args) {
1242
- const value = args[0];
1243
- this.s.andOps.push({
1244
- col,
1245
- op,
1246
- value
1247
- });
1248
- return this;
1249
- }
1250
- orWhereOp(col, op, ...args) {
1251
- const value = args[0];
1252
- this.s.orOpGroups.push([{
1253
- col,
1254
- op,
1255
- value
1256
- }]);
1257
- return this;
1258
- }
1259
- andWhereOpGroup(predicates) {
1260
- const group = predicates.map((p) => ({
1261
- col: p[0],
1262
- op: p[1],
1263
- value: p[2]
1264
- }));
1265
- for (const g of group) this.s.andOps.push(g);
1266
- return this;
1267
- }
1268
- orWhereOpGroup(predicates) {
1269
- const group = predicates.map((p) => ({
1270
- col: p[0],
1271
- op: p[1],
1272
- value: p[2]
1273
- }));
1274
- this.s.orOpGroups.push(group);
1275
1295
  return this;
1296
+ };
1297
+ }
1298
+ returning(cols) {
1299
+ state.returning = cols || [];
1300
+ return this;
1301
+ }
1302
+ toSql() {
1303
+ const params = {};
1304
+ const type_hints = {};
1305
+ let p = 0;
1306
+ const setParts = [];
1307
+ for (const key in state.values) {
1308
+ const value = state.values[key];
1309
+ const col = findColumn(table, key);
1310
+ p += 1;
1311
+ const paramName = `${table.name}_${key}_${p}`;
1312
+ setParts.push(`"${key}" = :${paramName}`);
1313
+ params[paramName] = value;
1314
+ addTypeHintForParam(type_hints, paramName, col, value);
1276
1315
  }
1277
- orderBy(order) {
1278
- this.s.order = [];
1279
- const isValidDir = (d) => d === "asc" || d === "desc";
1280
- if (typeof order === "string") {
1281
- findColumn(table, String(order));
1282
- this.s.order.push({
1283
- col: order,
1284
- dir: "asc"
1285
- });
1286
- } else for (const item of order) {
1287
- const col = String(item[0]);
1288
- const dir = String(item[1]);
1289
- findColumn(table, col);
1290
- if (!isValidDir(dir)) throw new Error(`Invalid order direction: ${dir}. Allowed: asc | desc`);
1291
- this.s.order.push({
1292
- col: item[0],
1293
- dir
1294
- });
1316
+ const whereClauses = [];
1317
+ for (const key in state.where) {
1318
+ const value = state.where[key];
1319
+ const col = findColumn(table, key);
1320
+ p += 1;
1321
+ const paramName = `${table.name}_${key}_${p}`;
1322
+ if (value === null) {
1323
+ if (!col.is_nullable) throw new Error(`Column ${table.name}.${key} is not nullable; cannot compare to null`);
1324
+ whereClauses.push(`"${key}" is null`);
1325
+ } else if (Array.isArray(value) && !isArrayShapedGeomScalarValue(col, value)) {
1326
+ validateInArrayValues(col, key, value, "in");
1327
+ whereClauses.push(`"${key}" = ANY(:${paramName})`);
1328
+ params[paramName] = value;
1329
+ addTypeHintForParam(type_hints, paramName, col, value);
1330
+ } else {
1331
+ validateScalarForColumn(col, value, `column ${key}`);
1332
+ whereClauses.push(`"${key}" = :${paramName}`);
1333
+ params[paramName] = value;
1334
+ addTypeHintForParam(type_hints, paramName, col, value);
1295
1335
  }
1296
- return this;
1297
1336
  }
1298
- limit(n) {
1299
- 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`);
1300
- this.s.limit = n;
1301
- return this;
1302
- }
1303
- offset(n) {
1304
- 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`);
1305
- this.s.offset = n;
1337
+ const parts = [];
1338
+ parts.push(`update "${schema.name}"."${table.name}" set ${setParts.join(", ")}`);
1339
+ if (whereClauses.length) parts.push("where " + whereClauses.join(" and "));
1340
+ if (state.returning.length) parts.push("returning " + state.returning.join(", "));
1341
+ const req = {
1342
+ q: parts.join(" "),
1343
+ params: Object.keys(params).length > 0 ? params : void 0,
1344
+ type_hints: Object.keys(type_hints).length ? type_hints : void 0
1345
+ };
1346
+ return state.returning.length ? req : req;
1347
+ }
1348
+ }();
1349
+ }
1350
+ delete() {
1351
+ const table = this.table;
1352
+ const schema = this.schema;
1353
+ const state = {
1354
+ where: {},
1355
+ returning: []
1356
+ };
1357
+ return new class {
1358
+ constructor() {
1359
+ this.where = (w) => {
1360
+ for (const k in w) state.where[k] = w[k];
1306
1361
  return this;
1307
- }
1308
- join(tableName, type = "inner") {
1309
- const target = findTable(schema, String(tableName));
1310
- const sources = [];
1311
- for (let i = this.s.joins.length - 1; i >= 0; i--) {
1312
- const src = this.s.joins[i].target;
1313
- if (!sources.some((s) => s.name === src.name)) sources.push(src);
1314
- }
1315
- if (!sources.some((s) => s.name === table.name)) sources.push(table);
1316
- let pickedSource = null;
1317
- let pairs = null;
1318
- for (const src of sources) {
1319
- const p = findJoinOn(src, target);
1320
- if (p && p.length) {
1321
- pickedSource = src;
1322
- pairs = p;
1323
- break;
1362
+ };
1363
+ this.wherePk = (pk) => {
1364
+ const pkCols = getPrimaryKeyColumns(table);
1365
+ if (!pkCols || pkCols.length === 0) throw new Error(`Table ${table.name} does not have a primary key`);
1366
+ if (pkCols.length === 1) {
1367
+ const col = pkCols[0];
1368
+ if (isPlainObject(pk)) throw new Error(`wherePk on ${table.name} expects a scalar for primary key column ${col}`);
1369
+ state.where[col] = pk;
1370
+ } else {
1371
+ if (!isPlainObject(pk)) throw new Error(`wherePk on ${table.name} requires an object with keys: ${pkCols.join(", ")}`);
1372
+ const obj = pk;
1373
+ for (const k of Object.keys(obj)) if (!pkCols.includes(k)) throw new Error(`wherePk received unknown key '${k}'. Expected keys: ${pkCols.join(", ")}`);
1374
+ for (const col of pkCols) {
1375
+ if (!(col in obj)) throw new Error(`wherePk missing key '${col}'. Required keys: ${pkCols.join(", ")}`);
1376
+ state.where[col] = obj[col];
1324
1377
  }
1325
1378
  }
1326
- if (!pairs || !pickedSource) {
1327
- const candidates = sources.map((s) => s.name).join(", ");
1328
- throw new Error(`No foreign key relation found between any of [${candidates}] and ${target.name}`);
1329
- }
1330
- const jt = String(type);
1331
- if (jt !== "inner" && jt !== "left" && jt !== "right" && jt !== "full") throw new Error(`Invalid join type: ${jt}. Allowed: inner | left | right | full`);
1332
- this.s.joins.push({
1333
- type: jt,
1334
- source: pickedSource,
1335
- target,
1336
- on: pairs
1337
- });
1338
1379
  return this;
1380
+ };
1381
+ }
1382
+ returning(cols) {
1383
+ state.returning = cols || [];
1384
+ return this;
1385
+ }
1386
+ toSql() {
1387
+ const params = {};
1388
+ const type_hints = {};
1389
+ let p = 0;
1390
+ const whereClauses = [];
1391
+ for (const key in state.where) {
1392
+ const value = state.where[key];
1393
+ const col = findColumn(table, key);
1394
+ p += 1;
1395
+ const paramName = `${table.name}_${key}_${p}`;
1396
+ if (value === null) {
1397
+ if (!col.is_nullable) throw new Error(`Column ${table.name}.${key} is not nullable; cannot compare to null`);
1398
+ whereClauses.push(`"${key}" is null`);
1399
+ } else if (Array.isArray(value)) {
1400
+ validateInArrayValues(col, key, value, "in");
1401
+ whereClauses.push(`"${key}" = ANY(:${paramName})`);
1402
+ params[paramName] = value;
1403
+ addTypeHintForParam(type_hints, paramName, col, value);
1404
+ } else {
1405
+ validateScalarForColumn(col, value, `column ${key}`);
1406
+ whereClauses.push(`"${key}" = :${paramName}`);
1407
+ params[paramName] = value;
1408
+ addTypeHintForParam(type_hints, paramName, col, value);
1409
+ }
1339
1410
  }
1340
- }();
1341
- }
1342
- insert(values) {
1343
- const table = this.table;
1344
- const schema = this.schema;
1345
- const state = {
1346
- values,
1347
- returning: []
1348
- };
1349
- return new class {
1350
- constructor() {
1351
- this.returning = (cols) => {
1352
- state.returning = cols || [];
1353
- return this;
1354
- };
1355
- this.toSql = () => {
1356
- const cols = [];
1357
- const vals = [];
1358
- const params = {};
1359
- const type_hints = {};
1360
- let p = 0;
1361
- for (const key in state.values) {
1362
- const value = state.values[key];
1363
- const col = findColumn(table, key);
1364
- p += 1;
1365
- const paramName = `${table.name}_${key}_${p}`;
1366
- cols.push(`"${key}"`);
1367
- vals.push(`:${paramName}`);
1368
- params[paramName] = value;
1369
- addTypeHintForParam(type_hints, paramName, col, value);
1370
- }
1371
- const parts = [];
1372
- parts.push(`insert into "${schema.name}"."${table.name}" (${cols.join(", ")}) values (${vals.join(", ")})`);
1373
- if (state.returning.length) parts.push("returning " + state.returning.join(", "));
1374
- return {
1375
- q: parts.join(" "),
1376
- params: Object.keys(params).length > 0 ? params : void 0,
1377
- type_hints: Object.keys(type_hints).length ? type_hints : void 0
1378
- };
1379
- };
1380
- }
1381
- }();
1382
- }
1383
- update(values) {
1384
- const table = this.table;
1385
- const schema = this.schema;
1386
- const state = {
1387
- values,
1388
- where: {},
1389
- returning: []
1390
- };
1391
- return new class {
1392
- constructor() {
1393
- this.where = (w) => {
1394
- for (const k in w) state.where[k] = w[k];
1395
- return this;
1396
- };
1397
- this.wherePk = (pk) => {
1398
- const pkCols = getPrimaryKeyColumns(table);
1399
- if (!pkCols || pkCols.length === 0) throw new Error(`Table ${table.name} does not have a primary key`);
1400
- if (pkCols.length === 1) {
1401
- const colName = pkCols[0];
1402
- const colDef = findColumn(table, colName);
1403
- if (pk === null || pk === void 0) throw new Error(`wherePk on ${table.name} requires a non-null value for primary key column ${colName}`);
1404
- if (Array.isArray(pk)) throw new Error(`wherePk on ${table.name} expects a scalar for primary key column ${colName}, not an array`);
1405
- if (isPlainObject(pk)) throw new Error(`wherePk on ${table.name} expects a scalar for primary key column ${colName}`);
1406
- validateScalarForColumn(colDef, pk, `primary key ${table.name}.${colName}`);
1407
- state.where[colName] = pk;
1408
- } else {
1409
- if (!isPlainObject(pk) || pk === null) throw new Error(`wherePk on ${table.name} requires an object with keys: ${pkCols.join(", ")}`);
1410
- const obj = pk;
1411
- for (const k of Object.keys(obj)) if (!pkCols.includes(k)) throw new Error(`wherePk received unknown key '${k}'. Expected keys: ${pkCols.join(", ")}`);
1412
- for (const colName of pkCols) {
1413
- if (!(colName in obj)) throw new Error(`wherePk missing key '${colName}'. Required keys: ${pkCols.join(", ")}`);
1414
- const v = obj[colName];
1415
- if (v === null || v === void 0) throw new Error(`wherePk on ${table.name} requires non-null values for all primary key columns (${pkCols.join(", ")})`);
1416
- if (Array.isArray(v)) throw new Error(`wherePk on ${table.name} expects scalar values for primary key column ${colName}, not an array`);
1417
- validateScalarForColumn(findColumn(table, colName), v, `primary key ${table.name}.${colName}`);
1418
- state.where[colName] = v;
1419
- }
1420
- }
1421
- return this;
1422
- };
1423
- this.returning = (cols) => {
1424
- state.returning = cols || [];
1425
- return this;
1426
- };
1427
- this.toSql = () => {
1428
- const params = {};
1429
- const type_hints = {};
1430
- let p = 0;
1431
- const setParts = [];
1432
- for (const key in state.values) {
1433
- const value = state.values[key];
1434
- const col = findColumn(table, key);
1435
- p += 1;
1436
- const paramName = `${table.name}_${key}_${p}`;
1437
- setParts.push(`"${key}" = :${paramName}`);
1438
- params[paramName] = value;
1439
- addTypeHintForParam(type_hints, paramName, col, value);
1440
- }
1441
- const whereClauses = [];
1442
- for (const key in state.where) {
1443
- const value = state.where[key];
1444
- const col = findColumn(table, key);
1445
- p += 1;
1446
- const paramName = `${table.name}_${key}_${p}`;
1447
- if (value === null) {
1448
- if (!col.is_nullable) throw new Error(`Column ${table.name}.${key} is not nullable; cannot compare to null`);
1449
- whereClauses.push(`"${key}" is null`);
1450
- } else if (Array.isArray(value) && !isArrayShapedGeomScalarValue(col, value)) {
1451
- validateInArrayValues(col, key, value, "in");
1452
- whereClauses.push(`"${key}" = ANY(:${paramName})`);
1453
- params[paramName] = value;
1454
- addTypeHintForParam(type_hints, paramName, col, value);
1455
- } else {
1456
- validateScalarForColumn(col, value, `column ${key}`);
1457
- whereClauses.push(`"${key}" = :${paramName}`);
1458
- params[paramName] = value;
1459
- addTypeHintForParam(type_hints, paramName, col, value);
1460
- }
1461
- }
1462
- const parts = [];
1463
- parts.push(`update "${schema.name}"."${table.name}" set ${setParts.join(", ")}`);
1464
- if (whereClauses.length) parts.push("where " + whereClauses.join(" and "));
1465
- if (state.returning.length) parts.push("returning " + state.returning.join(", "));
1466
- return {
1467
- q: parts.join(" "),
1468
- params: Object.keys(params).length > 0 ? params : void 0,
1469
- type_hints: Object.keys(type_hints).length ? type_hints : void 0
1470
- };
1471
- };
1472
- }
1473
- }();
1474
- }
1475
- delete() {
1476
- const table = this.table;
1477
- const schema = this.schema;
1478
- const state = {
1479
- where: {},
1480
- returning: []
1481
- };
1482
- return new class {
1483
- constructor() {
1484
- this.where = (w) => {
1485
- for (const k in w) state.where[k] = w[k];
1486
- return this;
1487
- };
1488
- this.wherePk = (pk) => {
1489
- const pkCols = getPrimaryKeyColumns(table);
1490
- if (!pkCols || pkCols.length === 0) throw new Error(`Table ${table.name} does not have a primary key`);
1491
- if (pkCols.length === 1) {
1492
- const col = pkCols[0];
1493
- if (isPlainObject(pk)) throw new Error(`wherePk on ${table.name} expects a scalar for primary key column ${col}`);
1494
- state.where[col] = pk;
1495
- } else {
1496
- if (!isPlainObject(pk)) throw new Error(`wherePk on ${table.name} requires an object with keys: ${pkCols.join(", ")}`);
1497
- const obj = pk;
1498
- for (const k of Object.keys(obj)) if (!pkCols.includes(k)) throw new Error(`wherePk received unknown key '${k}'. Expected keys: ${pkCols.join(", ")}`);
1499
- for (const col of pkCols) {
1500
- if (!(col in obj)) throw new Error(`wherePk missing key '${col}'. Required keys: ${pkCols.join(", ")}`);
1501
- state.where[col] = obj[col];
1502
- }
1503
- }
1504
- return this;
1505
- };
1506
- this.returning = (cols) => {
1507
- state.returning = cols || [];
1508
- return this;
1509
- };
1510
- this.toSql = () => {
1511
- const params = {};
1512
- const type_hints = {};
1513
- let p = 0;
1514
- const whereClauses = [];
1515
- for (const key in state.where) {
1516
- const value = state.where[key];
1517
- const col = findColumn(table, key);
1518
- p += 1;
1519
- const paramName = `${table.name}_${key}_${p}`;
1520
- if (value === null) {
1521
- if (!col.is_nullable) throw new Error(`Column ${table.name}.${key} is not nullable; cannot compare to null`);
1522
- whereClauses.push(`"${key}" is null`);
1523
- } else if (Array.isArray(value)) {
1524
- validateInArrayValues(col, key, value, "in");
1525
- whereClauses.push(`"${key}" = ANY(:${paramName})`);
1526
- params[paramName] = value;
1527
- addTypeHintForParam(type_hints, paramName, col, value);
1528
- } else {
1529
- validateScalarForColumn(col, value, `column ${key}`);
1530
- whereClauses.push(`"${key}" = :${paramName}`);
1531
- params[paramName] = value;
1532
- addTypeHintForParam(type_hints, paramName, col, value);
1533
- }
1534
- }
1535
- const parts = [];
1536
- parts.push(`delete from "${schema.name}"."${table.name}"`);
1537
- if (whereClauses.length) parts.push("where " + whereClauses.join(" and "));
1538
- if (state.returning.length) parts.push("returning " + state.returning.join(", "));
1539
- return {
1540
- q: parts.join(" "),
1541
- params: Object.keys(params).length > 0 ? params : void 0,
1542
- type_hints: Object.keys(type_hints).length ? type_hints : void 0
1543
- };
1544
- };
1545
- }
1546
- }();
1547
- }
1548
- };
1549
- function createSqlBuilder(schema) {
1550
- return { table: (name) => new TableQueryImpl(schema, String(name)) };
1411
+ const parts = [];
1412
+ parts.push(`delete from "${schema.name}"."${table.name}"`);
1413
+ if (whereClauses.length) parts.push("where " + whereClauses.join(" and "));
1414
+ if (state.returning.length) parts.push("returning " + state.returning.join(", "));
1415
+ const req = {
1416
+ q: parts.join(" "),
1417
+ params: Object.keys(params).length > 0 ? params : void 0,
1418
+ type_hints: Object.keys(type_hints).length ? type_hints : void 0
1419
+ };
1420
+ return state.returning.length ? req : req;
1421
+ }
1422
+ }();
1551
1423
  }
1552
-
1553
- //#endregion
1554
- //#region src/index.ts
1555
- /**
1556
- * @author Martin Høgh <mh@mapcentia.com>
1557
- * @copyright 2013-2026 MapCentia ApS
1558
- * @license https://opensource.org/license/mit The MIT License
1559
- *
1560
- */
1424
+ };
1425
+ function createSqlBuilder(schema) {
1426
+ return { table: (name) => new TableQueryImpl(schema, String(name)) };
1427
+ }
1561
1428
 
1562
1429
  //#endregion
1563
1430
  exports.Claims = Claims;
1564
1431
  exports.CodeFlow = CodeFlow;
1565
- exports.GraphQL = GraphQL;
1566
1432
  exports.Meta = Meta;
1567
1433
  exports.PasswordFlow = PasswordFlow;
1568
1434
  exports.Rpc = Rpc;