( client: Client, dmmfModelName: string, modelAction: ModelAction, fluentPropName?: string, prevDataPath?: string[], prevUserArgs?: UserArgs, )
| 74 | * @returns |
| 75 | */ |
| 76 | export function applyFluent( |
| 77 | client: Client, |
| 78 | dmmfModelName: string, |
| 79 | modelAction: ModelAction, |
| 80 | fluentPropName?: string, |
| 81 | prevDataPath?: string[], |
| 82 | prevUserArgs?: UserArgs, |
| 83 | ) { |
| 84 | // we retrieve the model that is described from the DMMF |
| 85 | const dmmfModel = client._runtimeDataModel.models[dmmfModelName] |
| 86 | |
| 87 | // map[field.name] === field, basically for quick access |
| 88 | const dmmfModelFieldMap = dmmfModel.fields.reduce( |
| 89 | (acc, field) => ({ ...acc, [field.name]: field }), |
| 90 | {} as { [dmmfModelFieldName: string]: DMMF.Field }, |
| 91 | ) |
| 92 | |
| 93 | // we return a regular model action but proxy its return |
| 94 | return (userArgs?: UserArgs) => { |
| 95 | const callsite = getCallSite(client._errorFormat) |
| 96 | // ! first call: nextDataPath => [], nextUserArgs => userArgs |
| 97 | const nextDataPath = getNextDataPath(fluentPropName, prevDataPath) |
| 98 | const nextUserArgs = getNextUserArgs(userArgs, prevUserArgs, nextDataPath) |
| 99 | const prismaPromise = modelAction({ dataPath: nextDataPath, callsite })(nextUserArgs) |
| 100 | // TODO: use an unpacker here instead of ClientFetcher logic |
| 101 | // TODO: once it's done we can deprecate the use of dataPath |
| 102 | const ownKeys = getOwnKeys(client, dmmfModelName) |
| 103 | |
| 104 | // we take control of the return promise to allow chaining |
| 105 | return new Proxy(prismaPromise, { |
| 106 | get(target, prop: string) { |
| 107 | // fluent api only works on fields that are relational |
| 108 | if (!ownKeys.includes(prop)) return target[prop] |
| 109 | |
| 110 | // here we are sure that prop is a field of type object |
| 111 | const dmmfModelName = dmmfModelFieldMap[prop].type |
| 112 | const modelArgs = [dmmfModelName, modelAction, prop] as const |
| 113 | const dataArgs = [nextDataPath, nextUserArgs] as const |
| 114 | |
| 115 | // we allow for chaining more with this recursive call |
| 116 | return applyFluent(client, ...modelArgs, ...dataArgs) |
| 117 | }, |
| 118 | ...defaultProxyHandlers([...ownKeys, ...Object.getOwnPropertyNames(prismaPromise)]), |
| 119 | }) |
| 120 | } |
| 121 | } |
| 122 | |
| 123 | // the only accessible fields are relations to be chained on |
| 124 | function getOwnKeys(client: Client, dmmfModelName: string) { |
no test coverage detected