import { AllRequired, InferredType, KeysOf, Primitive } from 'tsds-tools'; /** * Unwrap T[] (and readonly T[]) to T. Leave non-arrays unchanged. */ type UnwrapArray = T extends readonly (infer U)[] ? U : T; /** * `[T]` tuple-wrap blocks distribution over unions, so `string | null` * is tested as a whole (primitive) instead of element-wise. */ type IsRelation = [T] extends [Primitive | null | undefined] ? false : [T] extends [object] ? true : false; /** * Depth counter. Index into Prev with current depth to get depth-1. * Tuple lookup is O(1) at type-check time. */ type Prev = [never, 0, 1, 2, 3, 4, 5]; /** * Recursive depth-capped nested key extractor. * Replaces NestedKeysOf and NestedKeysOf2 with a single body. */ type NestedKeysUpTo = Depth extends 0 ? never : { [Key in keyof AllRequired]: UnwrapArray[Key]> extends infer V ? IsRelation extends true ? `${Key & string}.${KeysOf & string}` | `${Key & string}.${NestedKeysUpTo & string}` : never : never; }[keyof AllRequired]; /** * Extracts nested paths for relations (1 level deep). * * @example * type Post = { id: string; author: User } * type User = { id: string; name: string } * type Result = NestedKeysOf * // Result = 'author.id' | 'author.name' */ export type NestedKeysOf = NestedKeysUpTo; /** * Extracts nested paths for 2 levels deep. * * @example * type Post = { id: string; author: User } * type User = { id: string; profile: UserProfile } * type UserProfile = { bio: string; age: number } * type Result = NestedKeysOf2 * // Result = 'author.id' | 'author.name' | 'author.profile.bio' | 'author.profile.age' */ export type NestedKeysOf2 = NestedKeysUpTo; /** * 1-level nested keys alias. */ export type AllNestedKeysOf = NestedKeysOf; /** * Combined 1+2 level nested keys. */ export type AllNestedKeysOf2 = NestedKeysOf2; /** * Get the leaf type at a nested path. * * @example * type Post = { id: string; author: User } * type User = { id: string; name: string } * type Result = TypeOfNested * // Result = string */ export type TypeOfNested = Path extends `${infer K}.${infer Rest}` ? K extends keyof AllRequired ? UnwrapArray[K]> extends infer V ? Rest extends keyof AllRequired ? AllRequired[Rest] : TypeOfNested : never : never : Path extends keyof AllRequired ? AllRequired[Path] : never; /** * Direct keys + 1-level nested. */ export type DirectOrNestedKeysOf = KeysOf | NestedKeysOf; /** * Direct keys + 1-level + 2-level nested. */ export type DirectOrNestedKeysOf2 = KeysOf | NestedKeysOf2; /** * True if T is a dotted path. */ export type IsNestedPath = T extends `${string}.${string}` ? true : false; /** * Extract the relation prefix of a dotted path. * * @example * RelationOf<'author.profile.bio'> // 'author.profile' */ export type RelationOf = Path extends `${infer Relation}.${infer _Field}` ? _Field extends `${string}.${string}` ? `${Relation}.${RelationOf<_Field>}` : Relation : never; /** * Nested 2-segment paths that END on a relation (not primitive leaf). * Used for whereJoin-style ops. */ export type NestedRelationKeysOf = { [Key in keyof AllRequired]: UnwrapArray[Key]> extends infer V ? IsRelation extends true ? { [Key2 in keyof AllRequired]: UnwrapArray[Key2]> extends infer V2 ? IsRelation extends true ? `${Key & string}.${Key2 & string}` : never : never; }[keyof AllRequired] : never : never; }[keyof AllRequired]; /** * Get the inferred entity type at a nested relation path * (unwrapped from array if needed). */ export type InferredNestedType = Path extends `${infer K}.${infer Rest}` ? K extends keyof AllRequired ? InferredNestedType, Rest> : never : Path extends keyof AllRequired ? InferredType : never; export {};