@getstrata/core 0.3.0 → 0.3.2
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/dist/bootstrap/config.d.ts +2 -1
- package/dist/core/database/baseRepository.d.ts +6 -3
- package/dist/core/database/index.d.ts +1 -0
- package/dist/core/database/repositoryQuery.d.ts +20 -0
- package/dist/framework/public-api.d.ts +5 -0
- package/dist/index.js +103 -0
- package/dist/modules/user/provider.d.ts +1 -1
- package/package.json +1 -1
|
@@ -9,6 +9,7 @@ declare const CORE_CACHE_TOKEN = "core.cache";
|
|
|
9
9
|
declare const CORE_QUEUE_TOKEN = "core.queue";
|
|
10
10
|
declare const CORE_POLICY_GATE_TOKEN = "core.policyGate";
|
|
11
11
|
declare const CORE_AUTH_TOKEN = "core.auth";
|
|
12
|
+
declare const CORE_TOKEN_SERVICE_TOKEN = "core.tokenService";
|
|
12
13
|
declare const AUTH_DEV_HEADERS_CONFIG_KEY = "auth.allowDevHeaders";
|
|
13
14
|
declare const DEFAULT_APP_PORT = 3000;
|
|
14
15
|
declare const DEFAULT_CACHE_TTL_MS = 3600000;
|
|
@@ -16,4 +17,4 @@ declare const DEFAULT_CACHE_MAX_ENTRIES = 100;
|
|
|
16
17
|
declare const DEFAULT_CACHE_DRIVER = "array";
|
|
17
18
|
declare const DEFAULT_API_TOKEN = "";
|
|
18
19
|
declare const DEFAULT_QUEUE_DRIVER = "sync";
|
|
19
|
-
export { APP_PORT_CONFIG_KEY, AUTH_DEV_HEADERS_CONFIG_KEY, CACHE_DRIVER_CONFIG_KEY, CACHE_MAX_ENTRIES_CONFIG_KEY, CACHE_TTL_MS_CONFIG_KEY, CORE_AUTH_TOKEN, CORE_CACHE_TOKEN, CORE_CONFIG_TOKEN, CORE_POLICY_GATE_TOKEN, CORE_QUEUE_TOKEN, DATABASE_URL_CONFIG_KEY, DEFAULT_API_TOKEN, DEFAULT_APP_PORT, DEFAULT_CACHE_DRIVER, DEFAULT_CACHE_MAX_ENTRIES, DEFAULT_CACHE_TTL_MS, DEFAULT_QUEUE_DRIVER, REDIS_URL_CONFIG_KEY, };
|
|
20
|
+
export { APP_PORT_CONFIG_KEY, AUTH_DEV_HEADERS_CONFIG_KEY, CACHE_DRIVER_CONFIG_KEY, CACHE_MAX_ENTRIES_CONFIG_KEY, CACHE_TTL_MS_CONFIG_KEY, CORE_AUTH_TOKEN, CORE_CACHE_TOKEN, CORE_CONFIG_TOKEN, CORE_POLICY_GATE_TOKEN, CORE_QUEUE_TOKEN, CORE_TOKEN_SERVICE_TOKEN, DATABASE_URL_CONFIG_KEY, DEFAULT_API_TOKEN, DEFAULT_APP_PORT, DEFAULT_CACHE_DRIVER, DEFAULT_CACHE_MAX_ENTRIES, DEFAULT_CACHE_TTL_MS, DEFAULT_QUEUE_DRIVER, REDIS_URL_CONFIG_KEY, };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type PaginatedResult } from "../pagination/index.ts";
|
|
2
2
|
import { type BelongsToRelation, type HasManyRelation } from "./relationships.ts";
|
|
3
|
+
import { RepositoryQuery } from "./repositoryQuery.ts";
|
|
3
4
|
import type { TableDefinition } from "./table.ts";
|
|
4
5
|
import type { MutationValues, QueryOptions, QueryWhere, UpdateValues } from "./types.ts";
|
|
5
6
|
interface DatabaseConnection {
|
|
@@ -27,6 +28,8 @@ declare class BaseRepository<TEntity extends object, PrimaryKey extends keyof TE
|
|
|
27
28
|
forceDeleteById(id: TEntity[PrimaryKey]): Promise<boolean>;
|
|
28
29
|
restoreById(id: TEntity[PrimaryKey]): Promise<TEntity | null>;
|
|
29
30
|
withConnection(connection: DatabaseConnection): this;
|
|
31
|
+
getConnection(): DatabaseConnection;
|
|
32
|
+
query(where?: QueryWhere<TEntity>): RepositoryQuery<TEntity, PrimaryKey>;
|
|
30
33
|
protected findWhere(where: QueryWhere<TEntity>, options?: Omit<QueryOptions<TEntity>, "where">): Promise<TEntity[]>;
|
|
31
34
|
protected countWhere(where?: QueryWhere<TEntity>, options?: Pick<QueryOptions<TEntity>, "withTrashed" | "onlyTrashed">): Promise<number>;
|
|
32
35
|
protected averageColumn(column: keyof TEntity & string, where?: QueryWhere<TEntity>): Promise<number>;
|
|
@@ -36,9 +39,9 @@ declare class BaseRepository<TEntity extends object, PrimaryKey extends keyof TE
|
|
|
36
39
|
value: TEntity[K] | null;
|
|
37
40
|
count: number;
|
|
38
41
|
}>>;
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
+
findByHasManyRelation<TParent extends object, LocalKey extends keyof TParent & string, ForeignKey extends keyof TEntity & string>(relation: HasManyRelation<TParent, TEntity, LocalKey, ForeignKey>, parentId: TParent[LocalKey], options?: Omit<QueryOptions<TEntity>, "where">): Promise<TEntity[]>;
|
|
43
|
+
loadHasManyForParents<TParent extends object, LocalKey extends keyof TParent & string, ForeignKey extends keyof TEntity & string>(parents: readonly TParent[], relation: HasManyRelation<TParent, TEntity, LocalKey, ForeignKey>, options?: Omit<QueryOptions<TEntity>, "where">): Promise<Map<TParent[LocalKey], TEntity[]>>;
|
|
44
|
+
loadBelongsToForParents<TChild extends object, TParent extends object, ForeignKey extends keyof TChild & string, OwnerKey extends keyof TParent & string>(children: readonly TChild[], relation: BelongsToRelation<TChild, TParent, ForeignKey, OwnerKey>, parentRepository: BaseRepository<TParent, OwnerKey>, options?: Omit<QueryOptions<TParent>, "where">): Promise<Map<TChild[ForeignKey], TParent>>;
|
|
42
45
|
}
|
|
43
46
|
export default BaseRepository;
|
|
44
47
|
export type { DatabaseConnection };
|
|
@@ -5,6 +5,7 @@ export { mapDatabaseError, withDatabaseErrorHandling } from "./errors.ts";
|
|
|
5
5
|
export { buildCountQuery, buildDeleteByIdQuery, buildGroupedCountQuery, buildInsertQuery, buildOrderByClause, buildProjectionQuery, buildQueryWhereClause, buildRestoreByIdQuery, buildSelectQuery, buildSoftDeleteByIdQuery, buildUpdateQuery, buildWhereClause, qualifyColumn, quoteIdentifier, resolveSoftDeleteColumn, } from "./query.ts";
|
|
6
6
|
export type { BelongsToRelation, HasManyRelation } from "./relationships.ts";
|
|
7
7
|
export { belongsTo, hasMany, indexBelongsToRelation, indexHasManyRelation, } from "./relationships.ts";
|
|
8
|
+
export { RepositoryQuery } from "./repositoryQuery.ts";
|
|
8
9
|
export type { TableDefinition } from "./table.ts";
|
|
9
10
|
export { defineTable } from "./table.ts";
|
|
10
11
|
export { runInTransaction } from "./transaction.ts";
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type BaseRepository from "./baseRepository.ts";
|
|
2
|
+
import type { BelongsToRelation, HasManyRelation } from "./relationships.ts";
|
|
3
|
+
import type { QueryOptions, QueryWhere } from "./types.ts";
|
|
4
|
+
type LoadedRow = Record<string, unknown>;
|
|
5
|
+
declare class RepositoryQuery<TEntity extends object, PrimaryKey extends keyof TEntity & string> {
|
|
6
|
+
private readonly repository;
|
|
7
|
+
private whereClause;
|
|
8
|
+
private queryOptions;
|
|
9
|
+
private readonly eagerLoads;
|
|
10
|
+
constructor(repository: BaseRepository<TEntity, PrimaryKey>, whereClause?: QueryWhere<TEntity>, queryOptions?: Omit<QueryOptions<TEntity>, "where">);
|
|
11
|
+
where(where: QueryWhere<TEntity>): this;
|
|
12
|
+
orderBy(orderBy: QueryOptions<TEntity>["orderBy"]): this;
|
|
13
|
+
limit(limit: number): this;
|
|
14
|
+
withHasMany<TChild extends object, LocalKey extends keyof TEntity & string, ForeignKey extends keyof TChild & string, Alias extends string>(as: Alias, relation: HasManyRelation<TEntity, TChild, LocalKey, ForeignKey>, childRepository: BaseRepository<TChild, keyof TChild & string>, options?: Omit<QueryOptions<TChild>, "where">): this;
|
|
15
|
+
withBelongsTo<TParent extends object, ForeignKey extends keyof TEntity & string, OwnerKey extends keyof TParent & string, Alias extends string>(as: Alias, relation: BelongsToRelation<TEntity, TParent, ForeignKey, OwnerKey>, parentRepository: BaseRepository<TParent, OwnerKey>, options?: Omit<QueryOptions<TParent>, "where">): this;
|
|
16
|
+
get(): Promise<Array<TEntity & LoadedRow>>;
|
|
17
|
+
first(): Promise<(TEntity & LoadedRow) | null>;
|
|
18
|
+
private attach;
|
|
19
|
+
}
|
|
20
|
+
export { RepositoryQuery };
|
|
@@ -9,8 +9,13 @@ export { currentAuthUser, runWithAuthUser } from "../core/auth/authContext";
|
|
|
9
9
|
export { Policy } from "../core/auth/policy";
|
|
10
10
|
export { default as CacheRepository } from "../core/cache/repository";
|
|
11
11
|
export { CACHE_TAGS } from "../core/cache/tags";
|
|
12
|
+
export type { DatabaseConnection } from "../core/database/baseRepository";
|
|
12
13
|
export { default as BaseRepository } from "../core/database/baseRepository";
|
|
14
|
+
export type { BelongsToRelation, HasManyRelation } from "../core/database/relationships";
|
|
15
|
+
export { belongsTo, hasMany, indexBelongsToRelation, indexHasManyRelation, } from "../core/database/relationships";
|
|
16
|
+
export { RepositoryQuery } from "../core/database/repositoryQuery";
|
|
13
17
|
export { defineTable } from "../core/database/table";
|
|
18
|
+
export type { QueryOptions, QueryOrder, QueryWhere, } from "../core/database/types";
|
|
14
19
|
export { BadRequestError, ConflictError, ForbiddenError, NotFoundError, PreconditionFailedError, UnauthorizedError, UnprocessableEntityError, ValidationError, } from "../core/errors/http";
|
|
15
20
|
export { EventBus } from "../core/events/eventBus";
|
|
16
21
|
export { auth, cache, config, events, log, mail, policyGate, queue, storage, } from "../core/facades";
|
package/dist/index.js
CHANGED
|
@@ -699,6 +699,18 @@ function buildDeleteByIdQuery(table, id) {
|
|
|
699
699
|
}
|
|
700
700
|
|
|
701
701
|
// ../../src/core/database/relationships.ts
|
|
702
|
+
function hasMany(definition) {
|
|
703
|
+
return {
|
|
704
|
+
type: "hasMany",
|
|
705
|
+
...definition
|
|
706
|
+
};
|
|
707
|
+
}
|
|
708
|
+
function belongsTo(definition) {
|
|
709
|
+
return {
|
|
710
|
+
type: "belongsTo",
|
|
711
|
+
...definition
|
|
712
|
+
};
|
|
713
|
+
}
|
|
702
714
|
function indexHasManyRelation(parents, children, relation) {
|
|
703
715
|
const groups = new Map;
|
|
704
716
|
for (const parent of parents) {
|
|
@@ -730,6 +742,86 @@ function indexBelongsToRelation(children, parents, relation) {
|
|
|
730
742
|
return result;
|
|
731
743
|
}
|
|
732
744
|
|
|
745
|
+
// ../../src/core/database/repositoryQuery.ts
|
|
746
|
+
class RepositoryQuery {
|
|
747
|
+
repository;
|
|
748
|
+
whereClause;
|
|
749
|
+
queryOptions;
|
|
750
|
+
eagerLoads = [];
|
|
751
|
+
constructor(repository, whereClause = {}, queryOptions = {}) {
|
|
752
|
+
this.repository = repository;
|
|
753
|
+
this.whereClause = whereClause;
|
|
754
|
+
this.queryOptions = queryOptions;
|
|
755
|
+
}
|
|
756
|
+
where(where) {
|
|
757
|
+
this.whereClause = { ...this.whereClause, ...where };
|
|
758
|
+
return this;
|
|
759
|
+
}
|
|
760
|
+
orderBy(orderBy) {
|
|
761
|
+
this.queryOptions = { ...this.queryOptions, orderBy };
|
|
762
|
+
return this;
|
|
763
|
+
}
|
|
764
|
+
limit(limit) {
|
|
765
|
+
this.queryOptions = { ...this.queryOptions, limit };
|
|
766
|
+
return this;
|
|
767
|
+
}
|
|
768
|
+
withHasMany(as, relation, childRepository, options = {}) {
|
|
769
|
+
this.eagerLoads.push({
|
|
770
|
+
kind: "hasMany",
|
|
771
|
+
as,
|
|
772
|
+
relation,
|
|
773
|
+
repository: childRepository,
|
|
774
|
+
options
|
|
775
|
+
});
|
|
776
|
+
return this;
|
|
777
|
+
}
|
|
778
|
+
withBelongsTo(as, relation, parentRepository, options = {}) {
|
|
779
|
+
this.eagerLoads.push({
|
|
780
|
+
kind: "belongsTo",
|
|
781
|
+
as,
|
|
782
|
+
relation,
|
|
783
|
+
repository: parentRepository,
|
|
784
|
+
options
|
|
785
|
+
});
|
|
786
|
+
return this;
|
|
787
|
+
}
|
|
788
|
+
async get() {
|
|
789
|
+
const rows = await this.repository.findAll({
|
|
790
|
+
...this.queryOptions,
|
|
791
|
+
where: this.whereClause
|
|
792
|
+
});
|
|
793
|
+
return await this.attach(rows);
|
|
794
|
+
}
|
|
795
|
+
async first() {
|
|
796
|
+
const rows = await this.get();
|
|
797
|
+
return rows[0] ?? null;
|
|
798
|
+
}
|
|
799
|
+
async attach(rows) {
|
|
800
|
+
if (rows.length === 0 || this.eagerLoads.length === 0) {
|
|
801
|
+
return rows.map((row) => ({ ...row }));
|
|
802
|
+
}
|
|
803
|
+
let result = rows.map((row) => ({ ...row }));
|
|
804
|
+
for (const load of this.eagerLoads) {
|
|
805
|
+
if (load.kind === "hasMany") {
|
|
806
|
+
const relation2 = load.relation;
|
|
807
|
+
const grouped2 = await load.repository.withConnection(this.repository.getConnection()).loadHasManyForParents(rows, relation2, load.options);
|
|
808
|
+
result = result.map((row) => ({
|
|
809
|
+
...row,
|
|
810
|
+
[load.as]: grouped2.get(row[relation2.localKey]) ?? []
|
|
811
|
+
}));
|
|
812
|
+
continue;
|
|
813
|
+
}
|
|
814
|
+
const relation = load.relation;
|
|
815
|
+
const grouped = await this.repository.loadBelongsToForParents(rows, relation, load.repository, load.options);
|
|
816
|
+
result = result.map((row) => ({
|
|
817
|
+
...row,
|
|
818
|
+
[load.as]: grouped.get(row[relation.foreignKey])
|
|
819
|
+
}));
|
|
820
|
+
}
|
|
821
|
+
return result;
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
|
|
733
825
|
// ../../src/core/database/baseRepository.ts
|
|
734
826
|
class BaseRepository {
|
|
735
827
|
table;
|
|
@@ -866,6 +958,12 @@ class BaseRepository {
|
|
|
866
958
|
clone.connection = connection;
|
|
867
959
|
return clone;
|
|
868
960
|
}
|
|
961
|
+
getConnection() {
|
|
962
|
+
return this.connection;
|
|
963
|
+
}
|
|
964
|
+
query(where = {}) {
|
|
965
|
+
return new RepositoryQuery(this, where);
|
|
966
|
+
}
|
|
869
967
|
async findWhere(where, options = {}) {
|
|
870
968
|
return await this.findAll({ ...options, where });
|
|
871
969
|
}
|
|
@@ -2163,6 +2261,9 @@ export {
|
|
|
2163
2261
|
log,
|
|
2164
2262
|
jsonResponse,
|
|
2165
2263
|
isEtagEnabled,
|
|
2264
|
+
indexHasManyRelation,
|
|
2265
|
+
indexBelongsToRelation,
|
|
2266
|
+
hasMany,
|
|
2166
2267
|
events,
|
|
2167
2268
|
etagFromResource,
|
|
2168
2269
|
defineTable,
|
|
@@ -2172,6 +2273,7 @@ export {
|
|
|
2172
2273
|
createMetricsMiddleware,
|
|
2173
2274
|
config,
|
|
2174
2275
|
cache,
|
|
2276
|
+
belongsTo,
|
|
2175
2277
|
auth,
|
|
2176
2278
|
assertIfMatch,
|
|
2177
2279
|
WebFormRequest,
|
|
@@ -2181,6 +2283,7 @@ export {
|
|
|
2181
2283
|
SyncQueue,
|
|
2182
2284
|
StorageManager,
|
|
2183
2285
|
ServiceContainer,
|
|
2286
|
+
RepositoryQuery,
|
|
2184
2287
|
PrometheusRegistry,
|
|
2185
2288
|
PreconditionFailedError,
|
|
2186
2289
|
Policy,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ServiceProvider } from "../../bootstrap/contracts";
|
|
2
2
|
declare const userRepositoryToken = "user.repository";
|
|
3
3
|
declare const apiTokenRepositoryToken = "user.apiTokenRepository";
|
|
4
|
-
declare const tokenServiceToken = "
|
|
4
|
+
declare const tokenServiceToken = "core.tokenService";
|
|
5
5
|
declare const authServiceToken = "user.authService";
|
|
6
6
|
declare const oauthIdentityRepositoryToken = "user.oauthIdentityRepository";
|
|
7
7
|
declare const notificationRepositoryToken = "user.notificationRepository";
|