@getstrata/core 1.0.5 → 1.0.7

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 CHANGED
@@ -1,5 +1,11 @@
1
1
  # @getstrata/core changelog
2
2
 
3
+ ## 1.0.7
4
+
5
+ ## 1.0.6
6
+
7
+ - 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`.
8
+
3
9
  ## 1.0.5
4
10
 
5
11
  - `@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.
@@ -28,6 +28,7 @@ declare class BaseRepository<TEntity extends object, PrimaryKey extends keyof TE
28
28
  perPage: number;
29
29
  } & Omit<ExtendedQueryOptions<TEntity>, "limit" | "offset">): Promise<PaginatedResult<TEntity>>;
30
30
  chunk(count: number, callback: (rows: TEntity[]) => Promise<boolean | void>, options?: Omit<ExtendedQueryOptions<TEntity>, "limit" | "offset">): Promise<void>;
31
+ chunkById(count: number, callback: (rows: TEntity[]) => Promise<boolean | undefined>, options?: Omit<ExtendedQueryOptions<TEntity>, "limit" | "offset" | "orderBy">): Promise<void>;
31
32
  cursorPaginate(options: {
32
33
  perPage: number;
33
34
  cursor?: TEntity[PrimaryKey];
@@ -38,6 +39,9 @@ declare class BaseRepository<TEntity extends object, PrimaryKey extends keyof TE
38
39
  findByIdOrThrow(id: TEntity[PrimaryKey], errorFactory?: ErrorFactory<TEntity[PrimaryKey]>): Promise<TEntity>;
39
40
  findByIds(ids: readonly TEntity[PrimaryKey][]): Promise<TEntity[]>;
40
41
  firstOrNull(where: QueryWhere<TEntity>, options?: Omit<QueryOptions<TEntity>, "where" | "limit">): Promise<TEntity | null>;
42
+ upsert(values: MutationValues<TEntity>, conflictColumns: readonly (keyof TEntity & string)[], updateColumns?: readonly (keyof TEntity & string)[]): Promise<TEntity | null>;
43
+ incrementById(id: TEntity[PrimaryKey], column: keyof TEntity & string, amount?: number, extra?: UpdateValues<TEntity, PrimaryKey>): Promise<TEntity | null>;
44
+ decrementById(id: TEntity[PrimaryKey], column: keyof TEntity & string, amount?: number, extra?: UpdateValues<TEntity, PrimaryKey>): Promise<TEntity | null>;
41
45
  create(values: MutationValues<TEntity>): Promise<TEntity>;
42
46
  updateById(id: TEntity[PrimaryKey], changes: UpdateValues<TEntity, PrimaryKey>): Promise<TEntity | null>;
43
47
  updateByIdOrThrow(id: TEntity[PrimaryKey], changes: UpdateValues<TEntity, PrimaryKey>, errorFactory?: ErrorFactory<TEntity[PrimaryKey]>): Promise<TEntity>;
@@ -53,6 +57,11 @@ declare class BaseRepository<TEntity extends object, PrimaryKey extends keyof TE
53
57
  protected countWhere(where?: QueryWhere<TEntity>, options?: Pick<QueryOptions<TEntity>, "withTrashed" | "onlyTrashed" | "joins" | "groupBy">, whereNodes?: readonly WhereNode<TEntity>[]): Promise<number>;
54
58
  protected averageColumn(column: keyof TEntity & string, where?: QueryWhere<TEntity>): Promise<number>;
55
59
  protected averageExpression(expression: string, alias: string, where?: QueryWhere<TEntity>): Promise<number>;
60
+ sum(column: keyof TEntity & string, where?: QueryWhere<TEntity>): Promise<number>;
61
+ avg(column: keyof TEntity & string, where?: QueryWhere<TEntity>): Promise<number>;
62
+ min(column: keyof TEntity & string, where?: QueryWhere<TEntity>): Promise<number>;
63
+ max(column: keyof TEntity & string, where?: QueryWhere<TEntity>): Promise<number>;
64
+ private aggregateColumn;
56
65
  protected pluckNumberValues(expression: string, alias: string, options?: QueryOptions<TEntity>): Promise<number[]>;
57
66
  protected countGroupedBy<K extends keyof TEntity & string>(column: K, where?: QueryWhere<TEntity>): Promise<Array<{
58
67
  value: TEntity[K] | null;
@@ -10,6 +10,8 @@ interface SqlDialect {
10
10
  ilikeOperator(): "ILIKE" | "LIKE";
11
11
  nullsLastSuffix(): string;
12
12
  castToText(expression: string): string;
13
+ /** Conflict handling appended to an INSERT. Empty updates mean "do nothing". */
14
+ upsertSuffix(conflictColumns: readonly string[], updateColumns: readonly string[]): string;
13
15
  }
14
16
  declare function dialectFor(driver: DatabaseDriver): SqlDialect;
15
17
  declare function currentSqlDialect(): SqlDialect;
@@ -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";
@@ -43,7 +43,20 @@ declare class ModelQuery {
43
43
  limit(limit: number): this;
44
44
  offset(offset: number): this;
45
45
  whereNull(column: string): this;
46
+ whereNotNull(column: string): this;
46
47
  whereIn(column: string, values: readonly unknown[]): this;
48
+ whereNotIn(column: string, values: readonly unknown[]): this;
49
+ groupBy(groupBy: QueryOptions<object>["groupBy"]): this;
50
+ having(having: QueryWhere<object>): this;
51
+ join(left: `${string}.${string}`, right: `${string}.${string}`): this;
52
+ leftJoin(left: `${string}.${string}`, right: `${string}.${string}`): this;
53
+ paginate(options: {
54
+ page: number;
55
+ perPage: number;
56
+ }): Promise<{
57
+ data: Array<Model<Record<string, unknown>, "id">>;
58
+ meta: Awaited<ReturnType<RepositoryQuery<Record<string, unknown>, "id">["paginate"]>>["meta"];
59
+ }>;
47
60
  whereExists(sql: string, params?: readonly unknown[]): this;
48
61
  whereNotExists(sql: string, params?: readonly unknown[]): this;
49
62
  whereHas(name: string, constrain?: (query: AnyRelationQuery) => void): this;
@@ -60,10 +73,16 @@ declare class ModelQuery {
60
73
  withTrashed(): this;
61
74
  onlyTrashed(): this;
62
75
  get(): Promise<Array<Model<Record<string, unknown>, "id">>>;
76
+ private hydrateRows;
63
77
  first(): Promise<Model<Record<string, unknown>, "id"> | null>;
78
+ count(): Promise<number>;
79
+ pluck(column: string): Promise<unknown[]>;
80
+ pluck(column: string, keyBy: string): Promise<Map<unknown, unknown>>;
81
+ value(column: string): Promise<unknown>;
64
82
  find(id: unknown): Promise<Model<Record<string, unknown>, "id"> | null>;
65
83
  findOrFail(id: unknown, errorFactory?: (id: unknown) => Error): Promise<Model<Record<string, unknown>, "id">>;
66
84
  then(onfulfilled?: ((value: Array<Model<Record<string, unknown>, "id">>) => unknown) | null, onrejected?: ((reason: unknown) => unknown) | null): Promise<unknown>;
85
+ withCount(name: string, alias?: string): this;
67
86
  private constrainExists;
68
87
  }
69
88
  declare class Model<TEntity extends object, PrimaryKey extends keyof TEntity & string> {
@@ -129,6 +148,10 @@ declare class Model<TEntity extends object, PrimaryKey extends keyof TEntity & s
129
148
  static findOrFail(this: object, id: unknown, errorFactory?: (id: unknown) => Error): Promise<Model<Record<string, unknown>, "id">>;
130
149
  static all(this: object, options?: Omit<QueryOptions<object>, "where">): Promise<Array<Model<Record<string, unknown>, "id">>>;
131
150
  static where(this: object, where: QueryWhere<object>): ModelQuery;
151
+ static count(this: object): Promise<number>;
152
+ static pluck(this: object, column: string): Promise<unknown[]>;
153
+ static pluck(this: object, column: string, keyBy: string): Promise<Map<unknown, unknown>>;
154
+ static value(this: object, column: string): Promise<unknown>;
132
155
  static firstWhere(this: object, where: QueryWhere<object>, options?: Omit<QueryOptions<object>, "where">): Promise<Model<Record<string, unknown>, "id"> | null>;
133
156
  static firstOrNew(this: object, where: QueryWhere<object>, values?: Record<string, unknown>): Promise<Model<Record<string, unknown>, "id">>;
134
157
  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 };
@@ -44,6 +44,14 @@ declare function buildInsertQuery<TEntity extends object, PrimaryKey extends key
44
44
  text: string;
45
45
  params: unknown[];
46
46
  };
47
+ declare function buildUpsertQuery<TEntity extends object, PrimaryKey extends keyof TEntity & string>(table: TableDefinition<TEntity, PrimaryKey>, values: MutationValues<TEntity>, conflictColumns: readonly string[], updateColumns?: readonly string[]): {
48
+ text: string;
49
+ params: unknown[];
50
+ };
51
+ declare function buildIncrementQuery<TEntity extends object, PrimaryKey extends keyof TEntity & string>(table: TableDefinition<TEntity, PrimaryKey>, id: TEntity[PrimaryKey], column: keyof TEntity & string, amount: number, extra?: UpdateValues<TEntity, PrimaryKey>): {
52
+ text: string;
53
+ params: unknown[];
54
+ };
47
55
  declare function buildUpdateQuery<TEntity extends object, PrimaryKey extends keyof TEntity & string>(table: TableDefinition<TEntity, PrimaryKey>, id: TEntity[PrimaryKey], changes: UpdateValues<TEntity, PrimaryKey>): {
48
56
  text: string;
49
57
  params: unknown[];
@@ -60,4 +68,4 @@ declare function buildDeleteByIdQuery<TEntity extends object, PrimaryKey extends
60
68
  text: string;
61
69
  params: unknown[];
62
70
  };
63
- export { assertSafeProjectionExpression, buildAdvancedWhereClause, buildCountQuery, buildDeleteByIdQuery, buildGroupedCountQuery, buildInsertQuery, buildJoinClause, buildOrderByClause, buildProjectionQuery, buildQueryWhereClause, buildRestoreByIdQuery, buildSelectQuery, buildSoftDeleteByIdQuery, buildUpdateQuery, buildWhereClause, parseQualifiedColumn, qualifyColumn, quoteIdentifier, resolveQualifiedColumn, resolveSoftDeleteColumn, };
71
+ export { assertSafeProjectionExpression, buildAdvancedWhereClause, buildCountQuery, buildDeleteByIdQuery, buildGroupedCountQuery, buildIncrementQuery, buildInsertQuery, buildJoinClause, buildOrderByClause, buildProjectionQuery, buildQueryWhereClause, buildRestoreByIdQuery, buildSelectQuery, buildSoftDeleteByIdQuery, buildUpdateQuery, buildUpsertQuery, buildWhereClause, parseQualifiedColumn, qualifyColumn, quoteIdentifier, resolveQualifiedColumn, resolveSoftDeleteColumn, };
@@ -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 = {
@@ -17,6 +17,8 @@ declare class RepositoryQuery<TEntity extends object, PrimaryKey extends keyof T
17
17
  limit(limit: number): this;
18
18
  whereNull(column: keyof TEntity & string): this;
19
19
  whereNotNull(column: keyof TEntity & string): this;
20
+ whereNotIn(column: keyof TEntity & string, values: readonly unknown[]): this;
21
+ withSubqueryCount(alias: string, sql: string, params?: readonly unknown[]): this;
20
22
  whereIn(column: keyof TEntity & string, values: readonly unknown[]): this;
21
23
  whereExists(sql: string, params?: readonly unknown[]): this;
22
24
  whereNotExists(sql: string, params?: readonly unknown[]): this;
@@ -37,6 +39,9 @@ declare class RepositoryQuery<TEntity extends object, PrimaryKey extends keyof T
37
39
  get(): Promise<Array<TEntity & LoadedRow>>;
38
40
  first(): Promise<(TEntity & LoadedRow) | null>;
39
41
  count(): Promise<number>;
42
+ pluck<K extends keyof TEntity & string>(column: K): Promise<Array<TEntity[K]>>;
43
+ pluck<K extends keyof TEntity & string, KK extends keyof TEntity & string>(column: K, keyBy: KK): Promise<Map<TEntity[KK], TEntity[K]>>;
44
+ value<K extends keyof TEntity & string>(column: K): Promise<TEntity[K] | null>;
40
45
  attachToRows(rows: readonly TEntity[]): Promise<Array<TEntity & LoadedRow>>;
41
46
  paginate(options: {
42
47
  page: number;
@@ -47,4 +52,5 @@ declare class RepositoryQuery<TEntity extends object, PrimaryKey extends keyof T
47
52
  private attach;
48
53
  private hydrateEagerLoad;
49
54
  }
55
+ export { projectPluck, uniqueColumnSelect } from "./pluck.ts";
50
56
  export { RepositoryQuery };
@@ -2,7 +2,9 @@ type DatabaseComparable = string | number | Date;
2
2
  type DatabaseScalar = DatabaseComparable | boolean | null;
3
3
  type QueryOperator = {
4
4
  eq?: DatabaseScalar;
5
+ ne?: DatabaseScalar;
5
6
  in?: readonly DatabaseScalar[];
7
+ notIn?: readonly DatabaseScalar[];
6
8
  gt?: DatabaseComparable;
7
9
  gte?: DatabaseComparable;
8
10
  lt?: DatabaseComparable;
@@ -42,6 +44,11 @@ type QuerySelectItem = {
42
44
  kind: "literalText";
43
45
  value: string;
44
46
  as: string;
47
+ } | {
48
+ kind: "subqueryCount";
49
+ sql: string;
50
+ params: readonly unknown[];
51
+ as: string;
45
52
  } | {
46
53
  kind: "tsRank";
47
54
  table: string;