@centia-io/sdk 0.0.42 → 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,1068 +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/Gql.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 Gql = class {
546
- constructor(schema) {
547
- this.schema = schema;
548
- }
549
- async request(request) {
550
- return await get_response_default(await make_request_default(null, `graphql/schema/${this.schema}`, "POST", request), 200);
551
- }
552
- };
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
+ };
553
479
 
554
480
  //#endregion
555
481
  //#region src/Meta.ts
556
- /**
557
- * @author Martin Høgh <mh@mapcentia.com>
558
- * @copyright 2013-2026 MapCentia ApS
559
- * @license https://opensource.org/license/mit The MIT License
560
- *
561
- */
562
- var Meta = class {
563
- async query(rel) {
564
- return await get_response_default(await make_request_default("3", `meta/${rel}`, "GET", null), 200);
565
- }
566
- };
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
+ };
567
487
 
568
488
  //#endregion
569
489
  //#region src/Status.ts
570
- /**
571
- * @author Martin Høgh <mh@mapcentia.com>
572
- * @copyright 2013-2026 MapCentia ApS
573
- * @license https://opensource.org/license/mit The MIT License
574
- *
575
- */
576
- var Status = class {
577
- isAuth() {
578
- const tokens = getTokens();
579
- return !(!tokens.accessToken && !tokens.refreshToken);
580
- }
581
- getTokens() {
582
- return getTokens();
583
- }
584
- };
490
+ var Status = class {
491
+ isAuth() {
492
+ const tokens = getTokens();
493
+ return !(!tokens.accessToken && !tokens.refreshToken);
494
+ }
495
+ getTokens() {
496
+ return getTokens();
497
+ }
498
+ };
585
499
 
586
500
  //#endregion
587
501
  //#region src/Claims.ts
588
- /**
589
- * @author Martin Høgh <mh@mapcentia.com>
590
- * @copyright 2013-2026 MapCentia ApS
591
- * @license https://opensource.org/license/mit The MIT License
592
- *
593
- */
594
- var Claims = class {
595
- get() {
596
- const tokens = getTokens().accessToken;
597
- return claims(tokens);
598
- }
599
- };
502
+ var Claims = class {
503
+ get() {
504
+ const tokens = getTokens().accessToken;
505
+ return claims(tokens);
506
+ }
507
+ };
600
508
 
601
509
  //#endregion
602
510
  //#region src/Users.ts
603
- /**
604
- * @author Martin Høgh <mh@mapcentia.com>
605
- * @copyright 2013-2026 MapCentia ApS
606
- * @license https://opensource.org/license/mit The MIT License
607
- *
608
- */
609
- var Users = class {
610
- async get(user) {
611
- return await get_response_default(await make_request_default("4", `users/${user}`, "GET", null), 200);
612
- }
613
- };
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
+ };
614
516
 
615
517
  //#endregion
616
518
  //#region src/Ws.ts
617
- /**
618
- * @author Martin Høgh <mh@mapcentia.com>
619
- * @copyright 2013-2026 MapCentia ApS
620
- * @license https://opensource.org/license/mit The MIT License
621
- *
622
- */
623
- var Ws = class {
624
- constructor(options) {
625
- this.options = options;
626
- this.options.wsClient = this.options?.wsClient ?? WebSocket;
627
- }
628
- connect() {
629
- const me = this;
630
- const { accessToken } = getTokens();
631
- const connect = () => {
632
- let queryString = `?token=` + accessToken;
633
- if (this.options?.rel) queryString = queryString + `&rel=` + this.options.rel;
634
- const WSClass = this.options.wsClient;
635
- const ws = new WSClass(this.options.host + `/` + queryString);
636
- ws.onopen = function() {
637
- console.log("WebSocket connected!");
638
- };
639
- ws.onmessage = function(event) {
640
- me.options.callBack(event.data);
641
- };
642
- ws.onclose = function(event) {
643
- if (accessToken !== "") {
644
- console.log("WebSocket closed, reconnecting in 3 seconds...", event.reason);
645
- setTimeout(connect, 3e3);
646
- }
647
- };
648
- ws.onerror = function(err) {
649
- console.error("WebSocket error observed:", err);
650
- ws.close();
651
- };
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!");
652
534
  };
653
- if (accessToken !== "") connect();
654
- }
655
- };
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
+ };
656
552
 
657
553
  //#endregion
658
554
  //#region src/Stats.ts
659
- /**
660
- * @author Martin Høgh <mh@mapcentia.com>
661
- * @copyright 2013-2026 MapCentia ApS
662
- * @license https://opensource.org/license/mit The MIT License
663
- *
664
- */
665
- var Stats = class {
666
- async get() {
667
- return await get_response_default(await make_request_default("4", `stats`, "GET", null), 200);
668
- }
669
- };
555
+ var Stats = class {
556
+ async get() {
557
+ return await get_response_default(await make_request_default("4", `stats`, "GET", null), 200);
558
+ }
559
+ };
670
560
 
671
561
  //#endregion
672
562
  //#region src/Tables.ts
673
- /**
674
- * @author Martin Høgh <mh@mapcentia.com>
675
- * @copyright 2013-2026 MapCentia ApS
676
- * @license https://opensource.org/license/mit The MIT License
677
- *
678
- */
679
- var Tables = class {
680
- async get(schema, table) {
681
- return await get_response_default(await make_request_default("4", `schemas/${encodeURIComponent(schema)}/tables/${encodeURIComponent(table)}`, "GET", null), 200);
682
- }
683
- async create(schema, table, payload) {
684
- return await get_response_default(await make_request_default("4", `schemas/${encodeURIComponent(schema)}/tables/${encodeURIComponent(table)}`, "POST", payload), 200);
685
- }
686
- async patch(schema, table, payload) {
687
- return await get_response_default(await make_request_default("4", `schemas/${encodeURIComponent(schema)}/tables/${encodeURIComponent(table)}`, "PATCH", payload), 200);
688
- }
689
- async delete(schema, table) {
690
- return await get_response_default(await make_request_default("4", `schemas/${encodeURIComponent(schema)}/tables/${encodeURIComponent(table)}`, "DELETE", null), 204);
691
- }
692
- };
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
+ };
693
577
 
694
578
  //#endregion
695
579
  //#region src/Api.ts
696
- /**
697
- * @author Martin Høgh <mh@mapcentia.com>
698
- * @copyright 2013-2026 MapCentia ApS
699
- * @license https://opensource.org/license/mit The MIT License
700
- *
701
- */
702
- function isPlainObject$1(v) {
703
- return typeof v === "object" && v !== null && !Array.isArray(v);
704
- }
705
- function validateParamsForMethod(method, params) {
706
- if (Array.isArray(params)) {
707
- const badIndex = params.findIndex((p) => !isPlainObject$1(p));
708
- if (badIndex !== -1) throw new TypeError(`createApi: Invalid argument at index ${badIndex} for RPC method "${method}". Expected a plain object.`);
709
- return params;
710
- }
711
- if (params === void 0) return {};
712
- 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.`);
713
587
  return params;
714
588
  }
715
- function extractDataFromResponse(method, res) {
716
- if (!res || typeof res !== "object") throw new TypeError(`createApi: Invalid RPC response for method "${method}". Expected an object.`);
717
- if (res.jsonrpc !== "2.0") throw new TypeError(`createApi: Invalid RPC response for method "${method}". Missing or invalid jsonrpc version.`);
718
- const err = res.error;
719
- if (err !== void 0) {
720
- if (!err || typeof err !== "object") throw new TypeError(`createApi: Invalid RPC error for method "${method}". Expected 'error' to be an object.`);
721
- const code = err.code;
722
- const message = err.message;
723
- const data$1 = err.data;
724
- const codeIsNum = typeof code === "number" && Number.isFinite(code);
725
- const details = typeof message === "string" && message.length > 0 ? message : "Unknown error";
726
- const e = /* @__PURE__ */ new Error(`createApi: RPC error for method "${method}"${codeIsNum ? ` (${code})` : ""}: ${details}`);
727
- e.code = code;
728
- if (data$1 !== void 0) e.data = data$1;
729
- e.method = method;
730
- e.name = "JsonRpcError";
731
- throw e;
732
- }
733
- const result = res.result;
734
- if (!result || typeof result !== "object") throw new TypeError(`createApi: Invalid RPC response for method "${method}". Missing result object.`);
735
- const data = result.data;
736
- if (!Array.isArray(data)) throw new TypeError(`createApi: Invalid RPC response for method "${method}". Expected result.data to be an array.`);
737
- return data;
738
- }
739
- async function dispatch(name, paramsLike) {
740
- if (typeof name !== "string" || name.length === 0) throw new TypeError("createApi: RPC method name must be a non-empty string.");
741
- const params = validateParamsForMethod(String(name), paramsLike);
742
- const rpc = new Rpc();
743
- const request = {
744
- jsonrpc: "2.0",
745
- method: name,
746
- id: 1,
747
- params
748
- };
749
- const res = await rpc.call(request);
750
- return extractDataFromResponse(String(name), res);
751
- }
752
- function createApi() {
753
- return new Proxy({}, { get(_target, prop) {
754
- if (typeof prop !== "string") return void 0;
755
- return (...args) => {
756
- return dispatch(prop, args.length === 0 ? {} : args.length === 1 ? args[0] : args);
757
- };
758
- } });
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;
759
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
+ }
760
638
 
761
639
  //#endregion
762
640
  //#region src/SignUp.ts
763
- /**
764
- * @author Martin Høgh <mh@mapcentia.com>
765
- * @copyright 2013-2026 MapCentia ApS
766
- * @license https://opensource.org/license/mit The MIT License
767
- *
768
- */
769
- var SignUp = class {
770
- constructor(options) {
771
- this.options = options;
772
- this.service = new Gc2Service(options);
773
- }
774
- async signUp() {
775
- window.location.assign(this.service.getSignUpURL());
776
- }
777
- };
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
+ };
778
650
 
779
651
  //#endregion
780
652
  //#region src/SqlBuilder.ts
781
- function findTable(schema, name) {
782
- const tbl = schema.tables.find((t) => t.name === name);
783
- if (!tbl) throw new Error(`Table not found in schema: ${name}`);
784
- return tbl;
785
- }
786
- function findColumn(table, name) {
787
- const col = table.columns.find((c) => c.name === name);
788
- if (!col) throw new Error(`Column not found in table ${table.name}: ${name}`);
789
- return col;
790
- }
791
- function getPrimaryKeyColumns(table) {
792
- const pk = (table.constraints || []).find((c) => c.constraint === "primary" && Array.isArray(c.columns) && c.columns.length > 0);
793
- return pk ? pk.columns.map(String) : [];
794
- }
795
- function typeNameToHint(typname, isArray) {
796
- if (!typname) return void 0;
797
- const base = typname;
798
- return isArray ? base + "[]" : base;
799
- }
800
- function addTypeHintForParam(typeHints, paramName, col, value) {
801
- let isArr = col._is_array;
802
- if (Array.isArray(value)) if (isArrayShapedGeomTypename(col._typname)) isArr = value.every(Array.isArray);
803
- else isArr = true;
804
- const hint = typeNameToHint(col._typname, isArr);
805
- if (hint) typeHints[paramName] = hint;
806
- }
807
- function expectedScalarKind(typname) {
808
- const t = typname.toLowerCase();
809
- if (t === "int2" || t === "int4" || t === "int8" || t === "float4" || t === "float8") return "number";
810
- if (t === "numeric" || t === "decimal") return "string";
811
- if (t === "varchar" || t === "text" || t === "bpchar" || t === "char" || t === "date" || t === "time" || t === "timetz" || t === "timestamp" || t === "timestamptz") return "string";
812
- if (t === "bool") return "boolean";
813
- if (t === "json" || t === "jsonb") return "json";
814
- if (t === "int4range" || t === "int8range" || t === "numrange" || t === "tsrange" || t === "tstzrange" || t === "daterange") return "range";
815
- if (t === "interval") return "interval";
816
- if (t === "point" || t === "line" || t === "lseg" || t === "box" || t === "path" || t === "polygon" || t === "circle") return "geom";
817
- return "unknown";
818
- }
819
- function isArrayShapedGeomTypename(typname) {
820
- const t = typname.toLowerCase();
821
- return t === "path" || t === "polygon";
822
- }
823
- function isArrayShapedGeomScalarValue(col, value) {
824
- if (!Array.isArray(value)) return false;
825
- if (!isArrayShapedGeomTypename(col._typname)) return false;
826
- return !value.every(Array.isArray);
827
- }
828
- function expectedRangeInnerKind(typname) {
829
- const t = typname.toLowerCase();
830
- if (t === "int4range" || t === "int8range") return "number";
831
- if (t === "numrange" || t === "tsrange" || t === "tstzrange" || t === "daterange") return "string";
832
- return "unknown";
833
- }
834
- function isPlainObject(v) {
835
- return typeof v === "object" && v !== null && !Array.isArray(v);
836
- }
837
- function isFiniteNumber(n) {
838
- return typeof n === "number" && Number.isFinite(n);
839
- }
840
- function isPointLike(v) {
841
- if (!isPlainObject(v)) return false;
842
- const x = v.x;
843
- const y = v.y;
844
- return isFiniteNumber(x) && isFiniteNumber(y);
845
- }
846
- function validateGeometryForColumn(col, value, context) {
847
- const t = col._typname.toLowerCase();
848
- if (t === "point") {
849
- if (!isPointLike(value)) throw new Error(`Invalid value for ${context}. Expected Point { x: number, y: number }`);
850
- return;
851
- }
852
- if (t === "line") {
853
- if (!isPlainObject(value)) throw new Error(`Invalid value for ${context}. Expected Line { A: number, B: number, C: number }`);
854
- const A = value.A, B = value.B, C = value.C;
855
- if (!isFiniteNumber(A) || !isFiniteNumber(B) || !isFiniteNumber(C)) throw new Error(`Invalid Line for ${context}. A, B, C must be finite numbers`);
856
- return;
857
- }
858
- if (t === "lseg" || t === "box") {
859
- if (!isPlainObject(value)) throw new Error(`Invalid value for ${context}. Expected ${t.toUpperCase()} { start: Point, end: Point }`);
860
- const start = value.start;
861
- const end = value.end;
862
- if (!isPointLike(start) || !isPointLike(end)) throw new Error(`Invalid ${t} for ${context}. 'start' and 'end' must be Point { x, y }`);
863
- return;
864
- }
865
- if (t === "path") {
866
- if (!Array.isArray(value) || value.length < 1) throw new Error(`Invalid value for ${context}. Expected Path [isClosed: boolean, ...points: Point[]]`);
867
- const [isClosed, ...points] = value;
868
- if (typeof isClosed !== "boolean") throw new Error(`Invalid Path for ${context}. First element must be boolean (isClosed)`);
869
- 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 }`);
870
- return;
871
- }
872
- if (t === "polygon") {
873
- if (!Array.isArray(value)) throw new Error(`Invalid value for ${context}. Expected Polygon as Point[]`);
874
- 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 }`);
875
- return;
876
- }
877
- if (t === "circle") {
878
- if (!isPlainObject(value)) throw new Error(`Invalid value for ${context}. Expected Circle { center: Point, radius: number }`);
879
- const center = value.center;
880
- const radius = value.radius;
881
- if (!isPointLike(center) || !isFiniteNumber(radius)) throw new Error(`Invalid Circle for ${context}. 'center' must be Point and 'radius' must be finite number`);
882
- return;
883
- }
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;
884
723
  }
885
- function validateRangeForColumn(col, value, context) {
886
- if (!isPlainObject(value)) throw new Error(`Invalid value for ${context}. Expected a range object for type ${col._typname}`);
887
- const r = value;
888
- const hasLower = Object.prototype.hasOwnProperty.call(r, "lower");
889
- const hasUpper = Object.prototype.hasOwnProperty.call(r, "upper");
890
- const hasLi = Object.prototype.hasOwnProperty.call(r, "lowerInclusive");
891
- const hasUi = Object.prototype.hasOwnProperty.call(r, "upperInclusive");
892
- if (!hasLower || !hasUpper || !hasLi || !hasUi) throw new Error(`Invalid range for ${context}. Required properties: lower, upper, lowerInclusive, upperInclusive`);
893
- if (typeof r.lowerInclusive !== "boolean" || typeof r.upperInclusive !== "boolean") throw new Error(`Invalid range for ${context}. lowerInclusive and upperInclusive must be boolean`);
894
- const inner = expectedRangeInnerKind(col._typname);
895
- if (inner === "number") {
896
- if (typeof r.lower !== "number" || !Number.isFinite(r.lower)) throw new Error(`Invalid range.lower for ${context}. Expected number for type ${col._typname}`);
897
- if (typeof r.upper !== "number" || !Number.isFinite(r.upper)) throw new Error(`Invalid range.upper for ${context}. Expected number for type ${col._typname}`);
898
- } else if (inner === "string") {
899
- if (typeof r.lower !== "string") throw new Error(`Invalid range.lower for ${context}. Expected string for type ${col._typname}`);
900
- if (typeof r.upper !== "string") throw new Error(`Invalid range.upper for ${context}. Expected string for type ${col._typname}`);
901
- }
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;
902
729
  }
903
- function validateIntervalForColumn(col, value, context) {
904
- if (!isPlainObject(value)) throw new Error(`Invalid value for ${context}. Expected an interval object for type ${col._typname}`);
905
- const v = value;
906
- for (const k of [
907
- "y",
908
- "m",
909
- "d",
910
- "h",
911
- "i",
912
- "s"
913
- ]) {
914
- if (!Object.prototype.hasOwnProperty.call(v, k)) throw new Error(`Invalid interval for ${context}. Missing property '${k}'`);
915
- const num = v[k];
916
- if (typeof num !== "number" || !Number.isFinite(num)) throw new Error(`Invalid interval.${String(k)} for ${context}. Expected finite number`);
917
- }
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;
918
736
  }
919
- function isValidJsonLike(value) {
920
- 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;
921
743
  }
922
- function validateScalarForColumn(col, value, context) {
923
- const kind = expectedScalarKind(col._typname);
924
- if (kind === "unknown") return;
925
- if (kind === "number") {
926
- if (typeof value !== "number" || !Number.isFinite(value)) throw new Error(`Invalid value for ${context}. Expected number for type ${col._typname}, got ${typeof value}`);
927
- return;
928
- }
929
- if (kind === "string") {
930
- if (typeof value !== "string") throw new Error(`Invalid value for ${context}. Expected string for type ${col._typname}, got ${typeof value}`);
931
- return;
932
- }
933
- if (kind === "boolean") {
934
- if (typeof value !== "boolean") throw new Error(`Invalid value for ${context}. Expected boolean for type ${col._typname}, got ${typeof value}`);
935
- return;
936
- }
937
- if (kind === "json") {
938
- if (!isValidJsonLike(value)) throw new Error(`Invalid value for ${context}. Expected JSON-compatible value for type ${col._typname}`);
939
- return;
940
- }
941
- if (kind === "range") {
942
- validateRangeForColumn(col, value, context);
943
- return;
944
- }
945
- if (kind === "interval") {
946
- validateIntervalForColumn(col, value, context);
947
- return;
948
- }
949
- if (kind === "geom") {
950
- validateGeometryForColumn(col, value, context);
951
- return;
952
- }
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;
953
748
  }
954
- function validateComparisonValue(col, key, value, op) {
955
- 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.`);
956
- if (col._is_array) {
957
- if (!Array.isArray(value)) throw new Error(`Operator ${op} on array column ${key} requires an array value`);
958
- for (const [i, v] of value.entries()) validateScalarForColumn(col, v, `column ${key}[${i}]`);
959
- } else {
960
- if (Array.isArray(value) && !isArrayShapedGeomScalarValue(col, value)) throw new Error(`Operator ${op} on scalar column ${key} cannot accept an array value`);
961
- validateScalarForColumn(col, value, `column ${key}`);
962
- }
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;
963
755
  }
964
- function validateInArrayValues(col, key, values, op) {
965
- if (!col._is_array) {
966
- let idx = 0;
967
- for (const v of values) {
968
- validateScalarForColumn(col, v, `column ${key} (element ${idx})`);
969
- idx++;
970
- }
971
- }
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;
972
800
  }
973
- function findJoinOn(base, target) {
974
- const bc = base.constraints || [];
975
- const tc = target.constraints || [];
976
- 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) => ({
977
- left: String(col),
978
- right: String(c.referenced_columns[i])
979
- }));
980
- 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) => ({
981
- left: String(rcol),
982
- right: String(c.columns[i])
983
- }));
984
- return null;
985
- }
986
- var TableQueryImpl = class {
987
- constructor(schema, tableName) {
988
- this.schema = schema;
989
- this.table = findTable(schema, tableName);
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;
804
+ }
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++;
990
842
  }
991
- select(cols) {
992
- const table = this.table;
993
- const schema = this.schema;
994
- const selected = cols && cols.length ? cols : ["*"];
995
- const state = {
996
- table,
997
- selected,
998
- where: {},
999
- orWhereGroups: [],
1000
- andOps: [],
1001
- orOpGroups: [],
1002
- order: [],
1003
- limit: void 0,
1004
- offset: void 0,
1005
- joins: [],
1006
- joinSelections: []
1007
- };
1008
- return new class {
1009
- constructor() {
1010
- this.s = state;
1011
- this.toSql = () => {
1012
- const params = {};
1013
- const type_hints = {};
1014
- let p = 0;
1015
- const parts = [];
1016
- const selectParts = [];
1017
- if (selected.length === 1 && selected[0] === "*") selectParts.push(`"${table.name}".*`);
1018
- else {
1019
- const sel = selected;
1020
- for (const c of sel) findColumn(table, String(c));
1021
- selectParts.push(sel.map((c) => `"${table.name}"."${c}"`).join(", "));
1022
- }
1023
- for (const js of state.joinSelections) if (js.selected.length === 1 && js.selected[0] === "*") selectParts.push(`"${js.target.name}".*`);
1024
- else {
1025
- const cols$1 = js.selected;
1026
- for (const c of cols$1) findColumn(js.target, String(c));
1027
- 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);
1028
925
  }
1029
- parts.push(`select ${selectParts.join(", ")} from "${schema.name}"."${table.name}"`);
1030
- for (const j of state.joins) {
1031
- const onExpr = j.on.map((p$1) => `"${j.source.name}"."${p$1.left}" = "${j.target.name}"."${p$1.right}"`).join(" and ");
1032
- 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);
1033
965
  }
1034
- const andParts = [];
1035
- for (const key in state.where) {
1036
- 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];
1037
972
  const col = findColumn(table, key);
1038
973
  p += 1;
1039
974
  const paramName = `${table.name}_${key}_${p}`;
1040
975
  if (value === null) {
1041
976
  if (!col.is_nullable) throw new Error(`Column ${table.name}.${key} is not nullable; cannot compare to null`);
1042
- andParts.push(`"${table.name}"."${key}" is null`);
977
+ orParts.push(`"${table.name}"."${key}" is null`);
1043
978
  } else if (Array.isArray(value) && !isArrayShapedGeomScalarValue(col, value)) {
1044
979
  validateInArrayValues(col, key, value, "in");
1045
- andParts.push(`"${table.name}"."${key}" = ANY(:${paramName})`);
980
+ orParts.push(`"${table.name}"."${key}" = ANY(:${paramName})`);
1046
981
  params[paramName] = value;
1047
982
  addTypeHintForParam(type_hints, paramName, col, value);
1048
983
  } else {
1049
984
  validateScalarForColumn(col, value, `column ${key}`);
1050
- andParts.push(`"${table.name}"."${key}" = :${paramName}`);
985
+ orParts.push(`"${table.name}"."${key}" = :${paramName}`);
1051
986
  params[paramName] = value;
1052
987
  addTypeHintForParam(type_hints, paramName, col, value);
1053
988
  }
1054
989
  }
1055
- 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) {
1056
995
  const key = String(pred.col);
1057
996
  const op = String(pred.op);
1058
997
  const col = findColumn(table, key);
1059
998
  const qualified = `"${table.name}"."${key}"`;
1060
999
  if (op === "isnull" || op === "notnull") {
1061
1000
  if (pred.value !== void 0) throw new Error(`Operator ${op} does not take a value for column ${key}`);
1062
- andParts.push(`${qualified} is ${op === "isnull" ? "null" : "not null"}`);
1001
+ orParts.push(`${qualified} is ${op === "isnull" ? "null" : "not null"}`);
1063
1002
  } else if (op === "in" || op === "notin") {
1064
1003
  const val = pred.value;
1065
1004
  if (!Array.isArray(val)) throw new Error(`Operator ${op} requires an array value for column ${key}`);
1066
1005
  validateInArrayValues(col, key, val, op);
1067
1006
  p += 1;
1068
1007
  const paramName = `${table.name}_${key}_${p}`;
1069
- andParts.push(`${qualified} ${op === "in" ? "= ANY" : "!= ALL"}(:${paramName})`);
1008
+ orParts.push(`${qualified} ${op === "in" ? "= ANY" : "!= ALL"}(:${paramName})`);
1070
1009
  params[paramName] = val;
1071
1010
  addTypeHintForParam(type_hints, paramName, col, val);
1072
1011
  } else if (op === "like" || op === "ilike" || op === "notlike" || op === "notilike") {
@@ -1075,7 +1014,7 @@
1075
1014
  p += 1;
1076
1015
  const paramName = `${table.name}_${key}_${p}`;
1077
1016
  const sqlOp = op === "like" ? "like" : op === "ilike" ? "ilike" : op === "notlike" ? "not like" : "not ilike";
1078
- andParts.push(`${qualified} ${sqlOp} :${paramName}`);
1017
+ orParts.push(`${qualified} ${sqlOp} :${paramName}`);
1079
1018
  params[paramName] = val;
1080
1019
  addTypeHintForParam(type_hints, paramName, col, val);
1081
1020
  } else {
@@ -1084,137 +1023,252 @@
1084
1023
  validateComparisonValue(col, key, val, op);
1085
1024
  p += 1;
1086
1025
  const paramName = `${table.name}_${key}_${p}`;
1087
- if (op === "=") andParts.push(`${qualified} = :${paramName}`);
1088
- else if (op === "!=") andParts.push(`${qualified} <> :${paramName}`);
1089
- 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}`);
1090
1029
  else throw new Error(`Unsupported operator: ${op}`);
1091
1030
  params[paramName] = val;
1092
1031
  addTypeHintForParam(type_hints, paramName, col, val);
1093
1032
  }
1094
1033
  }
1095
- const orGroupSql = [];
1096
- for (const group of state.orWhereGroups) {
1097
- const orParts = [];
1098
- for (const key in group) {
1099
- const value = group[key];
1100
- const col = findColumn(table, key);
1101
- p += 1;
1102
- const paramName = `${table.name}_${key}_${p}`;
1103
- if (value === null) {
1104
- if (!col.is_nullable) throw new Error(`Column ${table.name}.${key} is not nullable; cannot compare to null`);
1105
- orParts.push(`"${table.name}"."${key}" is null`);
1106
- } else if (Array.isArray(value) && !isArrayShapedGeomScalarValue(col, value)) {
1107
- validateInArrayValues(col, key, value, "in");
1108
- orParts.push(`"${table.name}"."${key}" = ANY(:${paramName})`);
1109
- params[paramName] = value;
1110
- addTypeHintForParam(type_hints, paramName, col, value);
1111
- } else {
1112
- validateScalarForColumn(col, value, `column ${key}`);
1113
- orParts.push(`"${table.name}"."${key}" = :${paramName}`);
1114
- params[paramName] = value;
1115
- addTypeHintForParam(type_hints, paramName, col, value);
1116
- }
1117
- }
1118
- if (orParts.length) orGroupSql.push("(" + orParts.join(" or ") + ")");
1119
- }
1120
- for (const group of state.orOpGroups) {
1121
- const orParts = [];
1122
- for (const pred of group) {
1123
- const key = String(pred.col);
1124
- const op = String(pred.op);
1125
- const col = findColumn(table, key);
1126
- const qualified = `"${table.name}"."${key}"`;
1127
- if (op === "isnull" || op === "notnull") {
1128
- if (pred.value !== void 0) throw new Error(`Operator ${op} does not take a value for column ${key}`);
1129
- orParts.push(`${qualified} is ${op === "isnull" ? "null" : "not null"}`);
1130
- } else if (op === "in" || op === "notin") {
1131
- const val = pred.value;
1132
- if (!Array.isArray(val)) throw new Error(`Operator ${op} requires an array value for column ${key}`);
1133
- validateInArrayValues(col, key, val, op);
1134
- p += 1;
1135
- const paramName = `${table.name}_${key}_${p}`;
1136
- orParts.push(`${qualified} ${op === "in" ? "= ANY" : "!= ALL"}(:${paramName})`);
1137
- params[paramName] = val;
1138
- addTypeHintForParam(type_hints, paramName, col, val);
1139
- } else if (op === "like" || op === "ilike" || op === "notlike" || op === "notilike") {
1140
- const val = pred.value;
1141
- if (typeof val !== "string") throw new Error(`Operator ${op} requires a string value for column ${key}`);
1142
- p += 1;
1143
- const paramName = `${table.name}_${key}_${p}`;
1144
- const sqlOp = op === "like" ? "like" : op === "ilike" ? "ilike" : op === "notlike" ? "not like" : "not ilike";
1145
- orParts.push(`${qualified} ${sqlOp} :${paramName}`);
1146
- params[paramName] = val;
1147
- addTypeHintForParam(type_hints, paramName, col, val);
1148
- } else {
1149
- const val = pred.value;
1150
- if (val === void 0) throw new Error(`Operator ${op} requires a value for column ${key}`);
1151
- validateComparisonValue(col, key, val, op);
1152
- p += 1;
1153
- const paramName = `${table.name}_${key}_${p}`;
1154
- if (op === "=") orParts.push(`${qualified} = :${paramName}`);
1155
- else if (op === "!=") orParts.push(`${qualified} <> :${paramName}`);
1156
- else if (op === "<" || op === "<=" || op === ">" || op === ">=") orParts.push(`${qualified} ${op} :${paramName}`);
1157
- else throw new Error(`Unsupported operator: ${op}`);
1158
- params[paramName] = val;
1159
- addTypeHintForParam(type_hints, paramName, col, val);
1160
- }
1161
- }
1162
- if (orParts.length) orGroupSql.push("(" + orParts.join(" or ") + ")");
1163
- }
1164
- if (orGroupSql.length) {
1165
- const andSql = andParts.length ? `(${andParts.join(" and ")})` : "";
1166
- const orSql = orGroupSql.join(" or ");
1167
- const full = andSql ? `${andSql} or ${orSql}` : orSql;
1168
- if (full.trim().length) parts.push("where " + full);
1169
- } else if (andParts.length) parts.push("where " + andParts.join(" and "));
1170
- if (state.order.length) {
1171
- const orders = [];
1172
- for (const o of state.order) orders.push(`"${table.name}"."${o.col}" ${o.dir}`);
1173
- parts.push("order by " + orders.join(", "));
1174
- }
1175
- if (state.limit !== void 0) parts.push("limit " + state.limit);
1176
- if (state.offset !== void 0) parts.push("offset " + state.offset);
1177
- return {
1178
- q: parts.join(" "),
1179
- params: Object.keys(params).length > 0 ? params : void 0,
1180
- type_hints: Object.keys(type_hints).length ? type_hints : void 0
1181
- };
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
1182
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;
1183
1114
  }
1184
- selectFrom(tableName, cols$1) {
1185
- const jtName = String(tableName);
1186
- const join = this.s.joins.find((j) => j.target.name === jtName);
1187
- if (!join) throw new Error(`selectFrom('${jtName}') requires a prior join('${jtName}') call`);
1188
- const sel = !cols$1 || cols$1.length === 0 ? ["*"] : cols$1.map(String);
1189
- if (!(sel.length === 1 && sel[0] === "*")) for (const c of sel) findColumn(join.target, String(c));
1190
- const existing = this.s.joinSelections.find((js) => js.target.name === jtName);
1191
- if (existing) {
1192
- if (existing.selected.includes("*")) return this;
1193
- if (sel.length === 1 && sel[0] === "*") existing.selected = ["*"];
1194
- else {
1195
- const set = new Set(existing.selected);
1196
- for (const c of sel) set.add(String(c));
1197
- existing.selected = Array.from(set);
1198
- }
1199
- } else this.s.joinSelections.push({
1200
- target: join.target,
1201
- 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
1202
1169
  });
1203
- return this;
1204
1170
  }
1205
- andWhere(where) {
1206
- for (const k in where) this.s.where[k] = where[k];
1207
- 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);
1208
1189
  }
1209
- /** @deprecated Use andWhere() instead */
1210
- where(where) {
1211
- 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
+ }
1212
1200
  }
1213
- orWhere(where) {
1214
- this.s.orWhereGroups.push(where);
1215
- 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);
1216
1244
  }
1217
- 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) => {
1218
1272
  const pkCols = getPrimaryKeyColumns(table);
1219
1273
  if (!pkCols || pkCols.length === 0) throw new Error(`Table ${table.name} does not have a primary key`);
1220
1274
  if (pkCols.length === 1) {
@@ -1224,8 +1278,7 @@
1224
1278
  if (Array.isArray(pk)) throw new Error(`wherePk on ${table.name} expects a scalar for primary key column ${colName}, not an array`);
1225
1279
  if (isPlainObject(pk)) throw new Error(`wherePk on ${table.name} expects a scalar for primary key column ${colName}`);
1226
1280
  validateScalarForColumn(colDef, pk, `primary key ${table.name}.${colName}`);
1227
- this.s.where[colName] = pk;
1228
- return this;
1281
+ state.where[colName] = pk;
1229
1282
  } else {
1230
1283
  if (!isPlainObject(pk) || pk === null) throw new Error(`wherePk on ${table.name} requires an object with keys: ${pkCols.join(", ")}`);
1231
1284
  const obj = pk;
@@ -1236,336 +1289,146 @@
1236
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(", ")})`);
1237
1290
  if (Array.isArray(v)) throw new Error(`wherePk on ${table.name} expects scalar values for primary key column ${colName}, not an array`);
1238
1291
  validateScalarForColumn(findColumn(table, colName), v, `primary key ${table.name}.${colName}`);
1239
- this.s.where[colName] = v;
1292
+ state.where[colName] = v;
1240
1293
  }
1241
- return this;
1242
1294
  }
1243
- }
1244
- andWhereOp(col, op, ...args) {
1245
- const value = args[0];
1246
- this.s.andOps.push({
1247
- col,
1248
- op,
1249
- value
1250
- });
1251
- return this;
1252
- }
1253
- orWhereOp(col, op, ...args) {
1254
- const value = args[0];
1255
- this.s.orOpGroups.push([{
1256
- col,
1257
- op,
1258
- value
1259
- }]);
1260
- return this;
1261
- }
1262
- andWhereOpGroup(predicates) {
1263
- const group = predicates.map((p) => ({
1264
- col: p[0],
1265
- op: p[1],
1266
- value: p[2]
1267
- }));
1268
- for (const g of group) this.s.andOps.push(g);
1269
- return this;
1270
- }
1271
- orWhereOpGroup(predicates) {
1272
- const group = predicates.map((p) => ({
1273
- col: p[0],
1274
- op: p[1],
1275
- value: p[2]
1276
- }));
1277
- this.s.orOpGroups.push(group);
1278
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);
1279
1315
  }
1280
- orderBy(order) {
1281
- this.s.order = [];
1282
- const isValidDir = (d) => d === "asc" || d === "desc";
1283
- if (typeof order === "string") {
1284
- findColumn(table, String(order));
1285
- this.s.order.push({
1286
- col: order,
1287
- dir: "asc"
1288
- });
1289
- } else for (const item of order) {
1290
- const col = String(item[0]);
1291
- const dir = String(item[1]);
1292
- findColumn(table, col);
1293
- if (!isValidDir(dir)) throw new Error(`Invalid order direction: ${dir}. Allowed: asc | desc`);
1294
- this.s.order.push({
1295
- col: item[0],
1296
- dir
1297
- });
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);
1298
1335
  }
1299
- return this;
1300
1336
  }
1301
- limit(n) {
1302
- 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`);
1303
- this.s.limit = n;
1304
- return this;
1305
- }
1306
- offset(n) {
1307
- 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`);
1308
- 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];
1309
1361
  return this;
1310
- }
1311
- join(tableName, type = "inner") {
1312
- const target = findTable(schema, String(tableName));
1313
- const sources = [];
1314
- for (let i = this.s.joins.length - 1; i >= 0; i--) {
1315
- const src = this.s.joins[i].target;
1316
- if (!sources.some((s) => s.name === src.name)) sources.push(src);
1317
- }
1318
- if (!sources.some((s) => s.name === table.name)) sources.push(table);
1319
- let pickedSource = null;
1320
- let pairs = null;
1321
- for (const src of sources) {
1322
- const p = findJoinOn(src, target);
1323
- if (p && p.length) {
1324
- pickedSource = src;
1325
- pairs = p;
1326
- 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];
1327
1377
  }
1328
1378
  }
1329
- if (!pairs || !pickedSource) {
1330
- const candidates = sources.map((s) => s.name).join(", ");
1331
- throw new Error(`No foreign key relation found between any of [${candidates}] and ${target.name}`);
1332
- }
1333
- const jt = String(type);
1334
- if (jt !== "inner" && jt !== "left" && jt !== "right" && jt !== "full") throw new Error(`Invalid join type: ${jt}. Allowed: inner | left | right | full`);
1335
- this.s.joins.push({
1336
- type: jt,
1337
- source: pickedSource,
1338
- target,
1339
- on: pairs
1340
- });
1341
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
+ }
1342
1410
  }
1343
- }();
1344
- }
1345
- insert(values) {
1346
- const table = this.table;
1347
- const schema = this.schema;
1348
- const state = {
1349
- values,
1350
- returning: []
1351
- };
1352
- return new class {
1353
- constructor() {
1354
- this.returning = (cols) => {
1355
- state.returning = cols || [];
1356
- return this;
1357
- };
1358
- this.toSql = () => {
1359
- const cols = [];
1360
- const vals = [];
1361
- const params = {};
1362
- const type_hints = {};
1363
- let p = 0;
1364
- for (const key in state.values) {
1365
- const value = state.values[key];
1366
- const col = findColumn(table, key);
1367
- p += 1;
1368
- const paramName = `${table.name}_${key}_${p}`;
1369
- cols.push(`"${key}"`);
1370
- vals.push(`:${paramName}`);
1371
- params[paramName] = value;
1372
- addTypeHintForParam(type_hints, paramName, col, value);
1373
- }
1374
- const parts = [];
1375
- parts.push(`insert into "${schema.name}"."${table.name}" (${cols.join(", ")}) values (${vals.join(", ")})`);
1376
- if (state.returning.length) parts.push("returning " + state.returning.join(", "));
1377
- return {
1378
- q: parts.join(" "),
1379
- params: Object.keys(params).length > 0 ? params : void 0,
1380
- type_hints: Object.keys(type_hints).length ? type_hints : void 0
1381
- };
1382
- };
1383
- }
1384
- }();
1385
- }
1386
- update(values) {
1387
- const table = this.table;
1388
- const schema = this.schema;
1389
- const state = {
1390
- values,
1391
- where: {},
1392
- returning: []
1393
- };
1394
- return new class {
1395
- constructor() {
1396
- this.where = (w) => {
1397
- for (const k in w) state.where[k] = w[k];
1398
- return this;
1399
- };
1400
- this.wherePk = (pk) => {
1401
- const pkCols = getPrimaryKeyColumns(table);
1402
- if (!pkCols || pkCols.length === 0) throw new Error(`Table ${table.name} does not have a primary key`);
1403
- if (pkCols.length === 1) {
1404
- const colName = pkCols[0];
1405
- const colDef = findColumn(table, colName);
1406
- if (pk === null || pk === void 0) throw new Error(`wherePk on ${table.name} requires a non-null value for primary key column ${colName}`);
1407
- if (Array.isArray(pk)) throw new Error(`wherePk on ${table.name} expects a scalar for primary key column ${colName}, not an array`);
1408
- if (isPlainObject(pk)) throw new Error(`wherePk on ${table.name} expects a scalar for primary key column ${colName}`);
1409
- validateScalarForColumn(colDef, pk, `primary key ${table.name}.${colName}`);
1410
- state.where[colName] = pk;
1411
- } else {
1412
- if (!isPlainObject(pk) || pk === null) throw new Error(`wherePk on ${table.name} requires an object with keys: ${pkCols.join(", ")}`);
1413
- const obj = pk;
1414
- for (const k of Object.keys(obj)) if (!pkCols.includes(k)) throw new Error(`wherePk received unknown key '${k}'. Expected keys: ${pkCols.join(", ")}`);
1415
- for (const colName of pkCols) {
1416
- if (!(colName in obj)) throw new Error(`wherePk missing key '${colName}'. Required keys: ${pkCols.join(", ")}`);
1417
- const v = obj[colName];
1418
- if (v === null || v === void 0) throw new Error(`wherePk on ${table.name} requires non-null values for all primary key columns (${pkCols.join(", ")})`);
1419
- if (Array.isArray(v)) throw new Error(`wherePk on ${table.name} expects scalar values for primary key column ${colName}, not an array`);
1420
- validateScalarForColumn(findColumn(table, colName), v, `primary key ${table.name}.${colName}`);
1421
- state.where[colName] = v;
1422
- }
1423
- }
1424
- return this;
1425
- };
1426
- this.returning = (cols) => {
1427
- state.returning = cols || [];
1428
- return this;
1429
- };
1430
- this.toSql = () => {
1431
- const params = {};
1432
- const type_hints = {};
1433
- let p = 0;
1434
- const setParts = [];
1435
- for (const key in state.values) {
1436
- const value = state.values[key];
1437
- const col = findColumn(table, key);
1438
- p += 1;
1439
- const paramName = `${table.name}_${key}_${p}`;
1440
- setParts.push(`"${key}" = :${paramName}`);
1441
- params[paramName] = value;
1442
- addTypeHintForParam(type_hints, paramName, col, value);
1443
- }
1444
- const whereClauses = [];
1445
- for (const key in state.where) {
1446
- const value = state.where[key];
1447
- const col = findColumn(table, key);
1448
- p += 1;
1449
- const paramName = `${table.name}_${key}_${p}`;
1450
- if (value === null) {
1451
- if (!col.is_nullable) throw new Error(`Column ${table.name}.${key} is not nullable; cannot compare to null`);
1452
- whereClauses.push(`"${key}" is null`);
1453
- } else if (Array.isArray(value) && !isArrayShapedGeomScalarValue(col, value)) {
1454
- validateInArrayValues(col, key, value, "in");
1455
- whereClauses.push(`"${key}" = ANY(:${paramName})`);
1456
- params[paramName] = value;
1457
- addTypeHintForParam(type_hints, paramName, col, value);
1458
- } else {
1459
- validateScalarForColumn(col, value, `column ${key}`);
1460
- whereClauses.push(`"${key}" = :${paramName}`);
1461
- params[paramName] = value;
1462
- addTypeHintForParam(type_hints, paramName, col, value);
1463
- }
1464
- }
1465
- const parts = [];
1466
- parts.push(`update "${schema.name}"."${table.name}" set ${setParts.join(", ")}`);
1467
- if (whereClauses.length) parts.push("where " + whereClauses.join(" and "));
1468
- if (state.returning.length) parts.push("returning " + state.returning.join(", "));
1469
- return {
1470
- q: parts.join(" "),
1471
- params: Object.keys(params).length > 0 ? params : void 0,
1472
- type_hints: Object.keys(type_hints).length ? type_hints : void 0
1473
- };
1474
- };
1475
- }
1476
- }();
1477
- }
1478
- delete() {
1479
- const table = this.table;
1480
- const schema = this.schema;
1481
- const state = {
1482
- where: {},
1483
- returning: []
1484
- };
1485
- return new class {
1486
- constructor() {
1487
- this.where = (w) => {
1488
- for (const k in w) state.where[k] = w[k];
1489
- return this;
1490
- };
1491
- this.wherePk = (pk) => {
1492
- const pkCols = getPrimaryKeyColumns(table);
1493
- if (!pkCols || pkCols.length === 0) throw new Error(`Table ${table.name} does not have a primary key`);
1494
- if (pkCols.length === 1) {
1495
- const col = pkCols[0];
1496
- if (isPlainObject(pk)) throw new Error(`wherePk on ${table.name} expects a scalar for primary key column ${col}`);
1497
- state.where[col] = pk;
1498
- } else {
1499
- if (!isPlainObject(pk)) throw new Error(`wherePk on ${table.name} requires an object with keys: ${pkCols.join(", ")}`);
1500
- const obj = pk;
1501
- for (const k of Object.keys(obj)) if (!pkCols.includes(k)) throw new Error(`wherePk received unknown key '${k}'. Expected keys: ${pkCols.join(", ")}`);
1502
- for (const col of pkCols) {
1503
- if (!(col in obj)) throw new Error(`wherePk missing key '${col}'. Required keys: ${pkCols.join(", ")}`);
1504
- state.where[col] = obj[col];
1505
- }
1506
- }
1507
- return this;
1508
- };
1509
- this.returning = (cols) => {
1510
- state.returning = cols || [];
1511
- return this;
1512
- };
1513
- this.toSql = () => {
1514
- const params = {};
1515
- const type_hints = {};
1516
- let p = 0;
1517
- const whereClauses = [];
1518
- for (const key in state.where) {
1519
- const value = state.where[key];
1520
- const col = findColumn(table, key);
1521
- p += 1;
1522
- const paramName = `${table.name}_${key}_${p}`;
1523
- if (value === null) {
1524
- if (!col.is_nullable) throw new Error(`Column ${table.name}.${key} is not nullable; cannot compare to null`);
1525
- whereClauses.push(`"${key}" is null`);
1526
- } else if (Array.isArray(value)) {
1527
- validateInArrayValues(col, key, value, "in");
1528
- whereClauses.push(`"${key}" = ANY(:${paramName})`);
1529
- params[paramName] = value;
1530
- addTypeHintForParam(type_hints, paramName, col, value);
1531
- } else {
1532
- validateScalarForColumn(col, value, `column ${key}`);
1533
- whereClauses.push(`"${key}" = :${paramName}`);
1534
- params[paramName] = value;
1535
- addTypeHintForParam(type_hints, paramName, col, value);
1536
- }
1537
- }
1538
- const parts = [];
1539
- parts.push(`delete from "${schema.name}"."${table.name}"`);
1540
- if (whereClauses.length) parts.push("where " + whereClauses.join(" and "));
1541
- if (state.returning.length) parts.push("returning " + state.returning.join(", "));
1542
- return {
1543
- q: parts.join(" "),
1544
- params: Object.keys(params).length > 0 ? params : void 0,
1545
- type_hints: Object.keys(type_hints).length ? type_hints : void 0
1546
- };
1547
- };
1548
- }
1549
- }();
1550
- }
1551
- };
1552
- function createSqlBuilder(schema) {
1553
- 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
+ }();
1554
1423
  }
1555
-
1556
- //#endregion
1557
- //#region src/index.ts
1558
- /**
1559
- * @author Martin Høgh <mh@mapcentia.com>
1560
- * @copyright 2013-2026 MapCentia ApS
1561
- * @license https://opensource.org/license/mit The MIT License
1562
- *
1563
- */
1424
+ };
1425
+ function createSqlBuilder(schema) {
1426
+ return { table: (name) => new TableQueryImpl(schema, String(name)) };
1427
+ }
1564
1428
 
1565
1429
  //#endregion
1566
1430
  exports.Claims = Claims;
1567
1431
  exports.CodeFlow = CodeFlow;
1568
- exports.Gql = Gql;
1569
1432
  exports.Meta = Meta;
1570
1433
  exports.PasswordFlow = PasswordFlow;
1571
1434
  exports.Rpc = Rpc;