* Join another table or subquery to the current query * * @param source - An object with a single key-value pair where the key is the table alias and the value is a Collection or subquery * @param onCallback - A function that receives table references and returns the join condition * @pa
(
source: TSource,
onCallback: JoinOnCallback<
MergeContextForJoinCallback<TContext, SchemaFromSource<TSource>>
>,
type: TJoinType = `left` as TJoinType,
)
| 260 | * .join({ p: postsCollection }, ({u, p}) => eq(u.id, p.userId)) |
| 261 | */ |
| 262 | join< |
| 263 | TSource extends Source, |
| 264 | TJoinType extends `inner` | `left` | `right` | `full` = `left`, |
| 265 | >( |
| 266 | source: TSource, |
| 267 | onCallback: JoinOnCallback< |
| 268 | MergeContextForJoinCallback<TContext, SchemaFromSource<TSource>> |
| 269 | >, |
| 270 | type: TJoinType = `left` as TJoinType, |
| 271 | ): QueryBuilder< |
| 272 | MergeContextWithJoinType<TContext, SchemaFromSource<TSource>, TJoinType> |
| 273 | > { |
| 274 | const [alias, from] = this._createRefForSource(source, `join clause`) |
| 275 | |
| 276 | // Create a temporary context for the callback |
| 277 | const currentAliases = this._getCurrentAliases() |
| 278 | const newAliases = [...currentAliases, alias] |
| 279 | const refProxy = createRefProxy(newAliases) as RefsForContext< |
| 280 | MergeContextForJoinCallback<TContext, SchemaFromSource<TSource>> |
| 281 | > |
| 282 | |
| 283 | // Get the join condition expression |
| 284 | const onExpression = onCallback(refProxy) |
| 285 | |
| 286 | // Extract left and right from the expression |
| 287 | // For now, we'll assume it's an eq function with two arguments |
| 288 | let left: BasicExpression |
| 289 | let right: BasicExpression |
| 290 | |
| 291 | if ( |
| 292 | onExpression.type === `func` && |
| 293 | onExpression.name === `eq` && |
| 294 | onExpression.args.length === 2 |
| 295 | ) { |
| 296 | left = onExpression.args[0]! |
| 297 | right = onExpression.args[1]! |
| 298 | } else { |
| 299 | throw new JoinConditionMustBeEqualityError() |
| 300 | } |
| 301 | |
| 302 | const joinClause: JoinClause = { |
| 303 | from, |
| 304 | type, |
| 305 | left, |
| 306 | right, |
| 307 | } |
| 308 | |
| 309 | const existingJoins = this.query.join || [] |
| 310 | |
| 311 | return new BaseQueryBuilder({ |
| 312 | ...this.query, |
| 313 | join: [...existingJoins, joinClause], |
| 314 | }) as any |
| 315 | } |
| 316 | |
| 317 | /** |
| 318 | * Perform a LEFT JOIN with another table or subquery |