$ open source · GPL-3.0 — need a commercial license? imqueue.com →

AssociatedWith() function

Marks a field of a filter input as standing for an association rather than for a column.

Signature:

export declare function AssociatedWith(cb: () => IAssociated): (target: any, key: string) => any;

Parameters

Parameter

Type

Description

cb

() => IAssociated

Returns the association descriptor.

Returns:

(target: any, key: string) => any

A property decorator.

Remarks

This is what lets a caller's filter reach through a relation. query.toWhereOptions instantiates the input class, and any property it finds carrying one of these descriptors becomes a required include on the associated model, with the nested filter resolved against that model's own input class — recursively, so the nesting can go as deep as the input classes do. Without it the nested object would be treated as a column filter and produce a where clause on a column that does not exist.

Declare the field with declare, and do not instantiate the input class yourself. The descriptor lives on the prototype as a read-only, non-enumerable property, so a real field declaration would shadow it with undefined under useDefineForClassFields and the association would be silently ignored — and an assignment to it throws in strict mode. These classes are descriptions of a wire shape, not containers for one.

The thunk is resolved on first read rather than at decoration time, which is what makes it worth being a thunk: input classes and models routinely import each other, and a decorator body runs while those modules are still initialising, so resolving eagerly could capture undefined as the model. First read happens on the first query, by which point every module is loaded.

Example

export class PaymentListInput {
    @property(() => `number[] | ${FilterInput.name}`, true)
    declare public amount?: number[] | FilterInput;

    @property('PaymentTypeListInput', true)
    @AssociatedWith(() => ({
        model: PaymentType,
        input: PaymentTypeListInput,
    }))
    declare public paymentType?: PaymentTypeListInput;
}

// A filter of { paymentType: { name: 'card' } } now becomes a required join on
// PaymentType with the name filter applied there.
const options = query.toWhereOptions(filter, PaymentListInput);