@getstrata/core 2.0.9 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/dist/core/cache/createCacheStore.d.ts +3 -1
  3. package/dist/core/cache/redisCacheStore.d.ts +21 -8
  4. package/dist/core/cache/repository.d.ts +3 -2
  5. package/dist/core/cache/store.d.ts +4 -1
  6. package/dist/core/cache/taggedCache.d.ts +1 -1
  7. package/dist/core/contracts/container.d.ts +28 -10
  8. package/dist/core/contracts/di.d.ts +7 -4
  9. package/dist/core/contracts/serviceTokens.d.ts +6 -1
  10. package/dist/core/database/baseRepository.d.ts +0 -1
  11. package/dist/core/database/index.d.ts +1 -1
  12. package/dist/core/database/model.d.ts +123 -42
  13. package/dist/core/database/repositoryQuery.d.ts +16 -1
  14. package/dist/core/database/types.d.ts +25 -2
  15. package/dist/core/database/whereBuilder.d.ts +5 -5
  16. package/dist/core/events/deferredModelEvents.d.ts +2 -1
  17. package/dist/core/http/loginThrottleMiddleware.d.ts +6 -5
  18. package/dist/core/http/memoryThrottleMiddleware.d.ts +11 -3
  19. package/dist/core/http/middleware.d.ts +2 -2
  20. package/dist/core/http/response.d.ts +2 -0
  21. package/dist/core/http/routeMiddleware.d.ts +3 -2
  22. package/dist/core/http/scimThrottleMiddleware.d.ts +12 -3
  23. package/dist/core/http/throttleMiddleware.d.ts +24 -6
  24. package/dist/core/lifecycle/gracefulShutdown.d.ts +33 -5
  25. package/dist/core/queue/index.d.ts +7 -0
  26. package/dist/core/queue/redisQueue.d.ts +1 -0
  27. package/dist/core/queue/resilientQueue.d.ts +2 -2
  28. package/dist/core/runtime/applicationRegistry.d.ts +2 -1
  29. package/dist/core/runtime/boundedThrottleStore.d.ts +29 -0
  30. package/dist/core/scheduler/leases.d.ts +40 -0
  31. package/dist/core/scheduler/schedule.d.ts +29 -5
  32. package/dist/core/tenant/tenantContext.d.ts +5 -4
  33. package/dist/core/tenant/tenantMiddleware.d.ts +7 -1
  34. package/dist/core/tracing/otel.d.ts +28 -26
  35. package/dist/core/tracing/tracingMiddleware.d.ts +4 -1
  36. package/dist/entries/audit/exportAuditLogs.js +14 -2
  37. package/dist/entries/auth/basicAuthGuard.js +80 -0
  38. package/dist/entries/auth/jwtGuard.js +80 -0
  39. package/dist/entries/auth/scimAuthMiddleware.js +17 -7
  40. package/dist/entries/auth/sessionGuard.js +80 -0
  41. package/dist/entries/cache/createCacheStore.js +365 -119
  42. package/dist/entries/cache/repository.js +5 -0
  43. package/dist/entries/contracts/container.js +8 -1
  44. package/dist/entries/contracts/serviceTokens.js +83 -0
  45. package/dist/entries/database/factory.js +0 -3
  46. package/dist/entries/database/model.js +1 -2465
  47. package/dist/entries/database/repositoryQuery.js +67 -9
  48. package/dist/entries/http/bodySizeLimitMiddleware.js +76 -10
  49. package/dist/entries/http/memoryThrottleMiddleware.js +276 -21
  50. package/dist/entries/http/routeMiddleware.js +1 -4
  51. package/dist/entries/http/scimThrottleMiddleware.js +576 -54
  52. package/dist/entries/http/throttleMiddleware.js +65 -16
  53. package/dist/entries/jobs/exportAuditLogsJob.js +44 -7
  54. package/dist/entries/jobs/invalidateCacheTagsJob.js +30 -5
  55. package/dist/entries/queue/createAppQueue.js +67 -6
  56. package/dist/entries/queue/publicQueue.js +67 -6
  57. package/dist/entries/queue/queueMetrics.js +67 -6
  58. package/dist/entries/queue/redisQueue.js +3 -0
  59. package/dist/entries/queue.js +30 -5
  60. package/dist/entries/scheduler/schedule.js +1 -72
  61. package/dist/entries/tenant/databaseTenantContext.js +14 -2
  62. package/dist/entries/tenant/tenantDatabaseScope.js +14 -2
  63. package/dist/entries/tracing/tracingMiddleware.js +186 -454
  64. package/dist/framework/public-api.d.ts +14 -10
  65. package/dist/index.js +1770 -638
  66. package/dist/types/services.d.ts +3 -3
  67. package/package.json +17 -8
package/CHANGELOG.md CHANGED
@@ -1,5 +1,42 @@
1
1
  # @getstrata/core changelog
2
2
 
3
+ ## 2.2.0
4
+
5
+ Consistent model scopes.
6
+ Changed-field model writes.
7
+ Awaited provider startup.
8
+ Shared cache correctness.
9
+ Native HTTP controls and body limits.
10
+ Graceful lifecycle.
11
+ Validated async discovery.
12
+ Stronger model input types.
13
+ OpenTelemetry tracing.
14
+ Distributed scheduler ownership.
15
+ App-owned quota policy.
16
+ Bounded memory throttling.
17
+
18
+ ## Unreleased
19
+
20
+ - Coordinate scheduled minute occurrences with renewable Redis ownership, overlap exclusion, completion retention and lease-loss cancellation. Production defaults to Redis without local fallback; direct task callbacks now accept ownership context. Share appSchedule across root/subpath imports. See SCHEDULER.md for explicit local mode and replay limits.
21
+
22
+ - Use maintained OpenTelemetry tracing with W3C propagation, consistent identities/epoch timestamps, bounded batching, sampling, error status and lifecycle-owned flush/shutdown. Raw URL/exception secrets are omitted; debug x-trace-id no longer overrides identity.
23
+
24
+ - Strengthen declared model write/filter/identifier contracts and add typed plain-record projections with model casts and existing scope/RLS semantics. Source compatibility: use `query().select(...)` instead of partial selects on model-returning helpers, `whereDynamic` for qualified/dynamic predicates, and `newFromTrustedRecord` for deliberate partial driver hydration. Database defaults and mass-assignment rules remain runtime concerns.
25
+
26
+ - Accept awaited provider hooks and explicit cleanup registration; expose optional closure of owned Redis cache/queue clients.
27
+
28
+ - Persist only changed attributes on existing model saves, skip no-op updates and unchanged write casts, and restore retryable snapshots after transaction/savepoint rollback.
29
+
30
+ - Apply related target model scopes and composed filters to lazy/eager/existence/count reads; retain batched connection reuse, isolate morph targets by type and ID, and use dialect-aware through/pivot read parameters.
31
+
32
+ - Compose repeated query predicates and protect global model scopes from caller OR branches; preserve scopes in chunks/cursor pages and intersect cursor bounds with existing filters.
33
+
34
+ - Add typed `defineModel(table)` bases and two-phase model startup; preserve explicit repository overrides and share model identity across package import paths.
35
+
36
+ ## 2.1.0
37
+
38
+ - refactor(starter): reuse shared config and base repositories - fix(database): await password casts before model writes - fix(database): preserve concrete model types in query results
39
+
3
40
  ## 2.0.9
4
41
 
5
42
  - fix(starter): remove demo credentials from public login defaults
@@ -1,3 +1,4 @@
1
+ import { type RedisCacheOptions } from "./redisCacheStore";
1
2
  import type { CacheStore } from "./store";
2
3
  type CacheDriver = "array" | "redis";
3
4
  interface CreateCacheStoreOptions {
@@ -5,7 +6,8 @@ interface CreateCacheStoreOptions {
5
6
  ttlMs: number;
6
7
  maxEntries: number;
7
8
  redisUrl?: string;
9
+ redis?: RedisCacheOptions;
8
10
  }
9
11
  declare function createCacheStore(options: CreateCacheStoreOptions): CacheStore;
10
- export type { CacheDriver, CreateCacheStoreOptions };
12
+ export type { CacheDriver, CreateCacheStoreOptions, RedisCacheOptions };
11
13
  export { createCacheStore };
@@ -1,23 +1,36 @@
1
1
  import type { CacheStore } from "./store";
2
+ type RedisCacheOptions = {
3
+ commandTimeoutMs?: number;
4
+ leaseMs?: number;
5
+ fillTimeoutMs?: number;
6
+ waitTimeoutMs?: number;
7
+ pollMs?: number;
8
+ metadataTtlMs?: number;
9
+ metadataLimit?: number;
10
+ };
2
11
  declare class RedisCacheStore implements CacheStore {
3
12
  private readonly ttlMs;
4
13
  private readonly maxEntries;
5
14
  private readonly client;
6
- private readonly inflight;
7
- private readonly keyTags;
8
- constructor(redisUrl: string, ttlMs: number, maxEntries: number);
15
+ private readonly keys;
16
+ private readonly options;
17
+ private readonly fills;
18
+ private closed;
19
+ constructor(redisUrl: string, ttlMs: number, maxEntries: number, options?: RedisCacheOptions);
20
+ close(): void;
9
21
  get<T>(key: string): Promise<T | undefined>;
10
22
  set<T>(key: string, value: T, ttlMs?: number): Promise<void>;
11
- getOrSet<T>(key: string, loader: () => Promise<T>, ttlMs?: number): Promise<T>;
23
+ getOrSet<T>(key: string, loader: (signal?: AbortSignal) => Promise<T>, ttlMs?: number): Promise<T>;
24
+ getOrSetTagged<T>(key: string, loader: (signal?: AbortSignal) => Promise<T>, tags: string[], ttlMs?: number): Promise<T>;
12
25
  attachTags(key: string, tags: string[]): Promise<void>;
13
26
  flushTags(tags: string[]): Promise<number>;
14
27
  invalidate(key: string): Promise<boolean>;
15
28
  invalidateByPrefix(prefix: string): Promise<number>;
16
29
  clear(): Promise<void>;
17
30
  size(): Promise<number>;
18
- private storageKey;
19
- private tagKey;
20
- private detachKeyFromTags;
21
- private enforceMaxEntries;
31
+ private fill;
32
+ private serialize;
33
+ private execute;
22
34
  }
35
+ export type { RedisCacheOptions };
23
36
  export default RedisCacheStore;
@@ -3,12 +3,13 @@ import TaggedCache from "./taggedCache";
3
3
  declare class CacheRepository {
4
4
  private readonly store;
5
5
  constructor(store: CacheStore);
6
+ close(): Promise<void>;
6
7
  get<T>(key: string): Promise<T | undefined>;
7
- remember<T>(key: string, callback: () => Promise<T>, ttlMs?: number): Promise<T>;
8
+ remember<T>(key: string, callback: (signal?: AbortSignal) => Promise<T>, ttlMs?: number): Promise<T>;
8
9
  forget(key: string): Promise<boolean>;
9
10
  flush(): Promise<void>;
10
11
  tags(...names: string[]): TaggedCache;
11
- getOrSet<T>(key: string, loader: () => Promise<T>, ttlMs?: number): Promise<T>;
12
+ getOrSet<T>(key: string, loader: (signal?: AbortSignal) => Promise<T>, ttlMs?: number): Promise<T>;
12
13
  invalidate(key: string): Promise<boolean>;
13
14
  invalidateByPrefix(prefix: string): Promise<number>;
14
15
  clear(): Promise<void>;
@@ -1,7 +1,10 @@
1
1
  interface CacheStore {
2
+ close?(): void | Promise<void>;
2
3
  get<T>(key: string): Promise<T | undefined>;
3
4
  set<T>(key: string, value: T, ttlMs?: number): Promise<void>;
4
- getOrSet<T>(key: string, loader: () => Promise<T>, ttlMs?: number): Promise<T>;
5
+ getOrSet<T>(key: string, loader: (signal?: AbortSignal) => Promise<T>, ttlMs?: number): Promise<T>;
6
+ /** Shared stores can bind tags before starting a fill. */
7
+ getOrSetTagged?<T>(key: string, loader: (signal?: AbortSignal) => Promise<T>, tags: string[], ttlMs?: number): Promise<T>;
5
8
  attachTags(key: string, tags: string[]): Promise<void>;
6
9
  flushTags(tags: string[]): Promise<number>;
7
10
  invalidate(key: string): Promise<boolean>;
@@ -3,7 +3,7 @@ declare class TaggedCache {
3
3
  private readonly store;
4
4
  private readonly tags;
5
5
  constructor(store: CacheStore, tags: string[]);
6
- remember<T>(key: string, callback: () => Promise<T>, ttlMs?: number): Promise<T>;
6
+ remember<T>(key: string, callback: (signal?: AbortSignal) => Promise<T>, ttlMs?: number): Promise<T>;
7
7
  flush(): Promise<number>;
8
8
  }
9
9
  export default TaggedCache;
@@ -1,19 +1,37 @@
1
+ declare const serviceTokenType: unique symbol;
2
+ /** Invariant service identity; its runtime value remains the existing string key. */
3
+ type ServiceToken<T> = string & {
4
+ readonly [serviceTokenType]: (value: T) => T;
5
+ };
6
+ /** Prevent a typed token from falling back to an unchecked legacy overload. */
7
+ type LegacyServiceKey = string & {
8
+ readonly [serviceTokenType]?: never;
9
+ };
10
+ declare function createServiceToken<T>(key: string): ServiceToken<T>;
1
11
  type ServiceFactory<T> = (container: ServiceContainer) => T;
2
12
  interface ServiceContainerLike {
3
13
  has(key: string): boolean;
4
- resolve<T>(key: string): T;
14
+ resolve<T>(key: ServiceToken<T>): T;
15
+ resolve<T>(key: LegacyServiceKey): T;
5
16
  }
6
17
  declare class ServiceContainer implements ServiceContainerLike {
7
18
  private readonly services;
8
19
  private readonly singletonFactories;
9
20
  private readonly bindings;
10
- set<T>(key: string, value: T): T;
11
- singleton<T>(key: string, factory: ServiceFactory<T>): void;
12
- bind<T>(key: string, factory: ServiceFactory<T>): void;
13
- get<T>(key: string): T;
14
- resolve<T>(key: string): T;
15
- make<T>(key: string): T;
16
- instance<T>(key: string, value: T): T;
21
+ set<T>(key: ServiceToken<T>, value: NoInfer<T>): T;
22
+ set<T>(key: LegacyServiceKey, value: T): T;
23
+ singleton<T>(key: ServiceToken<T>, factory: ServiceFactory<NoInfer<T>>): void;
24
+ singleton<T>(key: LegacyServiceKey, factory: ServiceFactory<T>): void;
25
+ bind<T>(key: ServiceToken<T>, factory: ServiceFactory<NoInfer<T>>): void;
26
+ bind<T>(key: LegacyServiceKey, factory: ServiceFactory<T>): void;
27
+ get<T>(key: ServiceToken<T>): T;
28
+ get<T>(key: LegacyServiceKey): T;
29
+ resolve<T>(key: ServiceToken<T>): T;
30
+ resolve<T>(key: LegacyServiceKey): T;
31
+ make<T>(key: ServiceToken<T>): T;
32
+ make<T>(key: LegacyServiceKey): T;
33
+ instance<T>(key: ServiceToken<T>, value: NoInfer<T>): T;
34
+ instance<T>(key: LegacyServiceKey, value: T): T;
17
35
  has(key: string): boolean;
18
36
  }
19
37
  interface ConfigStoreLike {
@@ -28,5 +46,5 @@ declare class ConfigStore implements ConfigStoreLike {
28
46
  require<T>(key: string): T;
29
47
  has(key: string): boolean;
30
48
  }
31
- export type { ConfigStoreLike, ServiceContainerLike, ServiceFactory };
32
- export { ConfigStore, ServiceContainer };
49
+ export type { ConfigStoreLike, LegacyServiceKey, ServiceContainerLike, ServiceFactory, ServiceToken, };
50
+ export { ConfigStore, createServiceToken, ServiceContainer };
@@ -1,6 +1,6 @@
1
1
  import type { CacheLike } from "../../types/services";
2
2
  import type { StorageManager } from "../storage/storage";
3
- import type { ConfigStore, ConfigStoreLike, ServiceContainer, ServiceFactory } from "./container";
3
+ import type { ConfigStore, ConfigStoreLike, LegacyServiceKey, ServiceContainer, ServiceFactory, ServiceToken } from "./container";
4
4
  type AppRouteMap = Record<string, any>;
5
5
  type CachedJson = <T>(cacheKey: string, loader: () => Promise<T>, tags?: string[], request?: Request) => Promise<Response>;
6
6
  interface AppDependencies {
@@ -13,11 +13,13 @@ interface ProviderContext {
13
13
  container: ServiceContainer;
14
14
  config: ConfigStore;
15
15
  dependencies: MutableAppDependencies;
16
+ /** Register owned resources immediately; flush precedes close, each in reverse order. */
17
+ onCleanup(handler: () => void | Promise<void>, phase?: "drain" | "flush" | "close"): void;
16
18
  }
17
19
  interface ServiceProvider {
18
20
  name: string;
19
- register?(context: ProviderContext): void;
20
- boot?(context: ProviderContext): void;
21
+ register?(context: ProviderContext): void | Promise<void>;
22
+ boot?(context: ProviderContext): void | Promise<void>;
21
23
  }
22
24
  interface AppContext {
23
25
  container: ServiceContainer;
@@ -26,6 +28,7 @@ interface AppContext {
26
28
  }
27
29
  declare function getRequiredDependency<K extends keyof AppDependencies>(dependencies: Partial<AppDependencies>, key: K): AppDependencies[K];
28
30
  declare function assertAppDependenciesComplete(dependencies: MutableAppDependencies): asserts dependencies is AppDependencies;
29
- declare function resolveService<T>(dependencies: AppDependencies, token: string): T;
31
+ declare function resolveService<T>(dependencies: AppDependencies, token: ServiceToken<T>): T;
32
+ declare function resolveService<T>(dependencies: AppDependencies, token: LegacyServiceKey): T;
30
33
  export type { AppContext, AppDependencies, AppRouteMap, CachedJson, MutableAppDependencies, ProviderContext, ServiceFactory, ServiceProvider, };
31
34
  export { assertAppDependenciesComplete, getRequiredDependency, resolveService };
@@ -1,6 +1,11 @@
1
1
  import type { AbilityChecker } from "../auth/abilityChecker";
2
+ import type { ThrottleQuotaPolicy } from "../http/throttleMiddleware";
3
+ import type { TenantResolver } from "../tenant/tenantMiddleware";
2
4
  import type { AuthUserDirectory } from "./authUserDirectory";
3
5
  import type { ServiceContainerLike } from "./container";
6
+ declare const CORE_THROTTLE_QUOTA_POLICY_TOKEN: import("./container").ServiceToken<ThrottleQuotaPolicy>;
7
+ declare const CORE_TENANT_RESOLVER_TOKEN: import("./container").ServiceToken<TenantResolver>;
8
+ declare const CORE_HTTP_CLEANUP_TOKEN: import("./container").ServiceToken<(cleanup: () => void) => void>;
4
9
  declare const CORE_CONFIG_TOKEN = "core.config";
5
10
  declare const CORE_CACHE_TOKEN = "core.cache";
6
11
  declare const CORE_QUEUE_TOKEN = "core.queue";
@@ -14,4 +19,4 @@ declare function isAbilityChecker(value: unknown): value is AbilityChecker;
14
19
  declare function isAuthUserDirectory(value: unknown): value is AuthUserDirectory;
15
20
  declare function resolveAbilityChecker(container: ServiceContainerLike): AbilityChecker;
16
21
  declare function resolveAuthUserDirectory(container: ServiceContainerLike): AuthUserDirectory | null;
17
- export { CORE_ABILITY_CHECKER_TOKEN, CORE_AUTH_TOKEN, CORE_AUTH_USER_DIRECTORY_TOKEN, CORE_CACHE_TOKEN, CORE_CONFIG_TOKEN, CORE_EVENT_BUS_TOKEN, CORE_POLICY_GATE_TOKEN, CORE_QUEUE_TOKEN, CORE_TOKEN_SERVICE_TOKEN, isAbilityChecker, isAuthUserDirectory, resolveAbilityChecker, resolveAuthUserDirectory, };
22
+ export { CORE_ABILITY_CHECKER_TOKEN, CORE_AUTH_TOKEN, CORE_AUTH_USER_DIRECTORY_TOKEN, CORE_CACHE_TOKEN, CORE_CONFIG_TOKEN, CORE_EVENT_BUS_TOKEN, CORE_HTTP_CLEANUP_TOKEN, CORE_POLICY_GATE_TOKEN, CORE_QUEUE_TOKEN, CORE_TENANT_RESOLVER_TOKEN, CORE_THROTTLE_QUOTA_POLICY_TOKEN, CORE_TOKEN_SERVICE_TOKEN, isAbilityChecker, isAuthUserDirectory, resolveAbilityChecker, resolveAuthUserDirectory, };
@@ -73,7 +73,6 @@ declare class BaseRepository<TEntity extends object, PrimaryKey extends keyof TE
73
73
  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[]>>;
74
74
  findHasManyThrough<TParent extends object, LocalKey extends keyof TParent & string, FirstKey extends string, SecondLocalKey extends string, SecondKey extends keyof TEntity & string>(parentId: unknown, relation: HasManyThroughRelation<TParent, TEntity, LocalKey, FirstKey, SecondLocalKey, SecondKey>, options?: QueryOptions<TEntity>): Promise<TEntity[]>;
75
75
  loadHasManyThroughForParents<TParent extends object, LocalKey extends keyof TParent & string, FirstKey extends string, SecondLocalKey extends string, SecondKey extends keyof TEntity & string>(parents: readonly TParent[], relation: HasManyThroughRelation<TParent, TEntity, LocalKey, FirstKey, SecondLocalKey, SecondKey>, options?: QueryOptions<TEntity>): Promise<Map<TParent[LocalKey], TEntity[]>>;
76
- private throughSoftDeleteClause;
77
76
  private buildThroughWhere;
78
77
  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>>;
79
78
  loadMorphManyForParents<TParent extends object, LocalKey extends keyof TParent & string, MorphTypeKey extends keyof TEntity & string, MorphIdKey extends keyof TEntity & string>(parents: readonly TParent[], relation: MorphManyRelation<TParent, TEntity, LocalKey, MorphTypeKey, MorphIdKey>, options?: Omit<QueryOptions<TEntity>, "where">): Promise<Map<TParent[LocalKey], TEntity[]>>;
@@ -9,7 +9,7 @@ export { mapDatabaseError, withDatabaseErrorHandling } from "./errors.ts";
9
9
  export { Factory } from "./factory.ts";
10
10
  export { foreignKeyFromTable, pivotTableName, singularize } from "./inflection.ts";
11
11
  export type { CastType, GlobalScopeFn, ModelConstructor } from "./model.ts";
12
- export { applyCasts, BelongsToManyRelationQuery, BelongsToRelationQuery, dehydrateValue, filterMassAssignable, HasManyRelationQuery, HasManyThroughRelationQuery, HasOneRelationQuery, hydrateValue, Model, ModelQuery, MorphManyRelationQuery, MorphOneRelationQuery, MorphToRelationQuery, registerModelClass, registerModelRepository, } from "./model.ts";
12
+ export { applyCasts, BelongsToManyRelationQuery, BelongsToRelationQuery, bootModels, defineModel, dehydrateValue, filterMassAssignable, HasManyRelationQuery, HasManyThroughRelationQuery, HasOneRelationQuery, hydrateValue, Model, ModelQuery, MorphManyRelationQuery, MorphOneRelationQuery, MorphToRelationQuery, registerModelClass, registerModelRepository, } from "./model.ts";
13
13
  export type { MysqlConnection, MysqlExecutable, MysqlPool } from "./mysqlConnection.ts";
14
14
  export { createMysqlConnection, createMysqlConnectionFromPool, createMysqlPool, } from "./mysqlConnection.ts";
15
15
  export type { NamedConnectionEntry } from "./namedConnections.ts";
@@ -1,9 +1,10 @@
1
- import type BaseRepository from "./baseRepository.ts";
1
+ import BaseRepository from "./baseRepository.ts";
2
2
  import type { AnyRelationQuery, RelatedModelClass } from "./relationQuery.ts";
3
3
  import { BelongsToManyRelationQuery, BelongsToRelationQuery, HasManyRelationQuery, HasManyThroughRelationQuery, HasOneRelationQuery, MorphManyRelationQuery, MorphOneRelationQuery, MorphToRelationQuery } from "./relationQuery.ts";
4
4
  import type { BelongsToManyRelation, BelongsToRelation, HasManyRelation, HasOneRelation } from "./relationships.ts";
5
5
  import type { RepositoryQuery } from "./repositoryQuery.ts";
6
- import type { QueryOptions, QueryWhere } from "./types.ts";
6
+ import type { TableDefinition } from "./table.ts";
7
+ import type { ModelWhere, ModelWriteValues, QueryOptions, QueryWhere } from "./types.ts";
7
8
  type CastType = "date" | "datetime" | "json" | "bool" | "boolean" | "integer" | "int" | "hashed";
8
9
  type LoadedAttributes = Record<string, unknown>;
9
10
  type ModelCasts = Partial<Record<string, CastType>>;
@@ -13,6 +14,17 @@ interface ModelConstructor<TEntity extends object, PrimaryKey extends keyof TEnt
13
14
  new (attributes: TEntity, repository: BaseRepository<TEntity, PrimaryKey>, exists?: boolean): TModel;
14
15
  }
15
16
  type AnyModel = Model<Record<string, unknown>, "id">;
17
+ type ModelAttributes<TModel> = TModel extends {
18
+ toObject(): infer TRecord extends object;
19
+ } ? TRecord : Record<string, unknown>;
20
+ type ModelIdentifier<TModel> = TModel extends {
21
+ readonly id: infer TKey;
22
+ } ? TKey : unknown;
23
+ type WithModelCount<TModel, TCount extends string> = {
24
+ toObject(): Omit<ModelAttributes<TModel>, TCount> & Record<TCount, unknown>;
25
+ get<K extends keyof (Omit<ModelAttributes<TModel>, TCount> & Record<TCount, unknown>)>(key: K): (Omit<ModelAttributes<TModel>, TCount> & Record<TCount, unknown>)[K];
26
+ } & TModel;
27
+ type ModelQueryResult<TModel, TCounts extends string> = [TCounts] extends [never] ? TModel : WithModelCount<TModel, TCounts>;
16
28
  type RelatedRef<TRelated extends object, RelatedKey extends keyof TRelated & string> = RelatedModelClass<TRelated, RelatedKey> | string | (() => RelatedModelClass<TRelated, RelatedKey>);
17
29
  type RelationNameInput = string | readonly string[];
18
30
  type ModelObserver = {
@@ -26,27 +38,45 @@ type ModelObserver = {
26
38
  deleting?: (model: AnyModel) => unknown;
27
39
  deleted?: (model: AnyModel) => unknown;
28
40
  };
41
+ /** Typed model base with a lazily created framework repository and active connection. */
42
+ declare function defineModel<TEntity extends object, PrimaryKey extends keyof TEntity & string>(table: TableDefinition<TEntity, PrimaryKey>): typeof Model<TEntity, PrimaryKey>;
43
+ /** Register all relationship names before initializing any model's boot hooks. */
44
+ declare function bootModels(models: readonly object[]): void;
29
45
  /** Alias for `hasMany("Name")` when `Name` is not `constructor.name` or `$morphClass`. */
30
46
  declare function registerModelClass(name: string, model: object): void;
31
47
  declare function hydrateValue(value: unknown, cast: CastType): unknown;
48
+ declare function dehydrateValue(value: unknown, cast: "hashed"): Promise<unknown>;
49
+ declare function dehydrateValue(value: unknown, cast: Exclude<CastType, "hashed">): unknown;
32
50
  declare function dehydrateValue(value: unknown, cast: CastType): unknown;
33
51
  declare function filterMassAssignable(fillable: readonly string[] | undefined, guarded: readonly string[] | true | undefined, input: LoadedAttributes): LoadedAttributes;
34
- declare function applyCasts(values: LoadedAttributes, casts: ModelCasts, direction: "hydrate" | "dehydrate"): LoadedAttributes;
35
- declare class ModelQuery {
52
+ declare function applyCasts(values: LoadedAttributes, casts: ModelCasts, direction: "hydrate"): LoadedAttributes;
53
+ declare function applyCasts(values: LoadedAttributes, casts: ModelCasts, direction: "dehydrate"): Promise<LoadedAttributes>;
54
+ declare function applyCasts(values: LoadedAttributes, casts: ModelCasts, direction: "hydrate" | "dehydrate"): LoadedAttributes | Promise<LoadedAttributes>;
55
+ /** Read-only plain records; partial selection never acquires model mutation methods. */
56
+ declare class ModelProjection<TEntity extends object, K extends keyof TEntity & string> {
57
+ private readonly load;
58
+ constructor(load: (limit?: number) => Promise<Array<Pick<TEntity, K>>>);
59
+ get(): Promise<Array<Pick<TEntity, K>>>;
60
+ first(): Promise<Pick<TEntity, K> | null>;
61
+ }
62
+ declare class ModelQuery<TModel extends object = AnyModel, TCounts extends string = never> {
36
63
  private readonly modelClass;
37
64
  readonly query: RepositoryQuery<Record<string, unknown>, "id">;
38
65
  private readonly eager;
39
66
  constructor(modelClass: object, query: RepositoryQuery<Record<string, unknown>, "id">);
40
67
  with(...relations: RelationNameInput[]): this;
41
- where(input: QueryWhere<object> | ((builder: import("./whereBuilder.ts").WhereBuilder<object>) => void)): this;
42
- orWhere(input: QueryWhere<object> | ((builder: import("./whereBuilder.ts").WhereBuilder<object>) => void)): this;
43
- orderBy(orderBy: QueryOptions<object>["orderBy"]): this;
68
+ where(input: ModelWhere<ModelAttributes<TModel>> | ((builder: import("./whereBuilder.ts").WhereBuilder<ModelAttributes<TModel>, ModelWhere<ModelAttributes<TModel>>>) => void)): this;
69
+ orWhere(input: ModelWhere<ModelAttributes<TModel>> | ((builder: import("./whereBuilder.ts").WhereBuilder<ModelAttributes<TModel>, ModelWhere<ModelAttributes<TModel>>>) => void)): this;
70
+ /** Qualified/dynamic filters retain existing SQL semantics through an explicit escape hatch. */
71
+ whereDynamic(input: QueryWhere<object>): this;
72
+ select<K extends keyof ModelAttributes<TModel> & string>(...columns: readonly K[]): ModelProjection<ModelAttributes<TModel>, K>;
73
+ orderBy(orderBy: QueryOptions<ModelAttributes<TModel>>["orderBy"]): this;
44
74
  limit(limit: number): this;
45
75
  offset(offset: number): this;
46
- whereNull(column: string): this;
47
- whereNotNull(column: string): this;
48
- whereIn(column: string, values: readonly unknown[]): this;
49
- whereNotIn(column: string, values: readonly unknown[]): this;
76
+ whereNull(column: keyof ModelAttributes<TModel> & string): this;
77
+ whereNotNull(column: keyof ModelAttributes<TModel> & string): this;
78
+ whereIn<K extends keyof ModelAttributes<TModel> & string>(column: K, values: readonly ModelAttributes<TModel>[K][]): this;
79
+ whereNotIn<K extends keyof ModelAttributes<TModel> & string>(column: K, values: readonly ModelAttributes<TModel>[K][]): this;
50
80
  groupBy(groupBy: QueryOptions<object>["groupBy"]): this;
51
81
  having(having: QueryWhere<object>): this;
52
82
  join(left: `${string}.${string}`, right: `${string}.${string}`): this;
@@ -55,7 +85,7 @@ declare class ModelQuery {
55
85
  page: number;
56
86
  perPage: number;
57
87
  }): Promise<{
58
- data: Array<Model<Record<string, unknown>, "id">>;
88
+ data: ModelQueryResult<TModel, TCounts>[];
59
89
  meta: Awaited<ReturnType<RepositoryQuery<Record<string, unknown>, "id">["paginate"]>>["meta"];
60
90
  }>;
61
91
  whereExists(sql: string, params?: readonly unknown[]): this;
@@ -73,17 +103,17 @@ declare class ModelQuery {
73
103
  withHasManyThrough(...args: Parameters<RepositoryQuery<Record<string, unknown>, "id">["withHasManyThrough"]>): this;
74
104
  withTrashed(): this;
75
105
  onlyTrashed(): this;
76
- get(): Promise<Array<Model<Record<string, unknown>, "id">>>;
106
+ get(): Promise<ModelQueryResult<TModel, TCounts>[]>;
77
107
  private hydrateRows;
78
- first(): Promise<Model<Record<string, unknown>, "id"> | null>;
108
+ first(): Promise<ModelQueryResult<TModel, TCounts> | null>;
79
109
  count(): Promise<number>;
80
110
  pluck(column: string): Promise<unknown[]>;
81
111
  pluck(column: string, keyBy: string): Promise<Map<unknown, unknown>>;
82
112
  value(column: string): Promise<unknown>;
83
- find(id: unknown): Promise<Model<Record<string, unknown>, "id"> | null>;
84
- findOrFail(id: unknown, errorFactory?: (id: unknown) => Error): Promise<Model<Record<string, unknown>, "id">>;
85
- then(onfulfilled?: ((value: Array<Model<Record<string, unknown>, "id">>) => unknown) | null, onrejected?: ((reason: unknown) => unknown) | null): Promise<unknown>;
86
- withCount(name: string, alias?: string): this;
113
+ find(id: ModelIdentifier<TModel>): Promise<ModelQueryResult<TModel, TCounts> | null>;
114
+ findOrFail(id: ModelIdentifier<TModel>, errorFactory?: (id: unknown) => Error): Promise<ModelQueryResult<TModel, TCounts>>;
115
+ then(onfulfilled?: ((value: ModelQueryResult<TModel, TCounts>[]) => unknown) | null, onrejected?: ((reason: unknown) => unknown) | null): Promise<unknown>;
116
+ withCount<TName extends string, TAlias extends string = `${TName}_count`>(name: TName, alias?: TAlias): ModelQuery<TModel, TCounts | TAlias>;
87
117
  private constrainExists;
88
118
  }
89
119
  declare class Model<TEntity extends object, PrimaryKey extends keyof TEntity & string> {
@@ -98,11 +128,13 @@ declare class Model<TEntity extends object, PrimaryKey extends keyof TEntity & s
98
128
  static $appends?: readonly string[];
99
129
  static $morphClass?: string;
100
130
  private _exists;
131
+ private originalAttributes;
101
132
  private readonly loadedRelations;
102
133
  private hiddenOverrides;
103
134
  private visibleOverrides;
104
135
  private appended;
105
136
  constructor(attributes: TEntity, repository: BaseRepository<TEntity, PrimaryKey>, exists?: boolean);
137
+ private acceptPersistedAttributes;
106
138
  getRepository(): BaseRepository<TEntity, PrimaryKey>;
107
139
  get $exists(): boolean;
108
140
  get<K extends keyof TEntity>(key: K): TEntity[K];
@@ -116,24 +148,49 @@ declare class Model<TEntity extends object, PrimaryKey extends keyof TEntity & s
116
148
  protected primaryKey(): PrimaryKey;
117
149
  protected static primaryKeyField(this: object): string;
118
150
  protected static hydrateAttributes<TEntity extends object>(this: object, attributes: TEntity): TEntity;
119
- protected static dehydrateAttributes(this: object, attributes: LoadedAttributes): LoadedAttributes;
151
+ protected static dehydrateAttributes(this: object, attributes: LoadedAttributes): LoadedAttributes | Promise<LoadedAttributes>;
120
152
  protected static fromRecord<TEntity extends object, PrimaryKey extends keyof TEntity & string>(this: object, record: TEntity, repository: BaseRepository<TEntity, PrimaryKey>, exists?: boolean): Model<TEntity, PrimaryKey>;
121
153
  static boot(): void;
122
154
  static observe(this: object, observer: ModelObserver): void;
123
155
  static addGlobalScope<TEntity extends object, PrimaryKey extends keyof TEntity & string>(this: object, _name: string, scope: GlobalScopeFn<TEntity, PrimaryKey>): void;
124
156
  static repository<TEntity extends object, PrimaryKey extends keyof TEntity & string>(this: object): BaseRepository<TEntity, PrimaryKey>;
125
- static query(this: object): ModelQuery;
126
- static newFromRecord(this: object, record: object, exists?: boolean): Model<Record<string, unknown>, "id">;
127
- static create(this: object, attributes: Record<string, unknown>, forced?: Record<string, unknown>): Promise<Model<Record<string, unknown>, "id">>;
128
- static with(this: object, ...relations: RelationNameInput[]): ModelQuery;
129
- static withTrashed(this: object): ModelQuery;
130
- static onlyTrashed(this: object): ModelQuery;
131
- static chunk(this: object, count: number, callback: (models: Array<Model<Record<string, unknown>, "id">>) => Promise<boolean | void>): Promise<void>;
132
- static cursorPaginate(this: object, options: {
157
+ /** Apply this model's global filters to a query with an explicitly selected connection. */
158
+ static scopeQuery<TEntity extends object, PrimaryKey extends keyof TEntity & string>(this: object, query: RepositoryQuery<TEntity, PrimaryKey>): RepositoryQuery<TEntity, PrimaryKey>;
159
+ static query<TModel extends object>(this: {
160
+ prototype: TModel;
161
+ }): ModelQuery<TModel>;
162
+ static newFromRecord<TModel extends object>(this: {
163
+ prototype: TModel;
164
+ }, record: NoInfer<ModelWriteValues<ModelAttributes<TModel>>>, exists: false): TModel;
165
+ static newFromRecord<TModel extends object>(this: {
166
+ prototype: TModel;
167
+ }, record: NoInfer<ModelAttributes<TModel>>, exists?: boolean): TModel;
168
+ /** Trusted SQL/driver/partial-record hydration. Callers own shape and completeness. */
169
+ static newFromTrustedRecord<TModel extends object>(this: {
170
+ prototype: TModel;
171
+ }, record: object, exists?: boolean): TModel;
172
+ static create<TModel extends object>(this: {
173
+ prototype: TModel;
174
+ }, attributes: NoInfer<ModelWriteValues<ModelAttributes<TModel>>>, forced?: NoInfer<ModelWriteValues<ModelAttributes<TModel>>>): Promise<TModel>;
175
+ static with<TModel extends object>(this: {
176
+ prototype: TModel;
177
+ }, ...relations: RelationNameInput[]): ModelQuery<TModel>;
178
+ static withTrashed<TModel extends object>(this: {
179
+ prototype: TModel;
180
+ }): ModelQuery<TModel>;
181
+ static onlyTrashed<TModel extends object>(this: {
182
+ prototype: TModel;
183
+ }): ModelQuery<TModel>;
184
+ static chunk<TModel extends object>(this: {
185
+ prototype: TModel;
186
+ }, count: number, callback: (models: TModel[]) => Promise<boolean | void>): Promise<void>;
187
+ static cursorPaginate<TModel extends object>(this: {
188
+ prototype: TModel;
189
+ }, options: {
133
190
  perPage: number;
134
191
  cursor?: unknown;
135
192
  }): Promise<{
136
- data: Array<Model<Record<string, unknown>, "id">>;
193
+ data: TModel[];
137
194
  meta: {
138
195
  per_page: number;
139
196
  next_cursor: unknown;
@@ -141,22 +198,46 @@ declare class Model<TEntity extends object, PrimaryKey extends keyof TEntity & s
141
198
  has_more: boolean;
142
199
  };
143
200
  }>;
144
- static whereHas(this: object, name: string, constrain?: (query: AnyRelationQuery) => void): ModelQuery;
145
- static has(this: object, name: string): ModelQuery;
146
- static doesntHave(this: object, name: string): ModelQuery;
147
- static whereDoesntHave(this: object, name: string, constrain?: (query: AnyRelationQuery) => void): ModelQuery;
148
- static find(this: object, id: unknown): Promise<Model<Record<string, unknown>, "id"> | null>;
149
- static findOrFail(this: object, id: unknown, errorFactory?: (id: unknown) => Error): Promise<Model<Record<string, unknown>, "id">>;
150
- static all(this: object, options?: Omit<QueryOptions<object>, "where">): Promise<Array<Model<Record<string, unknown>, "id">>>;
151
- static where(this: object, where: QueryWhere<object>): ModelQuery;
201
+ static whereHas<TModel extends object>(this: {
202
+ prototype: TModel;
203
+ }, name: string, constrain?: (query: AnyRelationQuery) => void): ModelQuery<TModel>;
204
+ static has<TModel extends object>(this: {
205
+ prototype: TModel;
206
+ }, name: string): ModelQuery<TModel>;
207
+ static doesntHave<TModel extends object>(this: {
208
+ prototype: TModel;
209
+ }, name: string): ModelQuery<TModel>;
210
+ static whereDoesntHave<TModel extends object>(this: {
211
+ prototype: TModel;
212
+ }, name: string, constrain?: (query: AnyRelationQuery) => void): ModelQuery<TModel>;
213
+ static find<TModel extends object>(this: {
214
+ prototype: TModel;
215
+ }, id: NoInfer<ModelIdentifier<TModel>>): Promise<TModel | null>;
216
+ static findOrFail<TModel extends object>(this: {
217
+ prototype: TModel;
218
+ }, id: NoInfer<ModelIdentifier<TModel>>, errorFactory?: (id: unknown) => Error): Promise<TModel>;
219
+ static all<TModel extends object>(this: {
220
+ prototype: TModel;
221
+ }, options?: Omit<QueryOptions<ModelAttributes<TModel>>, "where" | "select">): Promise<TModel[]>;
222
+ static where<TModel extends object>(this: {
223
+ prototype: TModel;
224
+ }, where: NoInfer<ModelWhere<ModelAttributes<TModel>>>): ModelQuery<TModel>;
152
225
  static count(this: object): Promise<number>;
153
226
  static pluck(this: object, column: string): Promise<unknown[]>;
154
227
  static pluck(this: object, column: string, keyBy: string): Promise<Map<unknown, unknown>>;
155
228
  static value(this: object, column: string): Promise<unknown>;
156
- static firstWhere(this: object, where: QueryWhere<object>, options?: Omit<QueryOptions<object>, "where">): Promise<Model<Record<string, unknown>, "id"> | null>;
157
- static firstOrNew(this: object, where: QueryWhere<object>, values?: Record<string, unknown>): Promise<Model<Record<string, unknown>, "id">>;
158
- static firstOrCreate(this: object, where: QueryWhere<object>, values?: Record<string, unknown>): Promise<Model<Record<string, unknown>, "id">>;
159
- static updateOrCreate(this: object, where: QueryWhere<object>, values?: Record<string, unknown>): Promise<Model<Record<string, unknown>, "id">>;
229
+ static firstWhere<TModel extends object>(this: {
230
+ prototype: TModel;
231
+ }, where: NoInfer<ModelWhere<ModelAttributes<TModel>>>, options?: Omit<QueryOptions<ModelAttributes<TModel>>, "where" | "select">): Promise<TModel | null>;
232
+ static firstOrNew<TModel extends object>(this: {
233
+ prototype: TModel;
234
+ }, where: NoInfer<ModelWhere<ModelAttributes<TModel>>>, values?: NoInfer<ModelWriteValues<ModelAttributes<TModel>>>): Promise<TModel>;
235
+ static firstOrCreate<TModel extends object>(this: {
236
+ prototype: TModel;
237
+ }, where: NoInfer<ModelWhere<ModelAttributes<TModel>>>, values?: NoInfer<ModelWriteValues<ModelAttributes<TModel>>>): Promise<TModel>;
238
+ static updateOrCreate<TModel extends object>(this: {
239
+ prototype: TModel;
240
+ }, where: NoInfer<ModelWhere<ModelAttributes<TModel>>>, values?: NoInfer<ModelWriteValues<ModelAttributes<TModel>>>): Promise<TModel>;
160
241
  save(): Promise<this>;
161
242
  update(changes: Partial<TEntity>): Promise<this>;
162
243
  delete(): Promise<boolean>;
@@ -182,5 +263,5 @@ declare class Model<TEntity extends object, PrimaryKey extends keyof TEntity & s
182
263
  /** Binds a Model class to its table/connection and names it for `hasMany("User")`. */
183
264
  declare function registerModelRepository<TModelClass>(model: TModelClass, repository: object): TModelClass;
184
265
  export { BelongsToManyRelationQuery, BelongsToRelationQuery, HasManyRelationQuery, HasManyThroughRelationQuery, HasOneRelationQuery, MorphManyRelationQuery, MorphOneRelationQuery, MorphToRelationQuery, } from "./relationQuery.ts";
185
- export type { CastType, GlobalScopeFn, ModelClassType, ModelConstructor };
186
- export { applyCasts, dehydrateValue, filterMassAssignable, hydrateValue, Model, ModelQuery, registerModelClass, registerModelRepository, };
266
+ export type { CastType, GlobalScopeFn, ModelAttributes, ModelClassType, ModelConstructor, ModelProjection, };
267
+ export { applyCasts, bootModels, defineModel, dehydrateValue, filterMassAssignable, hydrateValue, Model, ModelQuery, registerModelClass, registerModelRepository, };
@@ -10,8 +10,11 @@ declare class RepositoryQuery<TEntity extends object, PrimaryKey extends keyof T
10
10
  private queryOptions;
11
11
  private readonly eagerLoads;
12
12
  private readonly whereNodes;
13
+ private readonly protectedWhere;
13
14
  constructor(repository: BaseRepository<TEntity, PrimaryKey>, whereClause?: QueryWhere<TEntity>, queryOptions?: Omit<QueryOptions<TEntity>, "where">);
14
15
  where(input: QueryWhere<TEntity> | ((builder: WhereBuilder<TEntity>) => void)): this;
16
+ /** Preserve completed scope predicates separately from subsequent caller OR conditions. */
17
+ protectWhere(): this;
15
18
  orWhere(input: QueryWhere<TEntity> | ((builder: WhereBuilder<TEntity>) => void)): this;
16
19
  orderBy(orderBy: QueryOptions<TEntity>["orderBy"]): this;
17
20
  limit(limit: number): this;
@@ -31,7 +34,7 @@ declare class RepositoryQuery<TEntity extends object, PrimaryKey extends keyof T
31
34
  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;
32
35
  withMorphMany<TChild extends object, LocalKey extends keyof TEntity & string, MorphTypeKey extends keyof TChild & string, MorphIdKey extends keyof TChild & string, Alias extends string>(as: Alias, relation: MorphManyRelation<TEntity, TChild, LocalKey, MorphTypeKey, MorphIdKey>, childRepository: BaseRepository<TChild, keyof TChild & string>, options?: Omit<QueryOptions<TChild>, "where">): this;
33
36
  withMorphOne<TChild extends object, LocalKey extends keyof TEntity & string, MorphTypeKey extends keyof TChild & string, MorphIdKey extends keyof TChild & string, Alias extends string>(as: Alias, relation: MorphOneRelation<TEntity, TChild, LocalKey, MorphTypeKey, MorphIdKey>, childRepository: BaseRepository<TChild, keyof TChild & string>, options?: Omit<QueryOptions<TChild>, "where">): this;
34
- withMorphTo<TParent extends object, MorphTypeKey extends keyof TEntity & string, MorphIdKey extends keyof TEntity & string, Alias extends string>(as: Alias, relation: MorphToRelation<TEntity, MorphTypeKey, MorphIdKey>, repositoriesByType: ReadonlyMap<string, BaseRepository<TParent, keyof TParent & string>>, options?: Omit<QueryOptions<TParent>, "where">): this;
37
+ withMorphTo<TParent extends object, MorphTypeKey extends keyof TEntity & string, MorphIdKey extends keyof TEntity & string, Alias extends string>(as: Alias, relation: MorphToRelation<TEntity, MorphTypeKey, MorphIdKey>, repositoriesByType: ReadonlyMap<string, BaseRepository<TParent, keyof TParent & string>>, options?: Omit<QueryOptions<TParent>, "where">, optionsByType?: ReadonlyMap<string, QueryOptions<TParent>>): this;
35
38
  withBelongsToMany<TRelated extends object, Pivot extends object, ParentKey extends keyof TEntity & string, RelatedKey extends keyof TRelated & string, ForeignPivotKey extends keyof Pivot & string, RelatedPivotKey extends keyof Pivot & string, Alias extends string>(as: Alias, relation: BelongsToManyRelation<TEntity, TRelated, Pivot, ParentKey, RelatedKey, ForeignPivotKey, RelatedPivotKey>, relatedRepository: BaseRepository<TRelated, RelatedKey>, options?: Omit<QueryOptions<TRelated>, "where">): this;
36
39
  withHasManyThrough<TFar extends object, LocalKey extends keyof TEntity & string, SecondKey extends keyof TFar & string, Alias extends string>(as: Alias, relation: HasManyThroughRelation<TEntity, TFar, LocalKey, string, string, SecondKey>, farRepository: BaseRepository<TFar, keyof TFar & string>, options?: Omit<QueryOptions<TFar>, "where">): this;
37
40
  withTrashed(): this;
@@ -42,11 +45,23 @@ declare class RepositoryQuery<TEntity extends object, PrimaryKey extends keyof T
42
45
  pluck<K extends keyof TEntity & string>(column: K): Promise<Array<TEntity[K]>>;
43
46
  pluck<K extends keyof TEntity & string, KK extends keyof TEntity & string>(column: K, keyBy: KK): Promise<Map<TEntity[KK], TEntity[K]>>;
44
47
  value<K extends keyof TEntity & string>(column: K): Promise<TEntity[K] | null>;
48
+ /** Plain selected records, never complete entities or hydrated models. */
49
+ project<K extends keyof TEntity & string>(columns: readonly K[], limit?: number): Promise<Array<Pick<TEntity, K>>>;
45
50
  attachToRows(rows: readonly TEntity[]): Promise<Array<TEntity & LoadedRow>>;
46
51
  paginate(options: {
47
52
  page: number;
48
53
  perPage: number;
49
54
  }): Promise<PaginatedResult<TEntity>>;
55
+ chunk(count: number, callback: (rows: Array<TEntity & LoadedRow>) => Promise<boolean | void>): Promise<void>;
56
+ cursorPaginate(options: {
57
+ perPage: number;
58
+ cursor?: TEntity[PrimaryKey];
59
+ }): Promise<{
60
+ meta: import("../pagination/index.ts").CursorPaginationMeta<TEntity[PrimaryKey]>;
61
+ data: (TEntity & LoadedRow)[];
62
+ }>;
63
+ /** Compiled query filters for batched relationship loaders. */
64
+ getOptions(): QueryOptions<TEntity>;
50
65
  private buildOptions;
51
66
  private addJoin;
52
67
  private attach;