@getstrata/core 0.5.97 → 0.5.99
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/CHANGELOG.md +30 -0
- package/dist/core/contracts/container.d.ts +2 -0
- package/dist/core/database/baseRepository.d.ts +3 -1
- package/dist/core/database/factory.d.ts +47 -5
- package/dist/core/database/index.d.ts +3 -1
- package/dist/core/database/inflection.d.ts +4 -0
- package/dist/core/database/model.d.ts +88 -4
- package/dist/core/database/relationQuery.d.ts +172 -0
- package/dist/core/database/repositoryQuery.d.ts +9 -1
- package/dist/core/database/whereBuilder.d.ts +9 -1
- package/dist/core/events/eventBus.d.ts +2 -0
- package/dist/core/http/resources.d.ts +21 -1
- package/dist/entries/contracts/container.js +6 -0
- package/dist/entries/database/factory.js +159 -6
- package/dist/entries/database/model.js +1066 -23
- package/dist/entries/database/query.js +10 -1
- package/dist/entries/database/repositoryQuery.js +55 -3
- package/dist/entries/database/schema.js +10 -1
- package/dist/entries/http/resources.js +68 -1
- package/dist/framework/public-api.d.ts +4 -2
- package/dist/index.js +1374 -25
- package/package.json +1 -1
|
@@ -74,7 +74,7 @@ function buildOperatorClauses(column, operator, params) {
|
|
|
74
74
|
clauses.push(`${column} <= ${pushParam(params, operator.lte)}`);
|
|
75
75
|
}
|
|
76
76
|
if (operator.ilike !== undefined) {
|
|
77
|
-
clauses.push(`${column} ILIKE ${pushParam(params,
|
|
77
|
+
clauses.push(`${column} ILIKE ${pushParam(params, operator.ilike)}`);
|
|
78
78
|
}
|
|
79
79
|
if (operator.tsMatch !== undefined) {
|
|
80
80
|
clauses.push(`${column} @@ plainto_tsquery('english', ${pushParam(params, operator.tsMatch)})`);
|
|
@@ -112,7 +112,16 @@ function buildWhereClause(tableName, where = {}) {
|
|
|
112
112
|
params
|
|
113
113
|
};
|
|
114
114
|
}
|
|
115
|
+
function remapExistsSql(sql, existsParams, params) {
|
|
116
|
+
const offset = params.length;
|
|
117
|
+
params.push(...existsParams);
|
|
118
|
+
return sql.replace(/\$(\d+)/g, (_match, index) => `$${offset + Number(index)}`);
|
|
119
|
+
}
|
|
115
120
|
function buildWhereNodeClause(tableName, node, params) {
|
|
121
|
+
if ("exists" in node) {
|
|
122
|
+
const body = remapExistsSql(node.exists.sql, node.exists.params, params);
|
|
123
|
+
return `${node.exists.not ? "NOT " : ""}EXISTS (${body})`;
|
|
124
|
+
}
|
|
116
125
|
if ("where" in node) {
|
|
117
126
|
return appendWhereParts(tableName, node.where, params);
|
|
118
127
|
}
|
|
@@ -74,7 +74,7 @@ function buildOperatorClauses(column, operator, params) {
|
|
|
74
74
|
clauses.push(`${column} <= ${pushParam(params, operator.lte)}`);
|
|
75
75
|
}
|
|
76
76
|
if (operator.ilike !== undefined) {
|
|
77
|
-
clauses.push(`${column} ILIKE ${pushParam(params,
|
|
77
|
+
clauses.push(`${column} ILIKE ${pushParam(params, operator.ilike)}`);
|
|
78
78
|
}
|
|
79
79
|
if (operator.tsMatch !== undefined) {
|
|
80
80
|
clauses.push(`${column} @@ plainto_tsquery('english', ${pushParam(params, operator.tsMatch)})`);
|
|
@@ -112,7 +112,16 @@ function buildWhereClause(tableName, where = {}) {
|
|
|
112
112
|
params
|
|
113
113
|
};
|
|
114
114
|
}
|
|
115
|
+
function remapExistsSql(sql, existsParams, params) {
|
|
116
|
+
const offset = params.length;
|
|
117
|
+
params.push(...existsParams);
|
|
118
|
+
return sql.replace(/\$(\d+)/g, (_match, index) => `$${offset + Number(index)}`);
|
|
119
|
+
}
|
|
115
120
|
function buildWhereNodeClause(tableName, node, params) {
|
|
121
|
+
if ("exists" in node) {
|
|
122
|
+
const body = remapExistsSql(node.exists.sql, node.exists.params, params);
|
|
123
|
+
return `${node.exists.not ? "NOT " : ""}EXISTS (${body})`;
|
|
124
|
+
}
|
|
116
125
|
if ("where" in node) {
|
|
117
126
|
return appendWhereParts(tableName, node.where, params);
|
|
118
127
|
}
|
|
@@ -484,6 +493,23 @@ class RepositoryQuery {
|
|
|
484
493
|
this.queryOptions = { ...this.queryOptions, limit };
|
|
485
494
|
return this;
|
|
486
495
|
}
|
|
496
|
+
whereNull(column) {
|
|
497
|
+
return this.where({ [column]: null });
|
|
498
|
+
}
|
|
499
|
+
whereNotNull(column) {
|
|
500
|
+
return this.where({ [column]: { isNull: false } });
|
|
501
|
+
}
|
|
502
|
+
whereIn(column, values) {
|
|
503
|
+
return this.where({ [column]: values });
|
|
504
|
+
}
|
|
505
|
+
whereExists(sql, params = []) {
|
|
506
|
+
this.whereNodes.push({ kind: "and", exists: { sql, params } });
|
|
507
|
+
return this;
|
|
508
|
+
}
|
|
509
|
+
whereNotExists(sql, params = []) {
|
|
510
|
+
this.whereNodes.push({ kind: "and", exists: { sql, params, not: true } });
|
|
511
|
+
return this;
|
|
512
|
+
}
|
|
487
513
|
offset(offset) {
|
|
488
514
|
this.queryOptions = { ...this.queryOptions, offset };
|
|
489
515
|
return this;
|
|
@@ -553,13 +579,30 @@ class RepositoryQuery {
|
|
|
553
579
|
});
|
|
554
580
|
return this;
|
|
555
581
|
}
|
|
582
|
+
withBelongsToMany(as, relation, relatedRepository, options = {}) {
|
|
583
|
+
this.eagerLoads.push({
|
|
584
|
+
kind: "belongsToMany",
|
|
585
|
+
as,
|
|
586
|
+
relation,
|
|
587
|
+
repository: relatedRepository,
|
|
588
|
+
options
|
|
589
|
+
});
|
|
590
|
+
return this;
|
|
591
|
+
}
|
|
556
592
|
async get() {
|
|
557
593
|
const rows = await this.repository.findAll(this.buildOptions());
|
|
558
594
|
return await this.attach(rows);
|
|
559
595
|
}
|
|
560
596
|
async first() {
|
|
561
|
-
const rows = await this.
|
|
562
|
-
|
|
597
|
+
const rows = await this.repository.findAll({ ...this.buildOptions(), limit: 1 });
|
|
598
|
+
const attached = await this.attach(rows);
|
|
599
|
+
return attached[0] ?? null;
|
|
600
|
+
}
|
|
601
|
+
async count() {
|
|
602
|
+
return await this.repository.count(this.buildOptions());
|
|
603
|
+
}
|
|
604
|
+
async attachToRows(rows) {
|
|
605
|
+
return await this.attach(rows);
|
|
563
606
|
}
|
|
564
607
|
async paginate(options) {
|
|
565
608
|
return await this.repository.paginate({
|
|
@@ -631,6 +674,15 @@ class RepositoryQuery {
|
|
|
631
674
|
}));
|
|
632
675
|
continue;
|
|
633
676
|
}
|
|
677
|
+
if (load.kind === "belongsToMany") {
|
|
678
|
+
const relation2 = load.relation;
|
|
679
|
+
const grouped2 = await this.repository.loadBelongsToManyForParents(rows, relation2, load.repository, load.options);
|
|
680
|
+
result = result.map((row) => ({
|
|
681
|
+
...row,
|
|
682
|
+
[load.as]: grouped2.get(row[relation2.parentKey]) ?? []
|
|
683
|
+
}));
|
|
684
|
+
continue;
|
|
685
|
+
}
|
|
634
686
|
if (load.kind === "morphTo") {
|
|
635
687
|
const relation2 = load.relation;
|
|
636
688
|
const grouped2 = await this.repository.loadMorphToForChildren(rows, relation2, load.morphRepositories ?? new Map, load.options);
|
|
@@ -341,7 +341,7 @@ function buildOperatorClauses(column, operator, params) {
|
|
|
341
341
|
clauses.push(`${column} <= ${pushParam(params, operator.lte)}`);
|
|
342
342
|
}
|
|
343
343
|
if (operator.ilike !== undefined) {
|
|
344
|
-
clauses.push(`${column} ILIKE ${pushParam(params,
|
|
344
|
+
clauses.push(`${column} ILIKE ${pushParam(params, operator.ilike)}`);
|
|
345
345
|
}
|
|
346
346
|
if (operator.tsMatch !== undefined) {
|
|
347
347
|
clauses.push(`${column} @@ plainto_tsquery('english', ${pushParam(params, operator.tsMatch)})`);
|
|
@@ -379,7 +379,16 @@ function buildWhereClause(tableName, where = {}) {
|
|
|
379
379
|
params
|
|
380
380
|
};
|
|
381
381
|
}
|
|
382
|
+
function remapExistsSql(sql, existsParams, params) {
|
|
383
|
+
const offset = params.length;
|
|
384
|
+
params.push(...existsParams);
|
|
385
|
+
return sql.replace(/\$(\d+)/g, (_match, index) => `$${offset + Number(index)}`);
|
|
386
|
+
}
|
|
382
387
|
function buildWhereNodeClause(tableName, node, params) {
|
|
388
|
+
if ("exists" in node) {
|
|
389
|
+
const body = remapExistsSql(node.exists.sql, node.exists.params, params);
|
|
390
|
+
return `${node.exists.not ? "NOT " : ""}EXISTS (${body})`;
|
|
391
|
+
}
|
|
383
392
|
if ("where" in node) {
|
|
384
393
|
return appendWhereParts(tableName, node.where, params);
|
|
385
394
|
}
|
|
@@ -3,6 +3,70 @@
|
|
|
3
3
|
function serializeDate(value) {
|
|
4
4
|
return value instanceof Date ? value.toISOString() : value;
|
|
5
5
|
}
|
|
6
|
+
function whenLoaded(model, relation, transform) {
|
|
7
|
+
const value = model.loaded(relation);
|
|
8
|
+
if (value === undefined) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
return transform ? transform(value) : value;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
class JsonResource {
|
|
15
|
+
resource;
|
|
16
|
+
static wrap = "data";
|
|
17
|
+
extra = {};
|
|
18
|
+
constructor(resource) {
|
|
19
|
+
this.resource = resource;
|
|
20
|
+
}
|
|
21
|
+
static make(resource) {
|
|
22
|
+
return new JsonResource(resource);
|
|
23
|
+
}
|
|
24
|
+
static collection(items) {
|
|
25
|
+
return new ResourceCollection(items);
|
|
26
|
+
}
|
|
27
|
+
additional(data) {
|
|
28
|
+
this.extra = { ...this.extra, ...data };
|
|
29
|
+
return this;
|
|
30
|
+
}
|
|
31
|
+
when(condition, value) {
|
|
32
|
+
return condition ? value : undefined;
|
|
33
|
+
}
|
|
34
|
+
whenLoaded(relation, transform) {
|
|
35
|
+
const model = this.resource;
|
|
36
|
+
if (typeof model.loaded !== "function") {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
return whenLoaded(model, relation, transform);
|
|
40
|
+
}
|
|
41
|
+
toArray() {
|
|
42
|
+
if (this.resource && typeof this.resource === "object" && "toArray" in this.resource) {
|
|
43
|
+
return this.resource.toArray();
|
|
44
|
+
}
|
|
45
|
+
return { ...this.resource };
|
|
46
|
+
}
|
|
47
|
+
toResponse() {
|
|
48
|
+
const wrap = this.constructor.wrap;
|
|
49
|
+
const payload = this.toArray();
|
|
50
|
+
if (wrap === null) {
|
|
51
|
+
return { ...payload, ...this.extra };
|
|
52
|
+
}
|
|
53
|
+
return { [wrap]: payload, ...this.extra };
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
class ResourceCollection extends JsonResource {
|
|
58
|
+
toArray() {
|
|
59
|
+
const items = this.resource.map((item) => item instanceof JsonResource ? item.toArray() : { ...item });
|
|
60
|
+
const wrap = this.constructor.wrap;
|
|
61
|
+
if (wrap === null) {
|
|
62
|
+
return { data: items };
|
|
63
|
+
}
|
|
64
|
+
return { [wrap]: items };
|
|
65
|
+
}
|
|
66
|
+
toResponse() {
|
|
67
|
+
return { ...this.toArray(), ...this.extra };
|
|
68
|
+
}
|
|
69
|
+
}
|
|
6
70
|
function toResourceCollection(items, transformer) {
|
|
7
71
|
return items.map(transformer);
|
|
8
72
|
}
|
|
@@ -13,7 +77,10 @@ function toPaginatedResourceCollection(items, meta, transformer) {
|
|
|
13
77
|
};
|
|
14
78
|
}
|
|
15
79
|
export {
|
|
80
|
+
JsonResource,
|
|
81
|
+
ResourceCollection,
|
|
16
82
|
serializeDate,
|
|
17
83
|
toPaginatedResourceCollection,
|
|
18
|
-
toResourceCollection
|
|
84
|
+
toResourceCollection,
|
|
85
|
+
whenLoaded
|
|
19
86
|
};
|
|
@@ -29,11 +29,13 @@ export { bindBunSql, createBunSqlPool } from "../core/database/bunSql.ts";
|
|
|
29
29
|
export { createDatabaseConnection } from "../core/database/connection.ts";
|
|
30
30
|
export { getActiveDatabaseConnection, runWithDatabaseConnection, } from "../core/database/connectionContext.ts";
|
|
31
31
|
export { getDefaultDatabasePool, getDefaultDatabaseQuery, registerDefaultDatabasePool, } from "../core/database/defaultConnection.ts";
|
|
32
|
+
export { Factory } from "../core/database/factory.ts";
|
|
33
|
+
export { foreignKeyFromTable, pivotTableName, singularize } from "../core/database/inflection.ts";
|
|
32
34
|
export { withMigrationLock } from "../core/database/migrations/advisoryLock.ts";
|
|
33
35
|
export { freshDatabase, getMigrationStatus, loadMigrationsFromDirectory, migrateDatabase, rollbackDatabase, } from "../core/database/migrations/runner.ts";
|
|
34
36
|
export type { Migration, MigrationDatabase, MigrationStatus, } from "../core/database/migrations/types.ts";
|
|
35
37
|
export type { CastType, GlobalScopeFn, ModelConstructor } from "../core/database/model.ts";
|
|
36
|
-
export { applyCasts, dehydrateValue, filterMassAssignable, hydrateValue, Model, registerModelRepository, } from "../core/database/model.ts";
|
|
38
|
+
export { applyCasts, BelongsToManyRelationQuery, BelongsToRelationQuery, dehydrateValue, filterMassAssignable, HasManyRelationQuery, HasOneRelationQuery, hydrateValue, Model, ModelQuery, MorphManyRelationQuery, MorphOneRelationQuery, MorphToRelationQuery, registerModelClass, registerModelRepository, } from "../core/database/model.ts";
|
|
37
39
|
export { createDatabaseQueryProxy } from "../core/database/queryProxy.ts";
|
|
38
40
|
export type { BelongsToManyRelation, BelongsToRelation, HasManyRelation, HasOneRelation, MorphManyRelation, MorphOneRelation, MorphToRelation, } from "../core/database/relationships.ts";
|
|
39
41
|
export { belongsTo, belongsToMany, hasMany, hasOne, indexBelongsToManyRelation, indexBelongsToRelation, indexHasManyRelation, indexHasOneRelation, indexMorphManyRelation, indexMorphOneRelation, indexMorphToRelation, morphMany, morphOne, morphTo, } from "../core/database/relationships.ts";
|
|
@@ -77,7 +79,7 @@ export { currentRequestMeta, runWithRequestMeta } from "../core/http/requestMeta
|
|
|
77
79
|
export { createRequireAbilityMiddleware } from "../core/http/requireAbilityMiddleware.ts";
|
|
78
80
|
export { createRequireGlobalAdminMiddleware } from "../core/http/requireGlobalAdminMiddleware.ts";
|
|
79
81
|
export { createRequireWebAuthMiddleware } from "../core/http/requireWebAuthMiddleware.ts";
|
|
80
|
-
export { serializeDate, toPaginatedResourceCollection, toResourceCollection, } from "../core/http/resources.ts";
|
|
82
|
+
export { JsonResource, ResourceCollection, serializeDate, toPaginatedResourceCollection, toResourceCollection, whenLoaded, } from "../core/http/resources.ts";
|
|
81
83
|
export { createdResponse, jsonResponse, noContentResponse, withErrorHandling, } from "../core/http/response.ts";
|
|
82
84
|
export type { RouteRequest } from "../core/http/route.ts";
|
|
83
85
|
export { loginRedirectLocation, safeInternalRedirectPath, sanitizeInternalPath, } from "../core/http/safeInternalPath.ts";
|