question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Extend Find Options and Query Builder functionality

See original GitHub issue

The following code:

const qb = this.manager.createQueryBuilder(PostEntity, "post");

        if (filter.tagIds && filter.tagIds.length > 0)
            qb.innerJoin("post.tags", "tags", "tags.id IN (:...tagIds)")
                .setParameters({ tagIds: filter.tagIds });

        if (filter.conceptType)
            qb.innerJoin("post.tags", "tags", "tags.conceptType = :conceptType")
                .setParameters({ conceptType: filter.conceptType });

        if (filter.keyword)
            qb.andWhere("post.name ILIKE :name", { name: "%" + filter.keyword + "%" });

        if (filter.skipIds && filter.skipIds.length > 0)
            qb.andWhere("post.id NOT IN (:...skipIds)", { skipIds: filter.skipIds });

        if (filter.sortBy === "my" && this.sessionUser)
            qb.andWhere("post.authorId = :userId", { userId: this.sessionUser.personId });

        switch (filter.sortBy) {
            case "last":
                qb.orderBy("post.id", "DESC");
                break;
            case "popular":
                qb.orderBy("post.widgetCounter.score", "DESC");
                break;
            case "active":
                qb.orderBy("post.lastActiveDate", "DESC");
                break;
            default:
                qb.orderBy("post.id", "DESC");
        }

        if (filter.offset)
            qb.skip(filter.offset);

        if (filter.limit)
            qb.take(filter.limit);

        return qb;

can be translated into:

        return this.manager
            .createQueryBuilder(PostEntity, "post")
            .where({
                tags: {
                    id: If(filter.tagIds && filter.tagIds.length > 0, In(filter.tagIds)),
                    conceptType: If(filter.conceptType, filter.conceptType),
                },
                name: If(filter.keyword, Like("%" + filter.keyword + "%")),
                id: If(filter.skipIds && filter.skipIds.length > 0, Not(In(filter.skipIds))),
                authorId: If(this.sessionUser, this.sessionUser.personId)
            })
            .orderBy(Switch(filter.sortBy, {
                last: { id: "DESC" },
                popular: { widgetCounter: { score: "DESC" } },
                active: { lastActiveDate: "DESC" },
                _: { id: "DESC" },
            }))

This functionality is an extension of find options and will work with find operators as well.

Issue Analytics

  • State:open
  • Created 5 years ago
  • Reactions:16
  • Comments:18 (12 by maintainers)

github_iconTop GitHub Comments

15reactions
pleerockcommented, May 11, 2018

Here is what I have done at the moment:

import {FindOperator} from "./FindOperator";

export type FindOptionsOrderByValue = "ASC" | "DESC" | "asc" | "desc" | 1 | -1 | {
    direction?: "asc"|"desc"|"ASC"|"DESC";
    nulls?: "first"|"last"|"FIRST"|"LAST";
};

export type FindOptionsOrderBy<E> = {
    [P in keyof E]?:
        E[P] extends (infer R)[] ? FindOptionsOrderBy<R> :
        E[P] extends object ? FindOptionsOrderBy<E[P]> :
        FindOptionsOrderByValue;
};

export type FindOptionsRelation<E> = {
    [P in keyof E]?:
        E[P] extends (infer R)[] ? FindOptionsRelation<R> | boolean :
        E[P] extends object ? FindOptionsRelation<E[P]> | boolean :
        boolean;
};

export type FindOptionsSelect<E> = {
    [P in keyof E]?:
        E[P] extends (infer R)[] ? FindOptionsSelect<R> | boolean :
        E[P] extends object ? FindOptionsSelect<E[P]> | boolean :
        boolean;
};

export type FindOptionsWhere<E> = {
    [P in keyof E]?:
        E[P] extends any[] ? FindOptionsWhere<E[P][number]> :
        E[P] extends (infer R)[] ? FindOptionsWhere<R> :
        E[P] extends object ? FindOptionsWhere<E[P]> :
        FindOperator<E[P]>|E[P]
};

export type FindExtraOptions = {
    eagerRelations?: boolean;
};

export type FindCacheOptions = {
    id?: any;
    milliseconds?: number;
};

export type FindOptions<E> = {
    select?: (keyof E)[]|FindOptionsSelect<E>;
    where?: FindOptionsWhere<E>;
    orderBy?: FindOptionsOrderBy<E>;
    relations?: (keyof E)[]|FindOptionsRelation<E>;
    cache?: boolean | number | FindCacheOptions;
    options?: FindExtraOptions;
};

export type FindManyOptions<E> = FindOptions<E> & {
    skip?: number;
    take?: number;
};

With following model:

export interface Post {

    id: number;
    title: string;
    author: {
        id: number;
        name: string;
    }
    tags: {
        id: number;
        name: string;
        questions: {
            id: number;
            name: string;
        }
    }[];

}

We’ll have following completely type-safe query:


const options: FindOptions<Post> = {
    select: {
        id: true,
        title: true,
        author: {
            name: true
        }
    },
    where: {
        id: 1,
        author: {
            name: "hello"
        },
        tags: {
            id: 1
        }
    },
    orderBy: {
        author: {
            id: "DESC"
        },
        tags: {
            id: "DESC"
        }
    },
    relations: {
        author: true,
        tags: {
            questions: true
        }
    }
};
8reactions
vlapocommented, Nov 5, 2018

@pleerock Do you want to cover “OR” operator in where statement? In your example I see only “AND”.

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to enable query builder for advanced filter/search in ...
In the Options dialog box, go to the Others tab, and check the Restore “Query Builder” tab in Outlook Advanced Find Dialog box,...
Read more >
Extend search functionality | Adobe Experience Manager
Extend the search capabilities of Adobe Experience Manager Assets ... Searching is done via the QueryBuilder interface so the search can be ...
Read more >
Custom query builder (extending the query builder) | Objection.js
You can extend the QueryBuilder returned by query(), relatedQuery(), $relatedQuery() and $query() methods (and all other methods that create a QueryBuilder) ...
Read more >
Customize Query Options with Data Query Builder
The OData expand options are added to the query by invoking the DataQueryBuilder expand API. This variadic method accepts a comma-separated ...
Read more >
Query options overview - OData | Microsoft Learn
The $search system query option allows clients to request items within a collection matching a free-text search expression. The $search query ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found