@onyx.dev/onyx-database 0.3.0 → 1.0.0
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 +42 -1
- package/dist/gen/cli/generate.cjs +87 -14
- package/dist/gen/cli/generate.cjs.map +1 -1
- package/dist/index.cjs +103 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -3
- package/dist/index.d.ts +7 -3
- package/dist/index.js +102 -21
- package/dist/index.js.map +1 -1
- package/dist/schema/cli/schema.cjs +308 -15
- package/dist/schema/cli/schema.cjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -174,6 +174,10 @@ onyx-schema get --tables=User,Profile
|
|
|
174
174
|
|
|
175
175
|
# Validate a schema file without publishing
|
|
176
176
|
onyx-schema validate ./onyx.schema.json
|
|
177
|
+
|
|
178
|
+
# Diff local schema vs API
|
|
179
|
+
onyx-schema diff ./onyx.schema.json
|
|
180
|
+
# Prints added/removed/changed tables and attribute differences between the API schema and your local file.
|
|
177
181
|
```
|
|
178
182
|
|
|
179
183
|
When `--tables` is provided, the subset is printed to stdout instead of writing a
|
|
@@ -322,7 +326,9 @@ Importable helpers for conditions and sort:
|
|
|
322
326
|
|
|
323
327
|
```ts
|
|
324
328
|
import {
|
|
325
|
-
eq, neq,
|
|
329
|
+
eq, neq, within, notWithin, // preferred aliases for IN/NOT IN
|
|
330
|
+
inOp, notIn,
|
|
331
|
+
between,
|
|
326
332
|
gt, gte, lt, lte,
|
|
327
333
|
like, notLike, contains, notContains,
|
|
328
334
|
startsWith, notStartsWith, matches, notMatches,
|
|
@@ -331,6 +337,41 @@ import {
|
|
|
331
337
|
} from '@onyx.dev/onyx-database';
|
|
332
338
|
```
|
|
333
339
|
|
|
340
|
+
- Prefer `within`/`notWithin` for inclusion checks (supports arrays, comma-separated strings, or inner queries).
|
|
341
|
+
- `inOp`/`notIn` remain available for backward compatibility and are exact aliases.
|
|
342
|
+
|
|
343
|
+
### Inner queries (IN/NOT IN with sub-selects)
|
|
344
|
+
|
|
345
|
+
You can pass another query builder to `within` or `notWithin` to create nested filters. The SDK serializes the inner query (including its table) before sending the request.
|
|
346
|
+
|
|
347
|
+
```ts
|
|
348
|
+
import { onyx, within, notWithin, eq, tables, Schema } from '@onyx.dev/onyx-database';
|
|
349
|
+
|
|
350
|
+
const db = onyx.init<Schema>();
|
|
351
|
+
|
|
352
|
+
// Users that HAVE the admin role
|
|
353
|
+
const usersWithAdmin = await db
|
|
354
|
+
.from(tables.User)
|
|
355
|
+
.where(
|
|
356
|
+
within(
|
|
357
|
+
'id',
|
|
358
|
+
db.select('userId').from(tables.UserRole).where(eq('roleId', 'role-admin')),
|
|
359
|
+
),
|
|
360
|
+
)
|
|
361
|
+
.list();
|
|
362
|
+
|
|
363
|
+
// Roles that DO NOT include a specific permission
|
|
364
|
+
const rolesMissingPermission = await db
|
|
365
|
+
.from(tables.Role)
|
|
366
|
+
.where(
|
|
367
|
+
notWithin(
|
|
368
|
+
'id',
|
|
369
|
+
db.from(tables.RolePermission).where(eq('permissionId', 'perm-manage-users')),
|
|
370
|
+
),
|
|
371
|
+
)
|
|
372
|
+
.list();
|
|
373
|
+
```
|
|
374
|
+
|
|
334
375
|
---
|
|
335
376
|
|
|
336
377
|
## Usage examples with `User`, `Role`, `Permission`
|
|
@@ -931,6 +931,56 @@ var QueryResults = class extends Array {
|
|
|
931
931
|
}
|
|
932
932
|
};
|
|
933
933
|
|
|
934
|
+
// src/helpers/condition-normalizer.ts
|
|
935
|
+
function isQueryBuilderLike(value) {
|
|
936
|
+
return !!value && typeof value.toSerializableQueryObject === "function";
|
|
937
|
+
}
|
|
938
|
+
function normalizeCriteriaValue(value) {
|
|
939
|
+
if (Array.isArray(value)) {
|
|
940
|
+
let changed = false;
|
|
941
|
+
const normalized = value.map((item) => {
|
|
942
|
+
const result = normalizeCriteriaValue(item);
|
|
943
|
+
if (result.changed) changed = true;
|
|
944
|
+
return result.value;
|
|
945
|
+
});
|
|
946
|
+
if (!changed) {
|
|
947
|
+
for (let i = 0; i < normalized.length; i += 1) {
|
|
948
|
+
if (normalized[i] !== value[i]) {
|
|
949
|
+
changed = true;
|
|
950
|
+
break;
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
return { value: changed ? normalized : value, changed };
|
|
955
|
+
}
|
|
956
|
+
if (isQueryBuilderLike(value)) {
|
|
957
|
+
return { value: value.toSerializableQueryObject(), changed: true };
|
|
958
|
+
}
|
|
959
|
+
return { value, changed: false };
|
|
960
|
+
}
|
|
961
|
+
function normalizeConditionInternal(condition) {
|
|
962
|
+
if (condition.conditionType === "SingleCondition") {
|
|
963
|
+
const { value, changed: changed2 } = normalizeCriteriaValue(condition.criteria.value);
|
|
964
|
+
if (!changed2) return condition;
|
|
965
|
+
return {
|
|
966
|
+
...condition,
|
|
967
|
+
criteria: { ...condition.criteria, value }
|
|
968
|
+
};
|
|
969
|
+
}
|
|
970
|
+
let changed = false;
|
|
971
|
+
const normalizedConditions = condition.conditions.map((child) => {
|
|
972
|
+
const normalized = normalizeConditionInternal(child);
|
|
973
|
+
if (normalized !== child) changed = true;
|
|
974
|
+
return normalized;
|
|
975
|
+
});
|
|
976
|
+
if (!changed) return condition;
|
|
977
|
+
return { ...condition, conditions: normalizedConditions };
|
|
978
|
+
}
|
|
979
|
+
function normalizeCondition(condition) {
|
|
980
|
+
if (!condition) return condition;
|
|
981
|
+
return normalizeConditionInternal(condition);
|
|
982
|
+
}
|
|
983
|
+
|
|
934
984
|
// src/builders/cascade-relationship-builder.ts
|
|
935
985
|
var CascadeRelationshipBuilder = class {
|
|
936
986
|
graphName;
|
|
@@ -1058,6 +1108,10 @@ function serializeDates(value) {
|
|
|
1058
1108
|
}
|
|
1059
1109
|
return value;
|
|
1060
1110
|
}
|
|
1111
|
+
function stripEntityText(input) {
|
|
1112
|
+
const { entityText, ...rest } = input;
|
|
1113
|
+
return rest;
|
|
1114
|
+
}
|
|
1061
1115
|
function normalizeSecretMetadata(input) {
|
|
1062
1116
|
return { ...input, updatedAt: new Date(input.updatedAt) };
|
|
1063
1117
|
}
|
|
@@ -1071,7 +1125,7 @@ function normalizeDate(value) {
|
|
|
1071
1125
|
return Number.isNaN(ts.getTime()) ? void 0 : ts;
|
|
1072
1126
|
}
|
|
1073
1127
|
function normalizeSchemaRevision(input, fallbackDatabaseId) {
|
|
1074
|
-
const { meta, createdAt, publishedAt, revisionId, ...rest } = input;
|
|
1128
|
+
const { meta, createdAt, publishedAt, revisionId, entityText, ...rest } = input;
|
|
1075
1129
|
const mergedMeta = {
|
|
1076
1130
|
revisionId: meta?.revisionId ?? revisionId,
|
|
1077
1131
|
createdAt: normalizeDate(meta?.createdAt ?? createdAt),
|
|
@@ -1242,15 +1296,23 @@ var OnyxDatabaseImpl = class {
|
|
|
1242
1296
|
const params = new URLSearchParams();
|
|
1243
1297
|
if (options?.publish) params.append("publish", "true");
|
|
1244
1298
|
const path = `/schemas/${encodeURIComponent(databaseId)}${params.size ? `?${params.toString()}` : ""}`;
|
|
1245
|
-
const body = { ...schema, databaseId: schema.databaseId ?? databaseId };
|
|
1246
|
-
const res = await http.request(
|
|
1299
|
+
const body = stripEntityText({ ...schema, databaseId: schema.databaseId ?? databaseId });
|
|
1300
|
+
const res = await http.request(
|
|
1301
|
+
"PUT",
|
|
1302
|
+
path,
|
|
1303
|
+
serializeDates(body)
|
|
1304
|
+
);
|
|
1247
1305
|
return normalizeSchemaRevision(res, databaseId);
|
|
1248
1306
|
}
|
|
1249
1307
|
async validateSchema(schema) {
|
|
1250
1308
|
const { http, databaseId } = await this.ensureClient();
|
|
1251
1309
|
const path = `/schemas/${encodeURIComponent(databaseId)}/validate`;
|
|
1252
|
-
const body = { ...schema, databaseId: schema.databaseId ?? databaseId };
|
|
1253
|
-
const res = await http.request(
|
|
1310
|
+
const body = stripEntityText({ ...schema, databaseId: schema.databaseId ?? databaseId });
|
|
1311
|
+
const res = await http.request(
|
|
1312
|
+
"POST",
|
|
1313
|
+
path,
|
|
1314
|
+
serializeDates(body)
|
|
1315
|
+
);
|
|
1254
1316
|
const normalizedSchema = res.schema ? normalizeSchemaRevision(res.schema, databaseId) : void 0;
|
|
1255
1317
|
return {
|
|
1256
1318
|
...res,
|
|
@@ -1412,11 +1474,14 @@ var QueryBuilderImpl = class {
|
|
|
1412
1474
|
if (!this.table) throw new Error("Table is not defined. Call from(<table>) first.");
|
|
1413
1475
|
return this.table;
|
|
1414
1476
|
}
|
|
1477
|
+
serializableConditions() {
|
|
1478
|
+
return normalizeCondition(this.conditions);
|
|
1479
|
+
}
|
|
1415
1480
|
toSelectQuery() {
|
|
1416
1481
|
return {
|
|
1417
1482
|
type: "SelectQuery",
|
|
1418
1483
|
fields: this.fields,
|
|
1419
|
-
conditions: this.
|
|
1484
|
+
conditions: this.serializableConditions(),
|
|
1420
1485
|
sort: this.sort,
|
|
1421
1486
|
limit: this.limitValue,
|
|
1422
1487
|
distinct: this.distinctValue,
|
|
@@ -1425,6 +1490,21 @@ var QueryBuilderImpl = class {
|
|
|
1425
1490
|
resolvers: this.resolvers
|
|
1426
1491
|
};
|
|
1427
1492
|
}
|
|
1493
|
+
toUpdateQuery() {
|
|
1494
|
+
return {
|
|
1495
|
+
type: "UpdateQuery",
|
|
1496
|
+
conditions: this.serializableConditions(),
|
|
1497
|
+
updates: this.updates ?? {},
|
|
1498
|
+
sort: this.sort,
|
|
1499
|
+
limit: this.limitValue,
|
|
1500
|
+
partition: this.partitionValue ?? null
|
|
1501
|
+
};
|
|
1502
|
+
}
|
|
1503
|
+
toSerializableQueryObject() {
|
|
1504
|
+
const table = this.ensureTable();
|
|
1505
|
+
const payload = this.mode === "update" ? this.toUpdateQuery() : this.toSelectQuery();
|
|
1506
|
+
return { ...payload, table };
|
|
1507
|
+
}
|
|
1428
1508
|
from(table) {
|
|
1429
1509
|
this.table = table;
|
|
1430
1510
|
return this;
|
|
@@ -1560,14 +1640,7 @@ var QueryBuilderImpl = class {
|
|
|
1560
1640
|
async update() {
|
|
1561
1641
|
if (this.mode !== "update") throw new Error("Call setUpdates(...) before update().");
|
|
1562
1642
|
const table = this.ensureTable();
|
|
1563
|
-
const update =
|
|
1564
|
-
type: "UpdateQuery",
|
|
1565
|
-
conditions: this.conditions,
|
|
1566
|
-
updates: this.updates ?? {},
|
|
1567
|
-
sort: this.sort,
|
|
1568
|
-
limit: this.limitValue,
|
|
1569
|
-
partition: this.partitionValue ?? null
|
|
1570
|
-
};
|
|
1643
|
+
const update = this.toUpdateQuery();
|
|
1571
1644
|
return this.db._update(table, update, this.partitionValue);
|
|
1572
1645
|
}
|
|
1573
1646
|
onItemAdded(listener) {
|