@aurabase/aurabase-js 0.3.1 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -795
- package/{packages/aurabase/dist/AuraClient-DAtDbfPB.d.ts → dist/AuraClient-BcFE8u1v.d.cts} +1 -1
- package/{packages/aurabase/dist/AuraClient-DAtDbfPB.d.cts → dist/AuraClient-BcFE8u1v.d.ts} +1 -1
- package/{packages/aurabase/dist → dist}/index.d.cts +1 -1
- package/{packages/aurabase/dist → dist}/index.d.ts +1 -1
- package/{packages/aurabase/dist → dist}/ssr.d.cts +1 -1
- package/{packages/aurabase/dist → dist}/ssr.d.ts +1 -1
- package/package.json +74 -82
- package/.changeset/config.json +0 -11
- package/CHANGELOG.md +0 -30
- package/packages/ai/LICENSE +0 -21
- package/packages/ai/README.md +0 -106
- package/packages/ai/dist/index.cjs +0 -229
- package/packages/ai/dist/index.d.cts +0 -139
- package/packages/ai/dist/index.d.ts +0 -139
- package/packages/ai/dist/index.js +0 -226
- package/packages/ai/package.json +0 -61
- package/packages/aurabase/LICENSE +0 -21
- package/packages/aurabase/README.md +0 -64
- package/packages/aurabase/package.json +0 -80
- package/packages/aurabase/vitest.e2e.config.ts +0 -9
- package/packages/auth/LICENSE +0 -21
- package/packages/auth/README.md +0 -215
- package/packages/auth/dist/index.cjs +0 -1175
- package/packages/auth/dist/index.d.cts +0 -397
- package/packages/auth/dist/index.d.ts +0 -397
- package/packages/auth/dist/index.js +0 -1170
- package/packages/auth/package.json +0 -61
- package/packages/core/LICENSE +0 -21
- package/packages/core/README.md +0 -132
- package/packages/core/dist/index.cjs +0 -695
- package/packages/core/dist/index.d.cts +0 -1137
- package/packages/core/dist/index.d.ts +0 -1137
- package/packages/core/dist/index.js +0 -673
- package/packages/core/package.json +0 -57
- package/packages/db/LICENSE +0 -21
- package/packages/db/README.md +0 -152
- package/packages/db/VENDORED.md +0 -93
- package/packages/db/dist/index.cjs +0 -544
- package/packages/db/dist/index.d.cts +0 -1111
- package/packages/db/dist/index.d.ts +0 -1111
- package/packages/db/dist/index.js +0 -541
- package/packages/db/package.json +0 -62
- package/packages/functions/LICENSE +0 -21
- package/packages/functions/README.md +0 -96
- package/packages/functions/dist/index.cjs +0 -173
- package/packages/functions/dist/index.d.cts +0 -81
- package/packages/functions/dist/index.d.ts +0 -81
- package/packages/functions/dist/index.js +0 -168
- package/packages/functions/package.json +0 -60
- package/packages/gen/LICENSE +0 -21
- package/packages/gen/README.md +0 -84
- package/packages/gen/dist/cli.cjs +0 -334
- package/packages/gen/dist/cli.d.cts +0 -1
- package/packages/gen/dist/cli.d.ts +0 -1
- package/packages/gen/dist/cli.js +0 -332
- package/packages/gen/dist/index.cjs +0 -257
- package/packages/gen/dist/index.d.cts +0 -12
- package/packages/gen/dist/index.d.ts +0 -12
- package/packages/gen/dist/index.js +0 -255
- package/packages/gen/package.json +0 -66
- package/packages/notifications/LICENSE +0 -21
- package/packages/notifications/README.md +0 -134
- package/packages/notifications/dist/index.cjs +0 -128
- package/packages/notifications/dist/index.d.cts +0 -81
- package/packages/notifications/dist/index.d.ts +0 -81
- package/packages/notifications/dist/index.js +0 -125
- package/packages/notifications/package.json +0 -60
- package/packages/realtime/LICENSE +0 -21
- package/packages/realtime/README.md +0 -183
- package/packages/realtime/dist/index.cjs +0 -977
- package/packages/realtime/dist/index.d.cts +0 -259
- package/packages/realtime/dist/index.d.ts +0 -259
- package/packages/realtime/dist/index.js +0 -973
- package/packages/realtime/package.json +0 -60
- package/packages/storage/LICENSE +0 -21
- package/packages/storage/README.md +0 -141
- package/packages/storage/dist/index.cjs +0 -333
- package/packages/storage/dist/index.d.cts +0 -185
- package/packages/storage/dist/index.d.ts +0 -185
- package/packages/storage/dist/index.js +0 -329
- package/packages/storage/package.json +0 -60
- /package/{packages/aurabase/dist → dist}/index.cjs +0 -0
- /package/{packages/aurabase/dist → dist}/index.js +0 -0
- /package/{packages/aurabase/dist → dist}/ssr.cjs +0 -0
- /package/{packages/aurabase/dist → dist}/ssr.js +0 -0
|
@@ -1,541 +0,0 @@
|
|
|
1
|
-
import { BaseService, fetchWithAuth, AuraError } from '@aurabase/core';
|
|
2
|
-
|
|
3
|
-
// src/DatabaseService.ts
|
|
4
|
-
function quoteReserved(v) {
|
|
5
|
-
const s = String(v);
|
|
6
|
-
return /[,()"]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s;
|
|
7
|
-
}
|
|
8
|
-
function encodeFilterValue(op, value) {
|
|
9
|
-
if (op === "in" || op === "not.in") {
|
|
10
|
-
const arr = Array.isArray(value) ? value : [value];
|
|
11
|
-
return `${op}.(${arr.map(quoteReserved).join(",")})`;
|
|
12
|
-
}
|
|
13
|
-
if (op === "cs" || op === "cd" || op === "ov") {
|
|
14
|
-
if (Array.isArray(value)) return `${op}.{${value.map(quoteReserved).join(",")}}`;
|
|
15
|
-
if (value !== null && typeof value === "object") return `${op}.${JSON.stringify(value)}`;
|
|
16
|
-
return `${op}.${value}`;
|
|
17
|
-
}
|
|
18
|
-
if (op.endsWith("(all)") || op.endsWith("(any)")) {
|
|
19
|
-
const arr = Array.isArray(value) ? value : [value];
|
|
20
|
-
return `${op}.{${arr.map(quoteReserved).join(",")}}`;
|
|
21
|
-
}
|
|
22
|
-
return `${op}.${value}`;
|
|
23
|
-
}
|
|
24
|
-
var PGRST_OBJECT_ACCEPT = "application/vnd.pgrst.object+json";
|
|
25
|
-
function mentionsZeroRows(err) {
|
|
26
|
-
if (!err) return false;
|
|
27
|
-
const details = typeof err.details === "string" ? err.details : JSON.stringify(err.details ?? "");
|
|
28
|
-
return /\b0 rows\b/.test(`${err.message ?? ""} ${details}`);
|
|
29
|
-
}
|
|
30
|
-
function pgrst116(zeroRows) {
|
|
31
|
-
return new AuraError(406, {
|
|
32
|
-
error: {
|
|
33
|
-
code: "PGRST116",
|
|
34
|
-
message: zeroRows ? "JSON object requested, 0 rows returned" : "JSON object requested, multiple rows returned"
|
|
35
|
-
}
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
var AuraPostgrestBuilder = class {
|
|
39
|
-
_client;
|
|
40
|
-
_basePath;
|
|
41
|
-
_filters = [];
|
|
42
|
-
_orGroups = [];
|
|
43
|
-
_selectColumns = null;
|
|
44
|
-
// `select()` a-t-il été appelé ? (distinct de `_selectColumns`, que `select('*')`
|
|
45
|
-
// remet à `null`) — sert à poser `Prefer: return=representation` sur une mutation
|
|
46
|
-
// même avec `select('*')`.
|
|
47
|
-
_selectInvoked = false;
|
|
48
|
-
_sortColumn = null;
|
|
49
|
-
_sortDirection = "asc";
|
|
50
|
-
_limit = null;
|
|
51
|
-
_offset = null;
|
|
52
|
-
_cursor = null;
|
|
53
|
-
_count = null;
|
|
54
|
-
_rawSelect = false;
|
|
55
|
-
_single = false;
|
|
56
|
-
_maybeSingle = false;
|
|
57
|
-
_throwOnError = false;
|
|
58
|
-
_mutation = null;
|
|
59
|
-
_rpc = null;
|
|
60
|
-
constructor(client, basePath) {
|
|
61
|
-
this._client = client;
|
|
62
|
-
this._basePath = basePath;
|
|
63
|
-
}
|
|
64
|
-
throwOnError() {
|
|
65
|
-
this._throwOnError = true;
|
|
66
|
-
return this;
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Positionne l'état interne `rpc` (args + verbe HTTP) — méthode package-interne
|
|
70
|
-
* utilisée par `DatabaseService.rpc()` pour éviter un cast sur un champ `protected`.
|
|
71
|
-
*
|
|
72
|
-
* `count` accepte `'planned'` (parité stricte `RpcOptions`, cf. `DatabaseService.rpc`)
|
|
73
|
-
* en plus de `CountMode` (`@aurabase/core`, qui ne connaît que `exact`/`estimated` —
|
|
74
|
-
* package partagé, non modifié ici). Le cast vers `_count` reste sans risque runtime :
|
|
75
|
-
* `buildQueryString` sérialise la valeur telle quelle en query param `count=`.
|
|
76
|
-
*/
|
|
77
|
-
_initRpc(args, verb, count) {
|
|
78
|
-
this._rpc = { args, verb };
|
|
79
|
-
if (count) this._count = count;
|
|
80
|
-
return this;
|
|
81
|
-
}
|
|
82
|
-
// -- Query string builder ---------------------------------------------------
|
|
83
|
-
buildQueryString() {
|
|
84
|
-
const params = new URLSearchParams();
|
|
85
|
-
if (this._selectColumns && this._selectColumns.length > 0) {
|
|
86
|
-
params.set("select", this._rawSelect ? this._selectColumns[0] : this._selectColumns.join(","));
|
|
87
|
-
}
|
|
88
|
-
for (const f of this._filters) {
|
|
89
|
-
params.append(f.column, encodeFilterValue(f.op, f.value));
|
|
90
|
-
}
|
|
91
|
-
for (const group of this._orGroups) {
|
|
92
|
-
const parts = group.filters.map((f) => `${f.column}.${encodeFilterValue(f.op, f.value)}`);
|
|
93
|
-
params.append("or", `(${parts.join(",")})`);
|
|
94
|
-
}
|
|
95
|
-
if (this._sortColumn) {
|
|
96
|
-
params.set("sort_by", this._sortColumn);
|
|
97
|
-
params.set("sort_order", this._sortDirection);
|
|
98
|
-
}
|
|
99
|
-
if (this._limit !== null) params.set("limit", String(this._limit));
|
|
100
|
-
if (this._offset !== null) params.set("offset", String(this._offset));
|
|
101
|
-
if (this._cursor !== null) params.set("cursor", this._cursor);
|
|
102
|
-
if (this._count) params.set("count", this._count);
|
|
103
|
-
if (this._rpc && (this._rpc.verb === "GET" || this._rpc.verb === "HEAD") && this._rpc.args && typeof this._rpc.args === "object") {
|
|
104
|
-
for (const [k, v] of Object.entries(this._rpc.args)) {
|
|
105
|
-
params.set(k, typeof v === "string" ? v : JSON.stringify(v));
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
return params.toString();
|
|
109
|
-
}
|
|
110
|
-
// -- Execution via PromiseLike ----------------------------------------------
|
|
111
|
-
then(onfulfilled, onrejected) {
|
|
112
|
-
return this._execute().then(onfulfilled, onrejected);
|
|
113
|
-
}
|
|
114
|
-
async _execute() {
|
|
115
|
-
let res;
|
|
116
|
-
const acceptSingle = this._single ? { Accept: PGRST_OBJECT_ACCEPT } : void 0;
|
|
117
|
-
if (this._rpc) {
|
|
118
|
-
const qs = this.buildQueryString();
|
|
119
|
-
const sep = qs ? "?" : "";
|
|
120
|
-
const url = `${this._client.baseUrl}${this._basePath}${sep}${qs}`;
|
|
121
|
-
const init = this._rpc.verb === "POST" ? { method: "POST", body: this._rpc.args, headers: acceptSingle } : { method: this._rpc.verb, headers: acceptSingle };
|
|
122
|
-
res = await fetchWithAuth(url, init, this._client);
|
|
123
|
-
} else if (this._mutation) {
|
|
124
|
-
const m = this._mutation;
|
|
125
|
-
const hasEffectiveFilter = this._filters.some((f) => f.column !== "") || this._orGroups.some((g) => g.filters.length > 0);
|
|
126
|
-
if ((m.type === "update" || m.type === "delete") && m.id === null && !hasEffectiveFilter) {
|
|
127
|
-
return {
|
|
128
|
-
data: null,
|
|
129
|
-
error: new AuraError(0, {
|
|
130
|
-
error: {
|
|
131
|
-
code: "unfiltered_mutation",
|
|
132
|
-
message: "update()/delete() sans filtre refus\xE9 (protection anti-wipe) \u2014 ajoutez un filtre .eq()/... ou utilisez une mutation id-based"
|
|
133
|
-
}
|
|
134
|
-
})
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
const prefer = [];
|
|
138
|
-
if (this._selectInvoked) prefer.push("return=representation");
|
|
139
|
-
if (this._count) prefer.push(`count=${this._count}`);
|
|
140
|
-
const merged = { ...acceptSingle };
|
|
141
|
-
if (prefer.length > 0) merged.Prefer = prefer.join(", ");
|
|
142
|
-
const headers = Object.keys(merged).length > 0 ? merged : void 0;
|
|
143
|
-
const qs = this.buildQueryString();
|
|
144
|
-
const sep = qs ? "?" : "";
|
|
145
|
-
switch (m.type) {
|
|
146
|
-
case "insert": {
|
|
147
|
-
res = await fetchWithAuth(
|
|
148
|
-
`${this._client.baseUrl}${this._basePath}${sep}${qs}`,
|
|
149
|
-
{ method: "POST", body: m.body, headers },
|
|
150
|
-
this._client
|
|
151
|
-
);
|
|
152
|
-
break;
|
|
153
|
-
}
|
|
154
|
-
case "update": {
|
|
155
|
-
const path = m.id !== null ? `${this._basePath}/${m.id}` : this._basePath;
|
|
156
|
-
res = await fetchWithAuth(
|
|
157
|
-
`${this._client.baseUrl}${path}${sep}${qs}`,
|
|
158
|
-
{ method: "PATCH", body: m.body, headers },
|
|
159
|
-
this._client
|
|
160
|
-
);
|
|
161
|
-
break;
|
|
162
|
-
}
|
|
163
|
-
case "delete": {
|
|
164
|
-
const path = m.id !== null ? `${this._basePath}/${m.id}` : this._basePath;
|
|
165
|
-
res = await fetchWithAuth(
|
|
166
|
-
`${this._client.baseUrl}${path}${sep}${qs}`,
|
|
167
|
-
{ method: "DELETE", headers },
|
|
168
|
-
this._client
|
|
169
|
-
);
|
|
170
|
-
break;
|
|
171
|
-
}
|
|
172
|
-
case "upsert": {
|
|
173
|
-
const params = new URLSearchParams(qs);
|
|
174
|
-
params.set("on_conflict", m.onConflict);
|
|
175
|
-
res = await fetchWithAuth(
|
|
176
|
-
`${this._client.baseUrl}${this._basePath}?${params.toString()}`,
|
|
177
|
-
{ method: "POST", body: m.body, headers },
|
|
178
|
-
this._client
|
|
179
|
-
);
|
|
180
|
-
break;
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
} else {
|
|
184
|
-
const qs = this.buildQueryString();
|
|
185
|
-
const sep = qs ? "?" : "";
|
|
186
|
-
res = await fetchWithAuth(
|
|
187
|
-
`${this._client.baseUrl}${this._basePath}${sep}${qs}`,
|
|
188
|
-
{ method: "GET", headers: acceptSingle },
|
|
189
|
-
this._client
|
|
190
|
-
);
|
|
191
|
-
}
|
|
192
|
-
if (!this._single && (this._mutation?.type === "insert" || this._mutation?.type === "upsert") && res.data !== null && typeof res.data === "object" && !Array.isArray(res.data)) {
|
|
193
|
-
res = { ...res, data: [res.data] };
|
|
194
|
-
}
|
|
195
|
-
if (this._single) {
|
|
196
|
-
if (res.error) {
|
|
197
|
-
const zero = res.error.status === 406 ? mentionsZeroRows(res.error) : res.error.status === 404 && res.error.code === "RECORD_NOT_FOUND" ? true : null;
|
|
198
|
-
if (zero !== null) {
|
|
199
|
-
res = this._maybeSingle && zero ? { ...res, data: null, error: null } : { ...res, data: null, error: pgrst116(zero) };
|
|
200
|
-
}
|
|
201
|
-
} else if (Array.isArray(res.data)) {
|
|
202
|
-
const rows = res.data;
|
|
203
|
-
if (this._maybeSingle) {
|
|
204
|
-
res = rows.length > 1 ? { ...res, data: null, error: pgrst116(false) } : { ...res, data: rows[0] ?? null };
|
|
205
|
-
} else if (rows.length === 1) {
|
|
206
|
-
res = { ...res, data: rows[0] };
|
|
207
|
-
} else {
|
|
208
|
-
res = { ...res, data: null, error: pgrst116(rows.length === 0) };
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
if (this._throwOnError && res.error) {
|
|
213
|
-
const err = new Error(res.error.message);
|
|
214
|
-
err.code = res.error.code;
|
|
215
|
-
err.details = res.error.details;
|
|
216
|
-
throw err;
|
|
217
|
-
}
|
|
218
|
-
return res;
|
|
219
|
-
}
|
|
220
|
-
};
|
|
221
|
-
var AuraTransformBuilder = class extends AuraPostgrestBuilder {
|
|
222
|
-
// -- Column selection & resource embedding -----------------------------------
|
|
223
|
-
/**
|
|
224
|
-
* Select columns and optionally embed related resources (PostgREST parity).
|
|
225
|
-
*
|
|
226
|
-
* @example
|
|
227
|
-
* // Simple columns
|
|
228
|
-
* db.from('users').select('id, name, email')
|
|
229
|
-
*
|
|
230
|
-
* // All columns (default)
|
|
231
|
-
* db.from('users').select('*')
|
|
232
|
-
*
|
|
233
|
-
* // Embed related table (many-to-one)
|
|
234
|
-
* db.from('orders').select('*, customer:customers(name, email)')
|
|
235
|
-
*
|
|
236
|
-
* // Embed related table (one-to-many)
|
|
237
|
-
* db.from('directors').select('last_name, films(title, year)')
|
|
238
|
-
*
|
|
239
|
-
* // FK disambiguation
|
|
240
|
-
* db.from('orders').select('*, billing:addresses!billing_address_id(name)')
|
|
241
|
-
*
|
|
242
|
-
* // Nested embedding
|
|
243
|
-
* db.from('actors').select('first_name, roles(character, films(title))')
|
|
244
|
-
*/
|
|
245
|
-
select(columns) {
|
|
246
|
-
this._selectInvoked = true;
|
|
247
|
-
const cols = columns;
|
|
248
|
-
if (cols === void 0 || cols === "*") {
|
|
249
|
-
this._selectColumns = null;
|
|
250
|
-
this._rawSelect = false;
|
|
251
|
-
} else if (typeof cols === "string") {
|
|
252
|
-
if (cols.includes("(")) {
|
|
253
|
-
this._selectColumns = [cols];
|
|
254
|
-
this._rawSelect = true;
|
|
255
|
-
} else {
|
|
256
|
-
this._selectColumns = cols.split(",").map((c) => c.trim());
|
|
257
|
-
this._rawSelect = false;
|
|
258
|
-
}
|
|
259
|
-
} else {
|
|
260
|
-
this._selectColumns = cols;
|
|
261
|
-
this._rawSelect = false;
|
|
262
|
-
}
|
|
263
|
-
return this;
|
|
264
|
-
}
|
|
265
|
-
// -- Sort / pagination ------------------------------------------------------
|
|
266
|
-
order(column, direction = "asc") {
|
|
267
|
-
this._sortColumn = column;
|
|
268
|
-
this._sortDirection = direction;
|
|
269
|
-
return this;
|
|
270
|
-
}
|
|
271
|
-
limit(n) {
|
|
272
|
-
this._limit = n;
|
|
273
|
-
return this;
|
|
274
|
-
}
|
|
275
|
-
offset(n) {
|
|
276
|
-
this._offset = n;
|
|
277
|
-
return this;
|
|
278
|
-
}
|
|
279
|
-
/**
|
|
280
|
-
* Pagination keyset : passer le `next_cursor` opaque de la page précédente (préférable à
|
|
281
|
-
* `offset` sur les grandes tables : stable, sans dup/skip). Renvoyer tel quel `meta.next_cursor` ;
|
|
282
|
-
* ne pas le construire/parser (format opaque).
|
|
283
|
-
*/
|
|
284
|
-
cursor(cursor) {
|
|
285
|
-
this._cursor = cursor;
|
|
286
|
-
return this;
|
|
287
|
-
}
|
|
288
|
-
count(mode = "exact") {
|
|
289
|
-
this._count = mode;
|
|
290
|
-
return this;
|
|
291
|
-
}
|
|
292
|
-
// -- Modifiers --------------------------------------------------------------
|
|
293
|
-
single() {
|
|
294
|
-
this._single = true;
|
|
295
|
-
return this;
|
|
296
|
-
}
|
|
297
|
-
maybeSingle() {
|
|
298
|
-
this._single = true;
|
|
299
|
-
this._maybeSingle = true;
|
|
300
|
-
return this;
|
|
301
|
-
}
|
|
302
|
-
};
|
|
303
|
-
var AuraFilterBuilder = class extends AuraTransformBuilder {
|
|
304
|
-
// -- Filter methods (each returns this for chaining) ------------------------
|
|
305
|
-
//
|
|
306
|
-
// Typées sur `Row` : `column` est contraint à `keyof Row & string` (autocomplete +
|
|
307
|
-
// erreur de compilation sur colonne inconnue) et `value`/`values` à `Row[C]` (erreur
|
|
308
|
-
// sur mauvais type). Runtime inchangé — seules les signatures changent.
|
|
309
|
-
eq(column, value) {
|
|
310
|
-
this._filters.push({ column, op: "eq", value });
|
|
311
|
-
return this;
|
|
312
|
-
}
|
|
313
|
-
neq(column, value) {
|
|
314
|
-
this._filters.push({ column, op: "neq", value });
|
|
315
|
-
return this;
|
|
316
|
-
}
|
|
317
|
-
gt(column, value) {
|
|
318
|
-
this._filters.push({ column, op: "gt", value });
|
|
319
|
-
return this;
|
|
320
|
-
}
|
|
321
|
-
gte(column, value) {
|
|
322
|
-
this._filters.push({ column, op: "gte", value });
|
|
323
|
-
return this;
|
|
324
|
-
}
|
|
325
|
-
lt(column, value) {
|
|
326
|
-
this._filters.push({ column, op: "lt", value });
|
|
327
|
-
return this;
|
|
328
|
-
}
|
|
329
|
-
lte(column, value) {
|
|
330
|
-
this._filters.push({ column, op: "lte", value });
|
|
331
|
-
return this;
|
|
332
|
-
}
|
|
333
|
-
like(column, pattern) {
|
|
334
|
-
this._filters.push({ column, op: "like", value: pattern });
|
|
335
|
-
return this;
|
|
336
|
-
}
|
|
337
|
-
ilike(column, pattern) {
|
|
338
|
-
this._filters.push({ column, op: "ilike", value: pattern });
|
|
339
|
-
return this;
|
|
340
|
-
}
|
|
341
|
-
/**
|
|
342
|
-
* IS NULL or IS NOT NULL filter.
|
|
343
|
-
* PostgREST accepts: is.null, is.true, is.false (no "not_null" — use neq for that).
|
|
344
|
-
* For IS NOT NULL, use `neq(column, null)` or `is(column, 'not.null')`.
|
|
345
|
-
*/
|
|
346
|
-
is(column, value) {
|
|
347
|
-
if (value === "not.null") {
|
|
348
|
-
this._filters.push({ column, op: "not.is", value: "null" });
|
|
349
|
-
} else {
|
|
350
|
-
this._filters.push({ column, op: "is", value });
|
|
351
|
-
}
|
|
352
|
-
return this;
|
|
353
|
-
}
|
|
354
|
-
in(column, values) {
|
|
355
|
-
this._filters.push({ column, op: "in", value: values });
|
|
356
|
-
return this;
|
|
357
|
-
}
|
|
358
|
-
/**
|
|
359
|
-
* Add an OR group: `or=(col1.eq.val1,col2.gt.val2)`
|
|
360
|
-
*/
|
|
361
|
-
or(filters) {
|
|
362
|
-
this._orGroups.push({
|
|
363
|
-
filters: filters.map((f) => ({ column: f.column, op: f.op, value: f.value }))
|
|
364
|
-
});
|
|
365
|
-
return this;
|
|
366
|
-
}
|
|
367
|
-
// -- Filtres étendus (parité PostgREST) -------------------------------------
|
|
368
|
-
notIn(column, values) {
|
|
369
|
-
this._filters.push({ column, op: "not.in", value: values });
|
|
370
|
-
return this;
|
|
371
|
-
}
|
|
372
|
-
contains(column, value) {
|
|
373
|
-
this._filters.push({ column, op: "cs", value });
|
|
374
|
-
return this;
|
|
375
|
-
}
|
|
376
|
-
containedBy(column, value) {
|
|
377
|
-
this._filters.push({ column, op: "cd", value });
|
|
378
|
-
return this;
|
|
379
|
-
}
|
|
380
|
-
overlaps(column, value) {
|
|
381
|
-
this._filters.push({ column, op: "ov", value });
|
|
382
|
-
return this;
|
|
383
|
-
}
|
|
384
|
-
rangeGt(column, range) {
|
|
385
|
-
this._filters.push({ column, op: "sr", value: range });
|
|
386
|
-
return this;
|
|
387
|
-
}
|
|
388
|
-
rangeGte(column, range) {
|
|
389
|
-
this._filters.push({ column, op: "nxl", value: range });
|
|
390
|
-
return this;
|
|
391
|
-
}
|
|
392
|
-
rangeLt(column, range) {
|
|
393
|
-
this._filters.push({ column, op: "sl", value: range });
|
|
394
|
-
return this;
|
|
395
|
-
}
|
|
396
|
-
rangeLte(column, range) {
|
|
397
|
-
this._filters.push({ column, op: "nxr", value: range });
|
|
398
|
-
return this;
|
|
399
|
-
}
|
|
400
|
-
rangeAdjacent(column, range) {
|
|
401
|
-
this._filters.push({ column, op: "adj", value: range });
|
|
402
|
-
return this;
|
|
403
|
-
}
|
|
404
|
-
isDistinct(column, value) {
|
|
405
|
-
this._filters.push({ column, op: "isdistinct", value });
|
|
406
|
-
return this;
|
|
407
|
-
}
|
|
408
|
-
// Échappatoires (parité postgrest-js) : colonne `string` permissive, pas de contrainte sur `Row`.
|
|
409
|
-
not(column, op, value) {
|
|
410
|
-
this._filters.push({ column, op: `not.${op}`, value });
|
|
411
|
-
return this;
|
|
412
|
-
}
|
|
413
|
-
filter(column, op, value) {
|
|
414
|
-
this._filters.push({ column, op, value });
|
|
415
|
-
return this;
|
|
416
|
-
}
|
|
417
|
-
match(query) {
|
|
418
|
-
for (const [column, value] of Object.entries(query)) this._filters.push({ column, op: "eq", value });
|
|
419
|
-
return this;
|
|
420
|
-
}
|
|
421
|
-
textSearch(column, query, options) {
|
|
422
|
-
const t = options?.type;
|
|
423
|
-
const token = t === "plain" ? "plfts" : t === "phrase" ? "phfts" : t === "websearch" ? "wfts" : "fts";
|
|
424
|
-
const op = options?.config ? `${token}(${options.config})` : token;
|
|
425
|
-
this._filters.push({ column, op, value: query });
|
|
426
|
-
return this;
|
|
427
|
-
}
|
|
428
|
-
likeAllOf(column, patterns) {
|
|
429
|
-
this._filters.push({ column, op: "like(all)", value: patterns });
|
|
430
|
-
return this;
|
|
431
|
-
}
|
|
432
|
-
likeAnyOf(column, patterns) {
|
|
433
|
-
this._filters.push({ column, op: "like(any)", value: patterns });
|
|
434
|
-
return this;
|
|
435
|
-
}
|
|
436
|
-
ilikeAllOf(column, patterns) {
|
|
437
|
-
this._filters.push({ column, op: "ilike(all)", value: patterns });
|
|
438
|
-
return this;
|
|
439
|
-
}
|
|
440
|
-
ilikeAnyOf(column, patterns) {
|
|
441
|
-
this._filters.push({ column, op: "ilike(any)", value: patterns });
|
|
442
|
-
return this;
|
|
443
|
-
}
|
|
444
|
-
};
|
|
445
|
-
var AuraQueryBuilder = class extends AuraFilterBuilder {
|
|
446
|
-
// -- Mutations --------------------------------------------------------------
|
|
447
|
-
//
|
|
448
|
-
// Typées sur `Relation['Insert']`/`Relation['Update']` (parité postgrest-js) :
|
|
449
|
-
// un champ requis manquant côté insert/upsert, ou une colonne inconnue côté
|
|
450
|
-
// update, est une erreur de compilation. Runtime inchangé.
|
|
451
|
-
//
|
|
452
|
-
// Extraction par type conditionnel (plutôt qu'un accès indexé direct
|
|
453
|
-
// `Relation['Insert']`) : `Relation` est contraint à `GenericTable | GenericView`
|
|
454
|
-
// et `GenericNonUpdatableView` ne porte pas `Insert`/`Update`. `infer` distribue
|
|
455
|
-
// sur cette union et retombe sur `never` pour la branche non-updatable, ce qui
|
|
456
|
-
// évite l'erreur TS2536 tout en gardant le typage strict pour les tables.
|
|
457
|
-
insert(body) {
|
|
458
|
-
this._mutation = { type: "insert", body };
|
|
459
|
-
return this;
|
|
460
|
-
}
|
|
461
|
-
update(idOrBody, body) {
|
|
462
|
-
if (typeof idOrBody === "string") {
|
|
463
|
-
this._mutation = { type: "update", id: idOrBody, body };
|
|
464
|
-
} else {
|
|
465
|
-
this._mutation = { type: "update", id: null, body: idOrBody };
|
|
466
|
-
}
|
|
467
|
-
return this;
|
|
468
|
-
}
|
|
469
|
-
// COMPAT `delete(id)` → route id-based ; FILTRÉ `delete()` → route Table
|
|
470
|
-
// (exige un filtre, garde-fou anti-wipe).
|
|
471
|
-
delete(id) {
|
|
472
|
-
this._mutation = { type: "delete", id: typeof id === "string" ? id : null };
|
|
473
|
-
return this;
|
|
474
|
-
}
|
|
475
|
-
upsert(body, options) {
|
|
476
|
-
this._mutation = { type: "upsert", body, onConflict: options?.onConflict ?? "id" };
|
|
477
|
-
return this;
|
|
478
|
-
}
|
|
479
|
-
};
|
|
480
|
-
|
|
481
|
-
// src/DatabaseService.ts
|
|
482
|
-
var DatabaseService = class extends BaseService {
|
|
483
|
-
constructor(client) {
|
|
484
|
-
super(client);
|
|
485
|
-
}
|
|
486
|
-
get prefix() {
|
|
487
|
-
return `/v1/db/${this.client.projectId}`;
|
|
488
|
-
}
|
|
489
|
-
from(table) {
|
|
490
|
-
return new AuraQueryBuilder(this.client, `${this.prefix}/${table}`);
|
|
491
|
-
}
|
|
492
|
-
/**
|
|
493
|
-
* Exécute une requête SQL brute (passthrough direct vers Postgres).
|
|
494
|
-
*
|
|
495
|
-
* ⚠️ N'est PAS en lecture seule : SELECT, INSERT, UPDATE, DELETE et DDL
|
|
496
|
-
* s'exécutent réellement et persistent, dans la limite des GRANTs du rôle
|
|
497
|
-
* Postgres connecté pour ce projet (seule barrière de sécurité — il n'y a
|
|
498
|
-
* aucun filtre applicatif par type d'instruction côté serveur). Ne pas
|
|
499
|
-
* exposer cet endpoint sans restriction à des clients non fiables.
|
|
500
|
-
*/
|
|
501
|
-
async sql(query, params) {
|
|
502
|
-
return this.request("POST", `${this.prefix}/raw`, { query, params });
|
|
503
|
-
}
|
|
504
|
-
/**
|
|
505
|
-
* Appelle une fonction Postgres exposée par PostgREST (`POST|GET|HEAD /rpc/{fn}`).
|
|
506
|
-
* Signature forte quand `Schema['Functions']` connaît `fn` (typage vendoré
|
|
507
|
-
* `GetRpcFunctionFilterBuilderByArgs`, parité postgrest-js) ; sinon repli permissif.
|
|
508
|
-
*
|
|
509
|
-
* @example
|
|
510
|
-
* const { data } = await db.rpc('add', { a: 1, b: 2 })
|
|
511
|
-
* const { data } = await db.rpc('list_things', {}).eq('id', 2).select('id,name').single()
|
|
512
|
-
*/
|
|
513
|
-
rpc(fn, args, options) {
|
|
514
|
-
const verb = options?.head ? "HEAD" : options?.get ? "GET" : "POST";
|
|
515
|
-
const builder = new AuraFilterBuilder(
|
|
516
|
-
this.client,
|
|
517
|
-
`${this.prefix}/rpc/${fn}`
|
|
518
|
-
)._initRpc(args ?? {}, verb, options?.count);
|
|
519
|
-
return builder;
|
|
520
|
-
}
|
|
521
|
-
/**
|
|
522
|
-
* Fetch the schema (tables & colonnes, fonctions Postgres exposées via PostgREST,
|
|
523
|
-
* types enum et vues) pour le projet courant.
|
|
524
|
-
*/
|
|
525
|
-
async schema() {
|
|
526
|
-
const res = await this.request("GET", `${this.prefix}/schema`);
|
|
527
|
-
if (res.error) return { data: null, error: res.error, meta: res.meta };
|
|
528
|
-
return {
|
|
529
|
-
data: {
|
|
530
|
-
tables: res.data?.tables ?? [],
|
|
531
|
-
functions: res.data?.functions ?? [],
|
|
532
|
-
enums: res.data?.enums ?? [],
|
|
533
|
-
views: res.data?.views ?? []
|
|
534
|
-
},
|
|
535
|
-
error: null,
|
|
536
|
-
meta: res.meta
|
|
537
|
-
};
|
|
538
|
-
}
|
|
539
|
-
};
|
|
540
|
-
|
|
541
|
-
export { DatabaseService, AuraQueryBuilder as QueryBuilder };
|
package/packages/db/package.json
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@aurabase/db",
|
|
3
|
-
"version": "0.3.0",
|
|
4
|
-
"description": "Service base de données du SDK Aurabase : query builder typé PostgREST-like + inférence de types",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "dist/index.cjs",
|
|
7
|
-
"module": "dist/index.js",
|
|
8
|
-
"types": "dist/index.d.ts",
|
|
9
|
-
"exports": {
|
|
10
|
-
".": {
|
|
11
|
-
"import": {
|
|
12
|
-
"types": "./dist/index.d.ts",
|
|
13
|
-
"default": "./dist/index.js"
|
|
14
|
-
},
|
|
15
|
-
"require": {
|
|
16
|
-
"types": "./dist/index.d.cts",
|
|
17
|
-
"default": "./dist/index.cjs"
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
},
|
|
21
|
-
"sideEffects": false,
|
|
22
|
-
"files": [
|
|
23
|
-
"dist",
|
|
24
|
-
"README.md",
|
|
25
|
-
"LICENSE"
|
|
26
|
-
],
|
|
27
|
-
"engines": {
|
|
28
|
-
"node": ">=20.0.0"
|
|
29
|
-
},
|
|
30
|
-
"license": "MIT",
|
|
31
|
-
"author": "Aurabase",
|
|
32
|
-
"repository": {
|
|
33
|
-
"type": "git",
|
|
34
|
-
"url": "git+https://github.com/daylami555/aurabase.git",
|
|
35
|
-
"directory": "aurabase-js/packages/db"
|
|
36
|
-
},
|
|
37
|
-
"homepage": "https://github.com/daylami555/aurabase/tree/main/aurabase-js/packages/db#readme",
|
|
38
|
-
"bugs": {
|
|
39
|
-
"url": "https://github.com/daylami555/aurabase/issues"
|
|
40
|
-
},
|
|
41
|
-
"keywords": [
|
|
42
|
-
"aurabase",
|
|
43
|
-
"baas",
|
|
44
|
-
"sdk",
|
|
45
|
-
"database",
|
|
46
|
-
"query"
|
|
47
|
-
],
|
|
48
|
-
"scripts": {
|
|
49
|
-
"build": "tsup",
|
|
50
|
-
"test": "vitest run --passWithNoTests && tsc --noEmit -p tsconfig.test-d.json",
|
|
51
|
-
"test:types": "tsc --noEmit -p tsconfig.test-d.json",
|
|
52
|
-
"typecheck": "tsc --noEmit"
|
|
53
|
-
},
|
|
54
|
-
"dependencies": {
|
|
55
|
-
"@aurabase/core": "workspace:*"
|
|
56
|
-
},
|
|
57
|
-
"devDependencies": {
|
|
58
|
-
"tsup": "catalog:",
|
|
59
|
-
"typescript": "catalog:",
|
|
60
|
-
"vitest": "catalog:"
|
|
61
|
-
}
|
|
62
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 Aurabase
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|