( query: QueryIR, ref: PropRef<any>, collection: Collection, )
| 330 | * `collection`, in which case the caller already knows the alias. |
| 331 | */ |
| 332 | export function followRef( |
| 333 | query: QueryIR, |
| 334 | ref: PropRef<any>, |
| 335 | collection: Collection, |
| 336 | ): { collection: Collection; path: Array<string>; alias?: string } | void { |
| 337 | if (ref.path.length === 0) { |
| 338 | return |
| 339 | } |
| 340 | |
| 341 | if (ref.path.length === 1) { |
| 342 | // This field should be part of this collection |
| 343 | const field = ref.path[0]! |
| 344 | // is it part of the select clause? |
| 345 | if (query.select) { |
| 346 | const selectedField = query.select[field] |
| 347 | if (selectedField && selectedField.type === `ref`) { |
| 348 | return followRef(query, selectedField, collection) |
| 349 | } |
| 350 | } |
| 351 | |
| 352 | // Either this field is not part of the select clause |
| 353 | // and thus it must be part of the collection itself |
| 354 | // or it is part of the select but is not a reference |
| 355 | // so we can stop here and don't have to follow it |
| 356 | return { collection, path: [field] } |
| 357 | } |
| 358 | |
| 359 | if (ref.path.length > 1) { |
| 360 | // This is a nested field |
| 361 | const [alias, ...rest] = ref.path |
| 362 | const aliasRef = getRefFromAlias(query, alias!) |
| 363 | if (!aliasRef) { |
| 364 | return |
| 365 | } |
| 366 | |
| 367 | if (aliasRef.type === `queryRef`) { |
| 368 | return followRef(aliasRef.query, new PropRef(rest), collection) |
| 369 | } else { |
| 370 | // This is a reference to a collection |
| 371 | // we can't follow it further |
| 372 | // so the field must be on the collection itself. |
| 373 | // Report the alias too: when the ref crossed a join, this is the source |
| 374 | // that actually holds the field (which may differ from the from clause). |
| 375 | return { collection: aliasRef.collection, path: rest, alias } |
| 376 | } |
| 377 | } |
| 378 | } |
nothing calls this directly
no test coverage detected