@getstrata/core 1.0.5 → 1.0.6
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 +4 -0
- package/dist/core/database/index.d.ts +1 -0
- package/dist/core/database/model.d.ts +8 -0
- package/dist/core/database/pluck.d.ts +5 -0
- package/dist/core/database/relationQuery.d.ts +30 -0
- package/dist/core/database/repositoryQuery.d.ts +4 -0
- package/dist/entries/database/model.js +172 -22
- package/dist/entries/database/repositoryQuery.js +49 -1
- package/dist/framework/public-api.d.ts +1 -1
- package/dist/index.js +196 -22
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# @getstrata/core changelog
|
|
2
2
|
|
|
3
|
+
## 1.0.6
|
|
4
|
+
|
|
5
|
+
- Query `pluck` and `value` on `RepositoryQuery`, `ModelQuery`, and relation queries. `pluck(column)` returns `T[]`; `pluck(column, keyBy)` returns a `Map`. Models apply `$casts` and skip hydration/observers. Generated apps and lockstep packages move to `^1.0.6`.
|
|
6
|
+
|
|
3
7
|
## 1.0.5
|
|
4
8
|
|
|
5
9
|
- `@getstrata/core/database/mysqlConnection` re-exports the barrel so the barrel and the subpath share one lazy `mysql2` load. Importing both in one process no longer starts two independent loaders.
|
|
@@ -14,6 +14,7 @@ export type { MysqlConnection, MysqlExecutable, MysqlPool } from "./mysqlConnect
|
|
|
14
14
|
export { createMysqlConnection, createMysqlConnectionFromPool, createMysqlPool, } from "./mysqlConnection.ts";
|
|
15
15
|
export type { NamedConnectionEntry } from "./namedConnections.ts";
|
|
16
16
|
export { getNamedConnection, hasNamedConnection, registerNamedConnection, resetNamedConnections, runOnNamedConnection, unregisterNamedConnection, } from "./namedConnections.ts";
|
|
17
|
+
export { projectPluck, uniqueColumnSelect } from "./pluck.ts";
|
|
17
18
|
export { buildAdvancedWhereClause, buildCountQuery, buildDeleteByIdQuery, buildGroupedCountQuery, buildInsertQuery, buildJoinClause, buildOrderByClause, buildProjectionQuery, buildQueryWhereClause, buildRestoreByIdQuery, buildSelectQuery, buildSoftDeleteByIdQuery, buildUpdateQuery, buildWhereClause, parseQualifiedColumn, qualifyColumn, quoteIdentifier, resolveQualifiedColumn, resolveSoftDeleteColumn, } from "./query.ts";
|
|
18
19
|
export type { BelongsToManyRelation, BelongsToRelation, HasManyRelation, HasManyThroughRelation, HasOneRelation, MorphManyRelation, MorphOneRelation, MorphToRelation, } from "./relationships.ts";
|
|
19
20
|
export { belongsTo, belongsToMany, hasMany, hasManyThrough, hasOne, indexBelongsToManyRelation, indexBelongsToRelation, indexHasManyRelation, indexHasManyThroughRelation, indexHasOneRelation, indexMorphManyRelation, indexMorphOneRelation, indexMorphToRelation, morphMany, morphOne, morphTo, } from "./relationships.ts";
|
|
@@ -61,6 +61,10 @@ declare class ModelQuery {
|
|
|
61
61
|
onlyTrashed(): this;
|
|
62
62
|
get(): Promise<Array<Model<Record<string, unknown>, "id">>>;
|
|
63
63
|
first(): Promise<Model<Record<string, unknown>, "id"> | null>;
|
|
64
|
+
count(): Promise<number>;
|
|
65
|
+
pluck(column: string): Promise<unknown[]>;
|
|
66
|
+
pluck(column: string, keyBy: string): Promise<Map<unknown, unknown>>;
|
|
67
|
+
value(column: string): Promise<unknown>;
|
|
64
68
|
find(id: unknown): Promise<Model<Record<string, unknown>, "id"> | null>;
|
|
65
69
|
findOrFail(id: unknown, errorFactory?: (id: unknown) => Error): Promise<Model<Record<string, unknown>, "id">>;
|
|
66
70
|
then(onfulfilled?: ((value: Array<Model<Record<string, unknown>, "id">>) => unknown) | null, onrejected?: ((reason: unknown) => unknown) | null): Promise<unknown>;
|
|
@@ -129,6 +133,10 @@ declare class Model<TEntity extends object, PrimaryKey extends keyof TEntity & s
|
|
|
129
133
|
static findOrFail(this: object, id: unknown, errorFactory?: (id: unknown) => Error): Promise<Model<Record<string, unknown>, "id">>;
|
|
130
134
|
static all(this: object, options?: Omit<QueryOptions<object>, "where">): Promise<Array<Model<Record<string, unknown>, "id">>>;
|
|
131
135
|
static where(this: object, where: QueryWhere<object>): ModelQuery;
|
|
136
|
+
static count(this: object): Promise<number>;
|
|
137
|
+
static pluck(this: object, column: string): Promise<unknown[]>;
|
|
138
|
+
static pluck(this: object, column: string, keyBy: string): Promise<Map<unknown, unknown>>;
|
|
139
|
+
static value(this: object, column: string): Promise<unknown>;
|
|
132
140
|
static firstWhere(this: object, where: QueryWhere<object>, options?: Omit<QueryOptions<object>, "where">): Promise<Model<Record<string, unknown>, "id"> | null>;
|
|
133
141
|
static firstOrNew(this: object, where: QueryWhere<object>, values?: Record<string, unknown>): Promise<Model<Record<string, unknown>, "id">>;
|
|
134
142
|
static firstOrCreate(this: object, where: QueryWhere<object>, values?: Record<string, unknown>): Promise<Model<Record<string, unknown>, "id">>;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { QuerySelectItem } from "./types.ts";
|
|
2
|
+
declare function uniqueColumnSelect(table: string, columns: readonly string[]): QuerySelectItem[];
|
|
3
|
+
declare function projectPluck<T extends object, K extends keyof T & string>(rows: readonly T[], column: K): Array<T[K]>;
|
|
4
|
+
declare function projectPluck<T extends object, K extends keyof T & string, KK extends keyof T & string>(rows: readonly T[], column: K, keyBy: KK): Map<T[KK], T[K]>;
|
|
5
|
+
export { projectPluck, uniqueColumnSelect };
|
|
@@ -40,6 +40,9 @@ declare class HasManyRelationQuery<TParent extends object, ParentKey extends key
|
|
|
40
40
|
get(): Promise<RelatedRecord[]>;
|
|
41
41
|
first(): Promise<RelatedRecord | null>;
|
|
42
42
|
count(): Promise<number>;
|
|
43
|
+
pluck(column: string): Promise<unknown[]>;
|
|
44
|
+
pluck(column: string, keyBy: string): Promise<Map<unknown, unknown>>;
|
|
45
|
+
value(column: string): Promise<unknown>;
|
|
43
46
|
then(onfulfilled?: ((value: RelatedRecord[]) => unknown) | null, onrejected?: ((reason: unknown) => unknown) | null): Promise<unknown>;
|
|
44
47
|
create(attributes?: Record<string, unknown>): Promise<RelatedRecord>;
|
|
45
48
|
save(related: RelatedRecord | (Record<string, unknown> & {
|
|
@@ -61,6 +64,9 @@ declare class HasOneRelationQuery<TParent extends object, ParentKey extends keyo
|
|
|
61
64
|
get(): Promise<RelatedRecord | null>;
|
|
62
65
|
first(): Promise<RelatedRecord | null>;
|
|
63
66
|
count(): Promise<number>;
|
|
67
|
+
pluck(column: string): Promise<unknown[]>;
|
|
68
|
+
pluck(column: string, keyBy: string): Promise<Map<unknown, unknown>>;
|
|
69
|
+
value(column: string): Promise<unknown>;
|
|
64
70
|
then(onfulfilled?: ((value: RelatedRecord | null) => unknown) | null, onrejected?: ((reason: unknown) => unknown) | null): Promise<unknown>;
|
|
65
71
|
create(attributes?: Record<string, unknown>): Promise<RelatedRecord>;
|
|
66
72
|
save(related: RelatedRecord | Record<string, unknown>): Promise<RelatedRecord>;
|
|
@@ -80,6 +86,10 @@ declare class BelongsToRelationQuery<TChild extends object, ChildKey extends key
|
|
|
80
86
|
toExistsClause(parentTable: string): ExistsClause;
|
|
81
87
|
get(): Promise<RelatedRecord | null>;
|
|
82
88
|
first(): Promise<RelatedRecord | null>;
|
|
89
|
+
pluck(column: string): Promise<unknown[]>;
|
|
90
|
+
pluck(column: string, keyBy: string): Promise<Map<unknown, unknown>>;
|
|
91
|
+
value(column: string): Promise<unknown>;
|
|
92
|
+
private relatedQuery;
|
|
83
93
|
then(onfulfilled?: ((value: RelatedRecord | null) => unknown) | null, onrejected?: ((reason: unknown) => unknown) | null): Promise<unknown>;
|
|
84
94
|
associate(owner: {
|
|
85
95
|
id?: unknown;
|
|
@@ -105,6 +115,10 @@ declare class BelongsToManyRelationQuery<TParent extends object, ParentKey exten
|
|
|
105
115
|
get(): Promise<RelatedRecord[]>;
|
|
106
116
|
first(): Promise<RelatedRecord | null>;
|
|
107
117
|
count(): Promise<number>;
|
|
118
|
+
pluck(column: string): Promise<unknown[]>;
|
|
119
|
+
pluck(column: string, keyBy: string): Promise<Map<unknown, unknown>>;
|
|
120
|
+
value(column: string): Promise<unknown>;
|
|
121
|
+
private relatedQuery;
|
|
108
122
|
then(onfulfilled?: ((value: RelatedRecord[]) => unknown) | null, onrejected?: ((reason: unknown) => unknown) | null): Promise<unknown>;
|
|
109
123
|
attach(ids: unknown | readonly unknown[]): Promise<void>;
|
|
110
124
|
toggle(ids: unknown | readonly unknown[]): Promise<void>;
|
|
@@ -124,9 +138,13 @@ declare class MorphManyRelationQuery<TParent extends object, ParentKey extends k
|
|
|
124
138
|
applyEagerLoad(query: RepositoryQuery<TParent, ParentKey>, alias: string): void;
|
|
125
139
|
hydrateEager(row: Record<string, unknown>, alias: string): unknown;
|
|
126
140
|
toExistsClause(parentTable: string): ExistsClause;
|
|
141
|
+
private scopedQuery;
|
|
127
142
|
get(): Promise<RelatedRecord[]>;
|
|
128
143
|
first(): Promise<RelatedRecord | null>;
|
|
129
144
|
count(): Promise<number>;
|
|
145
|
+
pluck(column: string): Promise<unknown[]>;
|
|
146
|
+
pluck(column: string, keyBy: string): Promise<Map<unknown, unknown>>;
|
|
147
|
+
value(column: string): Promise<unknown>;
|
|
130
148
|
then(onfulfilled?: ((value: RelatedRecord[]) => unknown) | null, onrejected?: ((reason: unknown) => unknown) | null): Promise<unknown>;
|
|
131
149
|
create(attributes?: Record<string, unknown>): Promise<RelatedRecord>;
|
|
132
150
|
}
|
|
@@ -142,6 +160,9 @@ declare class MorphOneRelationQuery<TParent extends object, ParentKey extends ke
|
|
|
142
160
|
get(): Promise<RelatedRecord | null>;
|
|
143
161
|
first(): Promise<RelatedRecord | null>;
|
|
144
162
|
count(): Promise<number>;
|
|
163
|
+
pluck(column: string): Promise<unknown[]>;
|
|
164
|
+
pluck(column: string, keyBy: string): Promise<Map<unknown, unknown>>;
|
|
165
|
+
value(column: string): Promise<unknown>;
|
|
145
166
|
then(onfulfilled?: ((value: RelatedRecord | null) => unknown) | null, onrejected?: ((reason: unknown) => unknown) | null): Promise<unknown>;
|
|
146
167
|
create(attributes?: Record<string, unknown>): Promise<RelatedRecord>;
|
|
147
168
|
}
|
|
@@ -157,6 +178,11 @@ declare class MorphToRelationQuery<TChild extends object, ChildKey extends keyof
|
|
|
157
178
|
hydrateEager(row: Record<string, unknown>, alias: string): unknown;
|
|
158
179
|
toExistsClause(parentTable: string): ExistsClause;
|
|
159
180
|
get(): Promise<RelatedRecord | null>;
|
|
181
|
+
pluck(column: string): Promise<unknown[]>;
|
|
182
|
+
pluck(column: string, keyBy: string): Promise<Map<unknown, unknown>>;
|
|
183
|
+
value(column: string): Promise<unknown>;
|
|
184
|
+
private relatedForCurrentType;
|
|
185
|
+
private relatedQuery;
|
|
160
186
|
then(onfulfilled?: ((value: RelatedRecord | null) => unknown) | null, onrejected?: ((reason: unknown) => unknown) | null): Promise<unknown>;
|
|
161
187
|
}
|
|
162
188
|
declare class HasManyThroughRelationQuery<TParent extends object, ParentKey extends keyof TParent & string, TFar extends object, FarKey extends keyof TFar & string> {
|
|
@@ -176,6 +202,10 @@ declare class HasManyThroughRelationQuery<TParent extends object, ParentKey exte
|
|
|
176
202
|
get(): Promise<RelatedRecord[]>;
|
|
177
203
|
first(): Promise<RelatedRecord | null>;
|
|
178
204
|
count(): Promise<number>;
|
|
205
|
+
pluck(column: string): Promise<unknown[]>;
|
|
206
|
+
pluck(column: string, keyBy: string): Promise<Map<unknown, unknown>>;
|
|
207
|
+
value(column: string): Promise<unknown>;
|
|
208
|
+
private farRows;
|
|
179
209
|
then(onfulfilled?: ((value: RelatedRecord[]) => unknown) | null, onrejected?: ((reason: unknown) => unknown) | null): Promise<unknown>;
|
|
180
210
|
}
|
|
181
211
|
type AnyRelationQuery = {
|
|
@@ -37,6 +37,9 @@ declare class RepositoryQuery<TEntity extends object, PrimaryKey extends keyof T
|
|
|
37
37
|
get(): Promise<Array<TEntity & LoadedRow>>;
|
|
38
38
|
first(): Promise<(TEntity & LoadedRow) | null>;
|
|
39
39
|
count(): Promise<number>;
|
|
40
|
+
pluck<K extends keyof TEntity & string>(column: K): Promise<Array<TEntity[K]>>;
|
|
41
|
+
pluck<K extends keyof TEntity & string, KK extends keyof TEntity & string>(column: K, keyBy: KK): Promise<Map<TEntity[KK], TEntity[K]>>;
|
|
42
|
+
value<K extends keyof TEntity & string>(column: K): Promise<TEntity[K] | null>;
|
|
40
43
|
attachToRows(rows: readonly TEntity[]): Promise<Array<TEntity & LoadedRow>>;
|
|
41
44
|
paginate(options: {
|
|
42
45
|
page: number;
|
|
@@ -47,4 +50,5 @@ declare class RepositoryQuery<TEntity extends object, PrimaryKey extends keyof T
|
|
|
47
50
|
private attach;
|
|
48
51
|
private hydrateEagerLoad;
|
|
49
52
|
}
|
|
53
|
+
export { projectPluck, uniqueColumnSelect } from "./pluck.ts";
|
|
50
54
|
export { RepositoryQuery };
|
|
@@ -458,6 +458,30 @@ function buildDeleteByIdQuery(table, id) {
|
|
|
458
458
|
};
|
|
459
459
|
}
|
|
460
460
|
|
|
461
|
+
// ../../src/core/database/pluck.ts
|
|
462
|
+
function uniqueColumnSelect(table, columns) {
|
|
463
|
+
const seen = new Set;
|
|
464
|
+
const select = [];
|
|
465
|
+
for (const column of columns) {
|
|
466
|
+
if (seen.has(column)) {
|
|
467
|
+
continue;
|
|
468
|
+
}
|
|
469
|
+
seen.add(column);
|
|
470
|
+
select.push({ kind: "column", table, column, as: column });
|
|
471
|
+
}
|
|
472
|
+
return select;
|
|
473
|
+
}
|
|
474
|
+
function projectPluck(rows, column, keyBy) {
|
|
475
|
+
if (keyBy === undefined) {
|
|
476
|
+
return rows.map((row) => row[column]);
|
|
477
|
+
}
|
|
478
|
+
const keyed = new Map;
|
|
479
|
+
for (const row of rows) {
|
|
480
|
+
keyed.set(row[keyBy], row[column]);
|
|
481
|
+
}
|
|
482
|
+
return keyed;
|
|
483
|
+
}
|
|
484
|
+
|
|
461
485
|
// ../../src/core/database/relationQuery.ts
|
|
462
486
|
function asWhere(where) {
|
|
463
487
|
return where;
|
|
@@ -474,6 +498,12 @@ function ownerId(owner, ownerKey) {
|
|
|
474
498
|
function thenGet(get, onfulfilled, onrejected) {
|
|
475
499
|
return get().then(onfulfilled ?? undefined, onrejected ?? undefined);
|
|
476
500
|
}
|
|
501
|
+
function pluckFromQuery(query, column, keyBy) {
|
|
502
|
+
if (!query) {
|
|
503
|
+
return Promise.resolve(keyBy === undefined ? [] : new Map);
|
|
504
|
+
}
|
|
505
|
+
return keyBy === undefined ? query.pluck(column) : query.pluck(column, keyBy);
|
|
506
|
+
}
|
|
477
507
|
|
|
478
508
|
class HasManyRelationQuery {
|
|
479
509
|
parent;
|
|
@@ -539,6 +569,12 @@ class HasManyRelationQuery {
|
|
|
539
569
|
async count() {
|
|
540
570
|
return this.scopedQuery().count();
|
|
541
571
|
}
|
|
572
|
+
async pluck(column, keyBy) {
|
|
573
|
+
return pluckFromQuery(this.scopedQuery(), column, keyBy);
|
|
574
|
+
}
|
|
575
|
+
async value(column) {
|
|
576
|
+
return this.scopedQuery().value(column);
|
|
577
|
+
}
|
|
542
578
|
then(onfulfilled, onrejected) {
|
|
543
579
|
return thenGet(() => this.get(), onfulfilled, onrejected);
|
|
544
580
|
}
|
|
@@ -604,6 +640,13 @@ class HasOneRelationQuery {
|
|
|
604
640
|
async count() {
|
|
605
641
|
return this.inner.count();
|
|
606
642
|
}
|
|
643
|
+
async pluck(column, keyBy) {
|
|
644
|
+
const query = this.inner.limit(1);
|
|
645
|
+
return keyBy === undefined ? query.pluck(column) : query.pluck(column, keyBy);
|
|
646
|
+
}
|
|
647
|
+
async value(column) {
|
|
648
|
+
return this.inner.limit(1).value(column);
|
|
649
|
+
}
|
|
607
650
|
then(onfulfilled, onrejected) {
|
|
608
651
|
return thenGet(() => this.get(), onfulfilled, onrejected);
|
|
609
652
|
}
|
|
@@ -650,6 +693,23 @@ class BelongsToRelationQuery {
|
|
|
650
693
|
return { sql, params: extra.params };
|
|
651
694
|
}
|
|
652
695
|
async get() {
|
|
696
|
+
const query = this.relatedQuery();
|
|
697
|
+
if (!query) {
|
|
698
|
+
return null;
|
|
699
|
+
}
|
|
700
|
+
const row = await query.first();
|
|
701
|
+
return row ? this.related.newFromRecord(row) : null;
|
|
702
|
+
}
|
|
703
|
+
async first() {
|
|
704
|
+
return this.get();
|
|
705
|
+
}
|
|
706
|
+
async pluck(column, keyBy) {
|
|
707
|
+
return pluckFromQuery(this.relatedQuery(), column, keyBy);
|
|
708
|
+
}
|
|
709
|
+
async value(column) {
|
|
710
|
+
return this.relatedQuery()?.value(column) ?? null;
|
|
711
|
+
}
|
|
712
|
+
relatedQuery() {
|
|
653
713
|
const foreign = this.parent.get(this.relation.foreignKey);
|
|
654
714
|
if (foreign === null || foreign === undefined) {
|
|
655
715
|
return null;
|
|
@@ -659,11 +719,7 @@ class BelongsToRelationQuery {
|
|
|
659
719
|
if (this.extraOptions.orderBy) {
|
|
660
720
|
query = query.orderBy(this.extraOptions.orderBy);
|
|
661
721
|
}
|
|
662
|
-
|
|
663
|
-
return row ? this.related.newFromRecord(row) : null;
|
|
664
|
-
}
|
|
665
|
-
async first() {
|
|
666
|
-
return this.get();
|
|
722
|
+
return query;
|
|
667
723
|
}
|
|
668
724
|
then(onfulfilled, onrejected) {
|
|
669
725
|
return thenGet(() => this.get(), onfulfilled, onrejected);
|
|
@@ -751,6 +807,31 @@ class BelongsToManyRelationQuery {
|
|
|
751
807
|
const rows = await this.connection().unsafe(`SELECT COUNT(*) AS count FROM ${this.relation.pivotTable} WHERE ${String(this.relation.foreignPivotKey)} = $1`, [parentId]);
|
|
752
808
|
return Number(rows[0]?.count ?? 0);
|
|
753
809
|
}
|
|
810
|
+
async pluck(column, keyBy) {
|
|
811
|
+
return pluckFromQuery(await this.relatedQuery(), column, keyBy);
|
|
812
|
+
}
|
|
813
|
+
async value(column) {
|
|
814
|
+
const query = await this.relatedQuery();
|
|
815
|
+
return query ? query.value(column) : null;
|
|
816
|
+
}
|
|
817
|
+
async relatedQuery() {
|
|
818
|
+
const parentId = this.parent.get(this.relation.parentKey);
|
|
819
|
+
const pivotRows = await this.connection().unsafe(`SELECT * FROM ${this.relation.pivotTable} WHERE ${String(this.relation.foreignPivotKey)} = $1`, [parentId]);
|
|
820
|
+
if (pivotRows.length === 0) {
|
|
821
|
+
return null;
|
|
822
|
+
}
|
|
823
|
+
const relatedIds = [
|
|
824
|
+
...new Set(pivotRows.map((row) => row[this.relation.relatedPivotKey]))
|
|
825
|
+
];
|
|
826
|
+
let query = this.related.repository().withConnection(this.connection()).query(asWhere({
|
|
827
|
+
[this.relation.relatedKey]: relatedIds,
|
|
828
|
+
...this.extraWhere
|
|
829
|
+
}));
|
|
830
|
+
if (this.extraOptions.orderBy) {
|
|
831
|
+
query = query.orderBy(this.extraOptions.orderBy);
|
|
832
|
+
}
|
|
833
|
+
return query;
|
|
834
|
+
}
|
|
754
835
|
then(onfulfilled, onrejected) {
|
|
755
836
|
return thenGet(() => this.get(), onfulfilled, onrejected);
|
|
756
837
|
}
|
|
@@ -834,13 +915,15 @@ class MorphManyRelationQuery {
|
|
|
834
915
|
const sql = `SELECT 1 FROM ${quoteIdentifier(childTable)} WHERE ${qualifyColumn(childTable, this.relation.morphIdKey)} = ${qualifyColumn(parentTable, this.relation.localKey)}${extraSql ? ` AND ${extraSql}` : ""}`;
|
|
835
916
|
return { sql, params: extra.params };
|
|
836
917
|
}
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
const rows = await repository.query(asWhere({
|
|
918
|
+
scopedQuery() {
|
|
919
|
+
return this.related.repository().withConnection(this.parent.getRepository().getConnection()).query(asWhere({
|
|
840
920
|
[this.relation.morphTypeKey]: this.relation.morphType,
|
|
841
921
|
[this.relation.morphIdKey]: this.parent.get(this.relation.localKey),
|
|
842
922
|
...this.extraWhere
|
|
843
|
-
}))
|
|
923
|
+
}));
|
|
924
|
+
}
|
|
925
|
+
async get() {
|
|
926
|
+
const rows = await this.scopedQuery().get();
|
|
844
927
|
return rows.map((row) => this.related.newFromRecord(row));
|
|
845
928
|
}
|
|
846
929
|
async first() {
|
|
@@ -848,12 +931,13 @@ class MorphManyRelationQuery {
|
|
|
848
931
|
return rows[0] ?? null;
|
|
849
932
|
}
|
|
850
933
|
async count() {
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
934
|
+
return this.scopedQuery().count();
|
|
935
|
+
}
|
|
936
|
+
async pluck(column, keyBy) {
|
|
937
|
+
return pluckFromQuery(this.scopedQuery(), column, keyBy);
|
|
938
|
+
}
|
|
939
|
+
async value(column) {
|
|
940
|
+
return this.scopedQuery().value(column);
|
|
857
941
|
}
|
|
858
942
|
then(onfulfilled, onrejected) {
|
|
859
943
|
return thenGet(() => this.get(), onfulfilled, onrejected);
|
|
@@ -904,6 +988,12 @@ class MorphOneRelationQuery {
|
|
|
904
988
|
async count() {
|
|
905
989
|
return this.inner.count();
|
|
906
990
|
}
|
|
991
|
+
async pluck(column, keyBy) {
|
|
992
|
+
return keyBy === undefined ? this.inner.pluck(column) : this.inner.pluck(column, keyBy);
|
|
993
|
+
}
|
|
994
|
+
async value(column) {
|
|
995
|
+
return this.inner.value(column);
|
|
996
|
+
}
|
|
907
997
|
then(onfulfilled, onrejected) {
|
|
908
998
|
return thenGet(() => this.get(), onfulfilled, onrejected);
|
|
909
999
|
}
|
|
@@ -952,15 +1042,31 @@ class MorphToRelationQuery {
|
|
|
952
1042
|
};
|
|
953
1043
|
}
|
|
954
1044
|
async get() {
|
|
1045
|
+
const query = this.relatedQuery();
|
|
1046
|
+
if (!query) {
|
|
1047
|
+
return null;
|
|
1048
|
+
}
|
|
1049
|
+
const row = await query.first();
|
|
1050
|
+
return row ? this.relatedForCurrentType()?.newFromRecord(row) ?? null : null;
|
|
1051
|
+
}
|
|
1052
|
+
async pluck(column, keyBy) {
|
|
1053
|
+
return pluckFromQuery(this.relatedQuery(), column, keyBy);
|
|
1054
|
+
}
|
|
1055
|
+
async value(column) {
|
|
1056
|
+
return this.relatedQuery()?.value(column) ?? null;
|
|
1057
|
+
}
|
|
1058
|
+
relatedForCurrentType() {
|
|
955
1059
|
const type = String(this.parent.get(this.relation.morphTypeKey) ?? "");
|
|
1060
|
+
return this.relatedByType[type];
|
|
1061
|
+
}
|
|
1062
|
+
relatedQuery() {
|
|
956
1063
|
const id = this.parent.get(this.relation.morphIdKey);
|
|
957
|
-
const related = this.
|
|
1064
|
+
const related = this.relatedForCurrentType();
|
|
958
1065
|
if (!related || id === null || id === undefined) {
|
|
959
1066
|
return null;
|
|
960
1067
|
}
|
|
961
1068
|
const table = related.repository().getTable();
|
|
962
|
-
|
|
963
|
-
return row ? related.newFromRecord(row) : null;
|
|
1069
|
+
return related.repository().withConnection(this.parent.getRepository().getConnection()).query(asWhere({ [table.primaryKey]: id, ...this.extraWhere }));
|
|
964
1070
|
}
|
|
965
1071
|
then(onfulfilled, onrejected) {
|
|
966
1072
|
return thenGet(() => this.get(), onfulfilled, onrejected);
|
|
@@ -1007,10 +1113,7 @@ class HasManyThroughRelationQuery {
|
|
|
1007
1113
|
return { sql, params: extra.params };
|
|
1008
1114
|
}
|
|
1009
1115
|
async get() {
|
|
1010
|
-
const rows = await this.
|
|
1011
|
-
...this.extraOptions,
|
|
1012
|
-
where: this.extraWhere
|
|
1013
|
-
});
|
|
1116
|
+
const rows = await this.farRows();
|
|
1014
1117
|
return rows.map((row) => this.related.newFromRecord(row));
|
|
1015
1118
|
}
|
|
1016
1119
|
async first() {
|
|
@@ -1021,6 +1124,20 @@ class HasManyThroughRelationQuery {
|
|
|
1021
1124
|
const rows = await this.get();
|
|
1022
1125
|
return rows.length;
|
|
1023
1126
|
}
|
|
1127
|
+
async pluck(column, keyBy) {
|
|
1128
|
+
const rows = await this.farRows();
|
|
1129
|
+
return keyBy === undefined ? projectPluck(rows, column) : projectPluck(rows, column, keyBy);
|
|
1130
|
+
}
|
|
1131
|
+
async value(column) {
|
|
1132
|
+
const values = await this.limit(1).pluck(column);
|
|
1133
|
+
return values[0] ?? null;
|
|
1134
|
+
}
|
|
1135
|
+
async farRows() {
|
|
1136
|
+
return this.related.repository().withConnection(this.parent.getRepository().getConnection()).findHasManyThrough(this.parent.get(this.relation.localKey), this.relation, {
|
|
1137
|
+
...this.extraOptions,
|
|
1138
|
+
where: this.extraWhere
|
|
1139
|
+
});
|
|
1140
|
+
}
|
|
1024
1141
|
then(onfulfilled, onrejected) {
|
|
1025
1142
|
return thenGet(() => this.get(), onfulfilled, onrejected);
|
|
1026
1143
|
}
|
|
@@ -1476,6 +1593,10 @@ function applyCasts(values, casts, direction) {
|
|
|
1476
1593
|
}
|
|
1477
1594
|
return result;
|
|
1478
1595
|
}
|
|
1596
|
+
function castPluckedValue(modelClass, column, value) {
|
|
1597
|
+
const cast = modelStatics(modelClass).$casts?.[column];
|
|
1598
|
+
return cast ? hydrateValue(value, cast) : value;
|
|
1599
|
+
}
|
|
1479
1600
|
function applyTimestampsOnCreate(columns, values, enabled) {
|
|
1480
1601
|
if (!enabled) {
|
|
1481
1602
|
return values;
|
|
@@ -1630,6 +1751,25 @@ class ModelQuery {
|
|
|
1630
1751
|
const models = await this.get();
|
|
1631
1752
|
return models[0] ?? null;
|
|
1632
1753
|
}
|
|
1754
|
+
async count() {
|
|
1755
|
+
return this.query.count();
|
|
1756
|
+
}
|
|
1757
|
+
async pluck(column, keyBy) {
|
|
1758
|
+
if (keyBy === undefined) {
|
|
1759
|
+
const values = await this.query.pluck(column);
|
|
1760
|
+
return values.map((value) => castPluckedValue(this.modelClass, column, value));
|
|
1761
|
+
}
|
|
1762
|
+
const keyed = await this.query.pluck(column, keyBy);
|
|
1763
|
+
const result = new Map;
|
|
1764
|
+
for (const [key, value] of keyed) {
|
|
1765
|
+
result.set(castPluckedValue(this.modelClass, keyBy, key), castPluckedValue(this.modelClass, column, value));
|
|
1766
|
+
}
|
|
1767
|
+
return result;
|
|
1768
|
+
}
|
|
1769
|
+
async value(column) {
|
|
1770
|
+
const value = await this.query.value(column);
|
|
1771
|
+
return castPluckedValue(this.modelClass, column, value);
|
|
1772
|
+
}
|
|
1633
1773
|
async find(id) {
|
|
1634
1774
|
const primaryKey = resolveModelRepository(this.modelClass).getTable().primaryKey;
|
|
1635
1775
|
return this.where({ [primaryKey]: id }).first();
|
|
@@ -1877,6 +2017,16 @@ class Model {
|
|
|
1877
2017
|
static where(where) {
|
|
1878
2018
|
return Model.query.call(this).where(where);
|
|
1879
2019
|
}
|
|
2020
|
+
static async count() {
|
|
2021
|
+
return Model.query.call(this).count();
|
|
2022
|
+
}
|
|
2023
|
+
static pluck(column, keyBy) {
|
|
2024
|
+
const query = Model.query.call(this);
|
|
2025
|
+
return keyBy === undefined ? query.pluck(column) : query.pluck(column, keyBy);
|
|
2026
|
+
}
|
|
2027
|
+
static value(column) {
|
|
2028
|
+
return Model.query.call(this).value(column);
|
|
2029
|
+
}
|
|
1880
2030
|
static async firstWhere(where, options = {}) {
|
|
1881
2031
|
let query = Model.query.call(this).where(where);
|
|
1882
2032
|
if (options.orderBy) {
|
|
@@ -1,4 +1,28 @@
|
|
|
1
1
|
// @bun
|
|
2
|
+
// ../../src/core/database/pluck.ts
|
|
3
|
+
function uniqueColumnSelect(table, columns) {
|
|
4
|
+
const seen = new Set;
|
|
5
|
+
const select = [];
|
|
6
|
+
for (const column of columns) {
|
|
7
|
+
if (seen.has(column)) {
|
|
8
|
+
continue;
|
|
9
|
+
}
|
|
10
|
+
seen.add(column);
|
|
11
|
+
select.push({ kind: "column", table, column, as: column });
|
|
12
|
+
}
|
|
13
|
+
return select;
|
|
14
|
+
}
|
|
15
|
+
function projectPluck(rows, column, keyBy) {
|
|
16
|
+
if (keyBy === undefined) {
|
|
17
|
+
return rows.map((row) => row[column]);
|
|
18
|
+
}
|
|
19
|
+
const keyed = new Map;
|
|
20
|
+
for (const row of rows) {
|
|
21
|
+
keyed.set(row[keyBy], row[column]);
|
|
22
|
+
}
|
|
23
|
+
return keyed;
|
|
24
|
+
}
|
|
25
|
+
|
|
2
26
|
// ../../src/core/database/query.ts
|
|
3
27
|
import { currentSqlDialect } from "@getstrata/core/database/dialect";
|
|
4
28
|
function quoteIdentifier(identifier) {
|
|
@@ -875,6 +899,28 @@ class RepositoryQuery {
|
|
|
875
899
|
async count() {
|
|
876
900
|
return await this.repository.count(this.buildOptions());
|
|
877
901
|
}
|
|
902
|
+
async pluck(column, keyBy) {
|
|
903
|
+
const rows = await this.repository.findAll({
|
|
904
|
+
...this.buildOptions(),
|
|
905
|
+
select: uniqueColumnSelect(this.repository.getTable().name, keyBy === undefined || keyBy === column ? [column] : [column, keyBy])
|
|
906
|
+
});
|
|
907
|
+
if (keyBy === undefined) {
|
|
908
|
+
return projectPluck(rows, column);
|
|
909
|
+
}
|
|
910
|
+
return projectPluck(rows, column, keyBy);
|
|
911
|
+
}
|
|
912
|
+
async value(column) {
|
|
913
|
+
const rows = await this.repository.findAll({
|
|
914
|
+
...this.buildOptions(),
|
|
915
|
+
select: uniqueColumnSelect(this.repository.getTable().name, [column]),
|
|
916
|
+
limit: 1
|
|
917
|
+
});
|
|
918
|
+
const row = rows[0];
|
|
919
|
+
if (row === undefined) {
|
|
920
|
+
return null;
|
|
921
|
+
}
|
|
922
|
+
return row[column];
|
|
923
|
+
}
|
|
878
924
|
async attachToRows(rows) {
|
|
879
925
|
return await this.attach(rows);
|
|
880
926
|
}
|
|
@@ -980,5 +1026,7 @@ class RepositoryQuery {
|
|
|
980
1026
|
}
|
|
981
1027
|
}
|
|
982
1028
|
export {
|
|
983
|
-
RepositoryQuery
|
|
1029
|
+
RepositoryQuery,
|
|
1030
|
+
projectPluck,
|
|
1031
|
+
uniqueColumnSelect
|
|
984
1032
|
};
|
|
@@ -52,7 +52,7 @@ export { createDatabaseQueryProxy } from "../core/database/queryProxy.ts";
|
|
|
52
52
|
export type { BelongsToManyRelation, BelongsToRelation, HasManyRelation, HasManyThroughRelation, HasOneRelation, MorphManyRelation, MorphOneRelation, MorphToRelation, } from "../core/database/relationships.ts";
|
|
53
53
|
export { belongsTo, belongsToMany, hasMany, hasManyThrough, hasOne, indexBelongsToManyRelation, indexBelongsToRelation, indexHasManyRelation, indexHasManyThroughRelation, indexHasOneRelation, indexMorphManyRelation, indexMorphOneRelation, indexMorphToRelation, morphMany, morphOne, morphTo, } from "../core/database/relationships.ts";
|
|
54
54
|
export { repositoryConnection, resolveRepositoryConnection, } from "../core/database/repositoryConnection.ts";
|
|
55
|
-
export { RepositoryQuery } from "../core/database/repositoryQuery.ts";
|
|
55
|
+
export { projectPluck, RepositoryQuery, uniqueColumnSelect, } from "../core/database/repositoryQuery.ts";
|
|
56
56
|
export type { BlueprintAction, BlueprintCallback, ColumnKind, DatabaseDriver, ForeignKeyOptions, Grammar, IndexDefinition, IndexKind, ResolveDatabaseDriverOptions, SchemaBuilder, } from "../core/database/schema/index.ts";
|
|
57
57
|
export { Blueprint, ColumnDefinition, compileBlueprint, createSchemaBuilder, ForeignIdColumnDefinition, grammarForDriver, inferReferencedTable, MySqlGrammar, PostgresGrammar, resolveDatabaseDriver, Schema, SqliteGrammar, UnsupportedSchemaFeatureError, } from "../core/database/schema/index.ts";
|
|
58
58
|
export { loadSeedersFromDirectory, runSeedersFromDirectory, } from "../core/database/seeders/runner.ts";
|
package/dist/index.js
CHANGED
|
@@ -2857,6 +2857,30 @@ function indexMorphToRelation(children, parentsByType, relation) {
|
|
|
2857
2857
|
return result;
|
|
2858
2858
|
}
|
|
2859
2859
|
|
|
2860
|
+
// ../../src/core/database/pluck.ts
|
|
2861
|
+
function uniqueColumnSelect(table, columns) {
|
|
2862
|
+
const seen = new Set;
|
|
2863
|
+
const select = [];
|
|
2864
|
+
for (const column of columns) {
|
|
2865
|
+
if (seen.has(column)) {
|
|
2866
|
+
continue;
|
|
2867
|
+
}
|
|
2868
|
+
seen.add(column);
|
|
2869
|
+
select.push({ kind: "column", table, column, as: column });
|
|
2870
|
+
}
|
|
2871
|
+
return select;
|
|
2872
|
+
}
|
|
2873
|
+
function projectPluck(rows, column, keyBy) {
|
|
2874
|
+
if (keyBy === undefined) {
|
|
2875
|
+
return rows.map((row) => row[column]);
|
|
2876
|
+
}
|
|
2877
|
+
const keyed = new Map;
|
|
2878
|
+
for (const row of rows) {
|
|
2879
|
+
keyed.set(row[keyBy], row[column]);
|
|
2880
|
+
}
|
|
2881
|
+
return keyed;
|
|
2882
|
+
}
|
|
2883
|
+
|
|
2860
2884
|
// ../../src/core/database/whereBuilder.ts
|
|
2861
2885
|
class WhereBuilder {
|
|
2862
2886
|
nodes = [];
|
|
@@ -3054,6 +3078,28 @@ class RepositoryQuery {
|
|
|
3054
3078
|
async count() {
|
|
3055
3079
|
return await this.repository.count(this.buildOptions());
|
|
3056
3080
|
}
|
|
3081
|
+
async pluck(column, keyBy) {
|
|
3082
|
+
const rows = await this.repository.findAll({
|
|
3083
|
+
...this.buildOptions(),
|
|
3084
|
+
select: uniqueColumnSelect(this.repository.getTable().name, keyBy === undefined || keyBy === column ? [column] : [column, keyBy])
|
|
3085
|
+
});
|
|
3086
|
+
if (keyBy === undefined) {
|
|
3087
|
+
return projectPluck(rows, column);
|
|
3088
|
+
}
|
|
3089
|
+
return projectPluck(rows, column, keyBy);
|
|
3090
|
+
}
|
|
3091
|
+
async value(column) {
|
|
3092
|
+
const rows = await this.repository.findAll({
|
|
3093
|
+
...this.buildOptions(),
|
|
3094
|
+
select: uniqueColumnSelect(this.repository.getTable().name, [column]),
|
|
3095
|
+
limit: 1
|
|
3096
|
+
});
|
|
3097
|
+
const row = rows[0];
|
|
3098
|
+
if (row === undefined) {
|
|
3099
|
+
return null;
|
|
3100
|
+
}
|
|
3101
|
+
return row[column];
|
|
3102
|
+
}
|
|
3057
3103
|
async attachToRows(rows) {
|
|
3058
3104
|
return await this.attach(rows);
|
|
3059
3105
|
}
|
|
@@ -3882,6 +3928,12 @@ function ownerId(owner, ownerKey) {
|
|
|
3882
3928
|
function thenGet(get, onfulfilled, onrejected) {
|
|
3883
3929
|
return get().then(onfulfilled ?? undefined, onrejected ?? undefined);
|
|
3884
3930
|
}
|
|
3931
|
+
function pluckFromQuery(query, column, keyBy) {
|
|
3932
|
+
if (!query) {
|
|
3933
|
+
return Promise.resolve(keyBy === undefined ? [] : new Map);
|
|
3934
|
+
}
|
|
3935
|
+
return keyBy === undefined ? query.pluck(column) : query.pluck(column, keyBy);
|
|
3936
|
+
}
|
|
3885
3937
|
|
|
3886
3938
|
class HasManyRelationQuery {
|
|
3887
3939
|
parent;
|
|
@@ -3947,6 +3999,12 @@ class HasManyRelationQuery {
|
|
|
3947
3999
|
async count() {
|
|
3948
4000
|
return this.scopedQuery().count();
|
|
3949
4001
|
}
|
|
4002
|
+
async pluck(column, keyBy) {
|
|
4003
|
+
return pluckFromQuery(this.scopedQuery(), column, keyBy);
|
|
4004
|
+
}
|
|
4005
|
+
async value(column) {
|
|
4006
|
+
return this.scopedQuery().value(column);
|
|
4007
|
+
}
|
|
3950
4008
|
then(onfulfilled, onrejected) {
|
|
3951
4009
|
return thenGet(() => this.get(), onfulfilled, onrejected);
|
|
3952
4010
|
}
|
|
@@ -4012,6 +4070,13 @@ class HasOneRelationQuery {
|
|
|
4012
4070
|
async count() {
|
|
4013
4071
|
return this.inner.count();
|
|
4014
4072
|
}
|
|
4073
|
+
async pluck(column, keyBy) {
|
|
4074
|
+
const query = this.inner.limit(1);
|
|
4075
|
+
return keyBy === undefined ? query.pluck(column) : query.pluck(column, keyBy);
|
|
4076
|
+
}
|
|
4077
|
+
async value(column) {
|
|
4078
|
+
return this.inner.limit(1).value(column);
|
|
4079
|
+
}
|
|
4015
4080
|
then(onfulfilled, onrejected) {
|
|
4016
4081
|
return thenGet(() => this.get(), onfulfilled, onrejected);
|
|
4017
4082
|
}
|
|
@@ -4058,6 +4123,23 @@ class BelongsToRelationQuery {
|
|
|
4058
4123
|
return { sql, params: extra.params };
|
|
4059
4124
|
}
|
|
4060
4125
|
async get() {
|
|
4126
|
+
const query = this.relatedQuery();
|
|
4127
|
+
if (!query) {
|
|
4128
|
+
return null;
|
|
4129
|
+
}
|
|
4130
|
+
const row = await query.first();
|
|
4131
|
+
return row ? this.related.newFromRecord(row) : null;
|
|
4132
|
+
}
|
|
4133
|
+
async first() {
|
|
4134
|
+
return this.get();
|
|
4135
|
+
}
|
|
4136
|
+
async pluck(column, keyBy) {
|
|
4137
|
+
return pluckFromQuery(this.relatedQuery(), column, keyBy);
|
|
4138
|
+
}
|
|
4139
|
+
async value(column) {
|
|
4140
|
+
return this.relatedQuery()?.value(column) ?? null;
|
|
4141
|
+
}
|
|
4142
|
+
relatedQuery() {
|
|
4061
4143
|
const foreign = this.parent.get(this.relation.foreignKey);
|
|
4062
4144
|
if (foreign === null || foreign === undefined) {
|
|
4063
4145
|
return null;
|
|
@@ -4067,11 +4149,7 @@ class BelongsToRelationQuery {
|
|
|
4067
4149
|
if (this.extraOptions.orderBy) {
|
|
4068
4150
|
query = query.orderBy(this.extraOptions.orderBy);
|
|
4069
4151
|
}
|
|
4070
|
-
|
|
4071
|
-
return row ? this.related.newFromRecord(row) : null;
|
|
4072
|
-
}
|
|
4073
|
-
async first() {
|
|
4074
|
-
return this.get();
|
|
4152
|
+
return query;
|
|
4075
4153
|
}
|
|
4076
4154
|
then(onfulfilled, onrejected) {
|
|
4077
4155
|
return thenGet(() => this.get(), onfulfilled, onrejected);
|
|
@@ -4159,6 +4237,31 @@ class BelongsToManyRelationQuery {
|
|
|
4159
4237
|
const rows = await this.connection().unsafe(`SELECT COUNT(*) AS count FROM ${this.relation.pivotTable} WHERE ${String(this.relation.foreignPivotKey)} = $1`, [parentId]);
|
|
4160
4238
|
return Number(rows[0]?.count ?? 0);
|
|
4161
4239
|
}
|
|
4240
|
+
async pluck(column, keyBy) {
|
|
4241
|
+
return pluckFromQuery(await this.relatedQuery(), column, keyBy);
|
|
4242
|
+
}
|
|
4243
|
+
async value(column) {
|
|
4244
|
+
const query = await this.relatedQuery();
|
|
4245
|
+
return query ? query.value(column) : null;
|
|
4246
|
+
}
|
|
4247
|
+
async relatedQuery() {
|
|
4248
|
+
const parentId = this.parent.get(this.relation.parentKey);
|
|
4249
|
+
const pivotRows = await this.connection().unsafe(`SELECT * FROM ${this.relation.pivotTable} WHERE ${String(this.relation.foreignPivotKey)} = $1`, [parentId]);
|
|
4250
|
+
if (pivotRows.length === 0) {
|
|
4251
|
+
return null;
|
|
4252
|
+
}
|
|
4253
|
+
const relatedIds = [
|
|
4254
|
+
...new Set(pivotRows.map((row) => row[this.relation.relatedPivotKey]))
|
|
4255
|
+
];
|
|
4256
|
+
let query = this.related.repository().withConnection(this.connection()).query(asWhere({
|
|
4257
|
+
[this.relation.relatedKey]: relatedIds,
|
|
4258
|
+
...this.extraWhere
|
|
4259
|
+
}));
|
|
4260
|
+
if (this.extraOptions.orderBy) {
|
|
4261
|
+
query = query.orderBy(this.extraOptions.orderBy);
|
|
4262
|
+
}
|
|
4263
|
+
return query;
|
|
4264
|
+
}
|
|
4162
4265
|
then(onfulfilled, onrejected) {
|
|
4163
4266
|
return thenGet(() => this.get(), onfulfilled, onrejected);
|
|
4164
4267
|
}
|
|
@@ -4242,13 +4345,15 @@ class MorphManyRelationQuery {
|
|
|
4242
4345
|
const sql = `SELECT 1 FROM ${quoteIdentifier(childTable)} WHERE ${qualifyColumn(childTable, this.relation.morphIdKey)} = ${qualifyColumn(parentTable, this.relation.localKey)}${extraSql ? ` AND ${extraSql}` : ""}`;
|
|
4243
4346
|
return { sql, params: extra.params };
|
|
4244
4347
|
}
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
const rows = await repository.query(asWhere({
|
|
4348
|
+
scopedQuery() {
|
|
4349
|
+
return this.related.repository().withConnection(this.parent.getRepository().getConnection()).query(asWhere({
|
|
4248
4350
|
[this.relation.morphTypeKey]: this.relation.morphType,
|
|
4249
4351
|
[this.relation.morphIdKey]: this.parent.get(this.relation.localKey),
|
|
4250
4352
|
...this.extraWhere
|
|
4251
|
-
}))
|
|
4353
|
+
}));
|
|
4354
|
+
}
|
|
4355
|
+
async get() {
|
|
4356
|
+
const rows = await this.scopedQuery().get();
|
|
4252
4357
|
return rows.map((row) => this.related.newFromRecord(row));
|
|
4253
4358
|
}
|
|
4254
4359
|
async first() {
|
|
@@ -4256,12 +4361,13 @@ class MorphManyRelationQuery {
|
|
|
4256
4361
|
return rows[0] ?? null;
|
|
4257
4362
|
}
|
|
4258
4363
|
async count() {
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4364
|
+
return this.scopedQuery().count();
|
|
4365
|
+
}
|
|
4366
|
+
async pluck(column, keyBy) {
|
|
4367
|
+
return pluckFromQuery(this.scopedQuery(), column, keyBy);
|
|
4368
|
+
}
|
|
4369
|
+
async value(column) {
|
|
4370
|
+
return this.scopedQuery().value(column);
|
|
4265
4371
|
}
|
|
4266
4372
|
then(onfulfilled, onrejected) {
|
|
4267
4373
|
return thenGet(() => this.get(), onfulfilled, onrejected);
|
|
@@ -4312,6 +4418,12 @@ class MorphOneRelationQuery {
|
|
|
4312
4418
|
async count() {
|
|
4313
4419
|
return this.inner.count();
|
|
4314
4420
|
}
|
|
4421
|
+
async pluck(column, keyBy) {
|
|
4422
|
+
return keyBy === undefined ? this.inner.pluck(column) : this.inner.pluck(column, keyBy);
|
|
4423
|
+
}
|
|
4424
|
+
async value(column) {
|
|
4425
|
+
return this.inner.value(column);
|
|
4426
|
+
}
|
|
4315
4427
|
then(onfulfilled, onrejected) {
|
|
4316
4428
|
return thenGet(() => this.get(), onfulfilled, onrejected);
|
|
4317
4429
|
}
|
|
@@ -4360,15 +4472,31 @@ class MorphToRelationQuery {
|
|
|
4360
4472
|
};
|
|
4361
4473
|
}
|
|
4362
4474
|
async get() {
|
|
4475
|
+
const query = this.relatedQuery();
|
|
4476
|
+
if (!query) {
|
|
4477
|
+
return null;
|
|
4478
|
+
}
|
|
4479
|
+
const row = await query.first();
|
|
4480
|
+
return row ? this.relatedForCurrentType()?.newFromRecord(row) ?? null : null;
|
|
4481
|
+
}
|
|
4482
|
+
async pluck(column, keyBy) {
|
|
4483
|
+
return pluckFromQuery(this.relatedQuery(), column, keyBy);
|
|
4484
|
+
}
|
|
4485
|
+
async value(column) {
|
|
4486
|
+
return this.relatedQuery()?.value(column) ?? null;
|
|
4487
|
+
}
|
|
4488
|
+
relatedForCurrentType() {
|
|
4363
4489
|
const type = String(this.parent.get(this.relation.morphTypeKey) ?? "");
|
|
4490
|
+
return this.relatedByType[type];
|
|
4491
|
+
}
|
|
4492
|
+
relatedQuery() {
|
|
4364
4493
|
const id = this.parent.get(this.relation.morphIdKey);
|
|
4365
|
-
const related = this.
|
|
4494
|
+
const related = this.relatedForCurrentType();
|
|
4366
4495
|
if (!related || id === null || id === undefined) {
|
|
4367
4496
|
return null;
|
|
4368
4497
|
}
|
|
4369
4498
|
const table = related.repository().getTable();
|
|
4370
|
-
|
|
4371
|
-
return row ? related.newFromRecord(row) : null;
|
|
4499
|
+
return related.repository().withConnection(this.parent.getRepository().getConnection()).query(asWhere({ [table.primaryKey]: id, ...this.extraWhere }));
|
|
4372
4500
|
}
|
|
4373
4501
|
then(onfulfilled, onrejected) {
|
|
4374
4502
|
return thenGet(() => this.get(), onfulfilled, onrejected);
|
|
@@ -4415,10 +4543,7 @@ class HasManyThroughRelationQuery {
|
|
|
4415
4543
|
return { sql, params: extra.params };
|
|
4416
4544
|
}
|
|
4417
4545
|
async get() {
|
|
4418
|
-
const rows = await this.
|
|
4419
|
-
...this.extraOptions,
|
|
4420
|
-
where: this.extraWhere
|
|
4421
|
-
});
|
|
4546
|
+
const rows = await this.farRows();
|
|
4422
4547
|
return rows.map((row) => this.related.newFromRecord(row));
|
|
4423
4548
|
}
|
|
4424
4549
|
async first() {
|
|
@@ -4429,6 +4554,20 @@ class HasManyThroughRelationQuery {
|
|
|
4429
4554
|
const rows = await this.get();
|
|
4430
4555
|
return rows.length;
|
|
4431
4556
|
}
|
|
4557
|
+
async pluck(column, keyBy) {
|
|
4558
|
+
const rows = await this.farRows();
|
|
4559
|
+
return keyBy === undefined ? projectPluck(rows, column) : projectPluck(rows, column, keyBy);
|
|
4560
|
+
}
|
|
4561
|
+
async value(column) {
|
|
4562
|
+
const values = await this.limit(1).pluck(column);
|
|
4563
|
+
return values[0] ?? null;
|
|
4564
|
+
}
|
|
4565
|
+
async farRows() {
|
|
4566
|
+
return this.related.repository().withConnection(this.parent.getRepository().getConnection()).findHasManyThrough(this.parent.get(this.relation.localKey), this.relation, {
|
|
4567
|
+
...this.extraOptions,
|
|
4568
|
+
where: this.extraWhere
|
|
4569
|
+
});
|
|
4570
|
+
}
|
|
4432
4571
|
then(onfulfilled, onrejected) {
|
|
4433
4572
|
return thenGet(() => this.get(), onfulfilled, onrejected);
|
|
4434
4573
|
}
|
|
@@ -4641,6 +4780,10 @@ function applyCasts(values, casts, direction) {
|
|
|
4641
4780
|
}
|
|
4642
4781
|
return result;
|
|
4643
4782
|
}
|
|
4783
|
+
function castPluckedValue(modelClass, column, value) {
|
|
4784
|
+
const cast = modelStatics(modelClass).$casts?.[column];
|
|
4785
|
+
return cast ? hydrateValue(value, cast) : value;
|
|
4786
|
+
}
|
|
4644
4787
|
function applyTimestampsOnCreate(columns, values, enabled) {
|
|
4645
4788
|
if (!enabled) {
|
|
4646
4789
|
return values;
|
|
@@ -4795,6 +4938,25 @@ class ModelQuery {
|
|
|
4795
4938
|
const models = await this.get();
|
|
4796
4939
|
return models[0] ?? null;
|
|
4797
4940
|
}
|
|
4941
|
+
async count() {
|
|
4942
|
+
return this.query.count();
|
|
4943
|
+
}
|
|
4944
|
+
async pluck(column, keyBy) {
|
|
4945
|
+
if (keyBy === undefined) {
|
|
4946
|
+
const values = await this.query.pluck(column);
|
|
4947
|
+
return values.map((value) => castPluckedValue(this.modelClass, column, value));
|
|
4948
|
+
}
|
|
4949
|
+
const keyed = await this.query.pluck(column, keyBy);
|
|
4950
|
+
const result = new Map;
|
|
4951
|
+
for (const [key, value] of keyed) {
|
|
4952
|
+
result.set(castPluckedValue(this.modelClass, keyBy, key), castPluckedValue(this.modelClass, column, value));
|
|
4953
|
+
}
|
|
4954
|
+
return result;
|
|
4955
|
+
}
|
|
4956
|
+
async value(column) {
|
|
4957
|
+
const value = await this.query.value(column);
|
|
4958
|
+
return castPluckedValue(this.modelClass, column, value);
|
|
4959
|
+
}
|
|
4798
4960
|
async find(id) {
|
|
4799
4961
|
const primaryKey = resolveModelRepository(this.modelClass).getTable().primaryKey;
|
|
4800
4962
|
return this.where({ [primaryKey]: id }).first();
|
|
@@ -5042,6 +5204,16 @@ class Model {
|
|
|
5042
5204
|
static where(where) {
|
|
5043
5205
|
return Model.query.call(this).where(where);
|
|
5044
5206
|
}
|
|
5207
|
+
static async count() {
|
|
5208
|
+
return Model.query.call(this).count();
|
|
5209
|
+
}
|
|
5210
|
+
static pluck(column, keyBy) {
|
|
5211
|
+
const query = Model.query.call(this);
|
|
5212
|
+
return keyBy === undefined ? query.pluck(column) : query.pluck(column, keyBy);
|
|
5213
|
+
}
|
|
5214
|
+
static value(column) {
|
|
5215
|
+
return Model.query.call(this).value(column);
|
|
5216
|
+
}
|
|
5045
5217
|
static async firstWhere(where, options = {}) {
|
|
5046
5218
|
let query = Model.query.call(this).where(where);
|
|
5047
5219
|
if (options.orderBy) {
|
|
@@ -10183,6 +10355,7 @@ export {
|
|
|
10183
10355
|
parseQualifiedColumn,
|
|
10184
10356
|
pivotTableName,
|
|
10185
10357
|
policyGate,
|
|
10358
|
+
projectPluck,
|
|
10186
10359
|
prometheusRegistry,
|
|
10187
10360
|
qualifyColumn,
|
|
10188
10361
|
queue,
|
|
@@ -10300,6 +10473,7 @@ export {
|
|
|
10300
10473
|
toResourceCollection,
|
|
10301
10474
|
traceContextStorage,
|
|
10302
10475
|
trustForwardedFor,
|
|
10476
|
+
uniqueColumnSelect,
|
|
10303
10477
|
unregisterNamedConnection,
|
|
10304
10478
|
useSqlDialect,
|
|
10305
10479
|
validateObject,
|