Skip to content

Latest commit

 

History

History
126 lines (96 loc) · 3.48 KB

README.md

File metadata and controls

126 lines (96 loc) · 3.48 KB

Nested Knex

Takes a knex.js query builder add select and return nested object with types using NestHydration. idea for types and runtime comes from io-ts module

Idea

I just wanted to get nested objects from knex.js, I did not like boilerplated ORMs.

ORMs build you query

one of the problems with ORMs is that you define your models and when it comes to relations you define them and connect all of them together but most of time you don't need to get all of the relationships. consider a post model like this

@Entity()
class Post {
  @PrimaryKey();
  id: number;

  @Column()
  body: string;

  @BelongsTo(type => Author)
  author? Author;
}


@Entity()
class Author {
  @PrimaryKey()
  id: number;

  @Column()
  name: string;
}

and you use the generic function to get data so maybe something like this Post.find({relations: ['author']}) then in another function you use Post.find() in the first it will populate the post.author but in the second one the author is null.

also knex.js is just a query builder, so you create your query and this library help you to get a nested object from it, but ORMs create complex sql queries to get data cause they are generic functions.

Runtime Type Check

right now I did not have time to write runtime check but the api is there I can work out the detail

so what if we query the database and we wanted a number but a gets a string or even worse get a null should we continue our work? even typescript cannot help us.

Getting Started

first install knex and drivers you want then you can install

npm install nested-knex

so we want to get an array of posts and every post have an author and a list of tags

import * as n from 'nested-knex';

n.array(
  n.type({
    id: n.number('post.id', { id: true }), //this for each row you should set an id
    title: n.string('post.title'),
    author: n.type({
      id: n.number('author.id', { id: true }),
      name: n.string('author.name'),
      email: n.nullableString('email'),
    }),
    tags: n.array(n.type({ id: n.number('tags.id'), label: n.string('tags.title') })),
  }),
)
  .withQuery(
    knex('post')
      .leftJoin('author', 'author.id', 'post.authorId')
      .leftJoin('tags', 'tags.postId', 'post.id'),
  )
  .then(records => {
    /*
        records will be like

        [
          {
            id:1,
            title: 'Test',
            author: {id: 1, name: 'Hadi Aliakbar', email: null},
            tags: [{id:1, label: 'test'}]
          },
          {
            id:2,
            title: 'Test2',
            author: {id: 2, name: 'Mohammad Hadi Aliakbar', email: "[email protected]"},
            tags: [{id:2, label: 'test2'}, {id:3, label: 'test3'}]
          }
        ]
        
      */
  });

and also we have types

instrospection

Implemented Types

Function Type
nullableType `{}
type {}
number number
string string
date date
boolean boolean
nullableNumber `number
nullableString `string
nullableDate `date
array []

RoadMap

  • run time type checks
  • default option
  • add a way to extend types
  • add intersection union and partial types