/boost

Primary LanguageTypeScript

Boost

Boost is a boilerplate code for node.js typescript applications. All the templates contain __boostorm folder in src with code for dealing with sql queries into rDB. Boost allows to import schema from database, build typescript types of all the entities and construct sql queries with strongly typed methods of the query builder. It provide as with tools for debugging queries.

Usage

First, create local.json file in config folder and organise it as example.json in the same folder. Set appropriate config parameters for DB connection.

Then import schema and build types.

yarn schema

Then organise repository folder. Implement your repositories in accordance with examples.

import { Repository, RepositoryOpts, SubSelect, Eq, OrderBy, JoinWhere, NotIn, In } from "../../__boostorm";
import { R } from '../__decorator/R'
import { RepoType } from '..'

class NewsRepository extends Repository {
    constructor(opts: RepositoryOpts) {
        super(opts)
        this.fetchProviderNews = this.fetchProviderNews.bind(this)
        this.fetchGlobalNews = this.fetchGlobalNews.bind(this)
    }

    @R('fetchProviderNews', {
        'id': [1],
        'limit': 1,
        'offset': 0
    })
    public async fetchProviderNews(args: RepoType['fetchProviderNews']['params']): Promise<RepoType['fetchProviderNews']['response']> {
        return await this.fetch({
            'table': 'news',
            'join': {
                'table': 'news_provider_link',
                'where': (c) => JoinWhere(c.news_provider_link, { 'provider_id': In(args.id) }),
                'select': 'providers',
                join: {
                    table: 'provider',
                    'where': (c) => JoinWhere(c.provider, { 'delete_date': null })
                }
            },
            where: {
                delete_date: null
            },
            'limit': args.limit,
            'offset': args.offset,
            'orderBy': (c) => OrderBy(c, 'id', 'desc')
        })
    }

    @R('fetchGlobalNews', {
        'id': [1],
        'limit': 1,
        'offset': 0
    })
    public async fetchGlobalNews(args: RepoType['fetchGlobalNews']['params']): Promise<RepoType['fetchGlobalNews']['response']> {
        return await this.fetch({
            'table': 'news',
            where: {
                delete_date: null,
                id: NotIn({
                    subSelect: SubSelect({
                        'from': 'news_provider_link',
                        'select': {
                            columns: ['news_id']
                        },
                        limit: 'infinity',
                        offset: 0
                    })
                })
            },
            'limit': args.limit,
            'offset': args.offset,
            'orderBy': (c) => OrderBy(c, 'id', 'desc')
        })
    }
}


export default NewsRepository

Add repositories and its methods here for making db requests via compact calling of repository('methodName', {methodParams}) function.

import { Repository as R } from '../__boostorm'
import Pg, { Executor } from '../__boostorm/Connection'
import { _Client, _Account, _Provider } from '../__boostorm/entities'
import NewsRepository from './repository/news'
import { Repository } from '../__boostorm/types'
import { FetchGlobalNewsReturn, FetchProviderNewsReturn } from './return'
import schema, { Schema } from '../__boostorm/Schema';

export interface RepoType {

    ///News
    fetchProviderNews: {
        params: PickAsArray<_Provider, 'id'> & { limit: number, offset: number },
        response: FetchProviderNewsReturn
    }
    fetchGlobalNews: {
        params: PickAsArray<_Provider, 'id'> & { limit: number, offset: number },
        response: FetchGlobalNewsReturn
    }
}




export const repo: { [T in keyof RepoType]: (ex: Executor) => (args: RepoType[T]['params']) => Promise<RepoType[T]['response']> } = {
    'fetchProviderNews': (ex) => (new NewsRepository({ schema, executor: ex })).fetchProviderNews,
    'fetchGlobalNews': (ex) => (new NewsRepository({ schema, executor: ex })).fetchGlobalNews,
}

export const repository: Repository = async (name, params) => {
    const request = { ...repo as any }[name]
    try {
        return await request(Pg.execute)(params)
    }
    catch (err) {
        throw err
    }
}



export const repositoryOpen = (executor: Executor): Repository => async (name, params) => {
    const request = { ...repo as any }[name]
    try {
        return await request(executor)(params)
    }
    catch (err) {
        throw err
    }
}


export const rootRep = new R({
    schema,
    executor: Pg.execute
})

export const rootRepOpen = (ex: Executor) => new R({
    schema,
    executor: ex
})

Decorate repository methods with R decorator and provide it with arguments for test call.

@R('fetchGlobalNews', {
        'id': [1],
        'limit': 1,
        'offset': 0
    })
public async fetchGlobalNews(args: RepoType['fetchGlobalNews']['params']): Promise<RepoType['fetchGlobalNews']['response']> {
        return await this.fetch({
            'table': 'news',
            where: {
                delete_date: null,
                id: NotIn({
                    subSelect: SubSelect({
                        'from': 'news_provider_link',
                        'select': {
                            columns: ['news_id']
                        },
                        limit: 'infinity',
                        offset: 0
                    })
                })
            },
            'limit': args.limit,
            'offset': args.offset,
            'orderBy': (c) => OrderBy(c, 'id', 'desc')
        })
}

Run

yarn return

to build return types of decorated query methods. Types will be generated and placed into return.d.ts file.

You can pass true into third argument of R to debug decorated method.

@R('fetchGlobalNews', {
        'id': [1],
        'limit': 1,
        'offset': 0
    }, true)

and run

yarn debug

to print out generated sql.

Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

Please make sure to update tests as appropriate.

License

MIT