New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@uql/sqlite

Package Overview
Dependencies
Maintainers
1
Versions
114
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@uql/sqlite

Querier for TypeScript, ES2015+. Supports MySQL, PostgreSQL, MariaDB, MongoDB databases.

  • 0.4.5
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
16
decreased by-89.33%
Maintainers
1
Weekly downloads
 
Created
Source

build status coverage status npm version

{*} uql = Universal Query Language

uql is a plug & play ORM, with a declarative JSON syntax to query/update multiple data-sources. Essentially, you just declare what you want from the datasource, and then uql will run efficient (and safe) SQL (or Mongo) queries.

Given uql is just a small library with serializable JSON syntax, the queries can be written in the client (web/mobile) and send to the backend; or just use uql directly in the backend; or even use it in a mobile app with an embedded database.

:star2: Features

  • supports on-demand populate (at multiple levels), projection of fields/columns (at multiple levels), complex filtering (at multiple levels), sorting, pagination, and more.
  • declarative and programmatic transactions
  • entity repositories
  • different relations between the entities
  • supports inheritance patterns between the entities
  • connection pooling
  • supports Postgres, MySQL, MariaDB, SQLite, MongoDB (more coming)
  • code is performant, readable, and flexible
  • plugins for frameworks: express (more coming)

Table of Contents

  1. Installation
  2. Configuration
  3. Entities
  4. Declarative Transactions
  5. Programmatic Transactions
  6. Generate REST APIs from Express
  7. Consume REST APIs from Frontend
  8. FAQs

:battery: Installation

  1. Install the core package:

    npm install @uql/core --save
    

    or

    yarn add @uql/core
    
  2. Install one of database packages according to your database:

    • for MySQL (or MariaDB)

      npm install @uql/mysql --save
      

      or with yarn

      yarn add @uql/mysql
      
    • for PostgreSQL

      npm install @uql/postgres --save
      

      or with yarn

      yarn add @uql/postgres
      
    • for SQLite

      npm install @uql/sqlite --save
      

      or with yarn

      yarn add @uql/sqlite
      
    • for MongoDB

      npm install @uql/mongo --save
      

      or with yarn

      yarn add @uql/mongo
      
  3. Your tsconfig.json needs the following flags:

"target": "es6", // or a more recent ecmascript version
"experimentalDecorators": true,
"emitDecoratorMetadata": true

:gear: Configuration

uql initialization should be done once (e.g. in one of the bootstrap files of your app).

import { setOptions } from '@uql/core';
import { PgQuerierPool } from '@uql/postgres';

setOptions({
  querierPool: new PgQuerierPool({
    host: 'localhost',
    user: 'theUser',
    password: 'thePassword',
    database: 'theDatabase',
  }),
  logger: console.log,
  debug: true,
});

:egg: Entities

Take any dump class (aka DTO) and annotate it with the decorators from '@uql/core/entity/decorator'.

Note: inheritance between entities is optional.

import { v4 as uuidv4 } from 'uuid';
import { Id, Property, OneToMany, OneToOne, ManyToOne, Entity } from '@uql/core/entity/decorator';

/**
 * an abstract class can optionally be used as a template for the entities
 * (so boilerplate code is reduced)
 */
export abstract class BaseEntity {
  @Id({ onInsert: () => uuidv4() })
  id?: string;

  /**
   * 'onInsert' callback can be used to specify a custom mechanism for
   * obtaining the value of a property when inserting:
   */
  @Property({ onInsert: () => Date.now() })
  createdAt?: number;

  /**
   * 'onUpdate' callback can be used to specify a custom mechanism for
   * obtaining the value of a property when updating:
   */
  @Property({ onUpdate: () => Date.now() })
  updatedAt?: number;

  @Property()
  status?: number;
}

@Entity()
export class Company extends BaseEntity {
  @Property()
  name?: string;

  @Property()
  description?: string;
}

/**
 * a custom name can be specified for the corresponding table/document
 */
@Entity({ name: 'user_profile' })
export class Profile extends BaseEntity {
  /**
   * a custom name can be optionally specified for every property (this also overrides parent's class ID declaration)
   */
  @Id({ name: 'pk' })
  id?: string;

  @Property({ name: 'image' })
  picture?: string;
}

@Entity()
export class User extends BaseEntity {
  @Property()
  name?: string;

  @Property()
  email?: string;

  @Property()
  password?: string;

  @OneToOne({ mappedBy: 'user' })
  profile?: Profile;
}

@Entity()
export class TaxCategory extends BaseEntity {
  /**
   * Any entity can specify its own ID Property and still inherit the others
   * columns/relations from its parent entity.
   * 'onInsert' callback can be used to specify a custom mechanism for
   * auto-generating the primary-key's value when inserting
   */
  @Id({ onInsert: () => uuidv4() })
  pk?: string;

  @Property()
  name?: string;

  @Property()
  description?: string;
}

@Entity()
export class Tax extends BaseEntity {
  @Property()
  name?: string;

  @Property()
  percentage?: number;

  @ManyToOne()
  category?: TaxCategory;

  @Property()
  description?: string;
}

:speaking_head: Declarative Transactions

uql supports both, declarative and programmatic transactions, with the former you can just describe the scope of your transactions, with the later you have more flexibility (hence more responsibility).

  1. take any service class, annotate the wanted function with the Transactional() decorator.
  2. inject the querier instance by decorating one of the function's arguments with @InjectQuerier().
import { Querier } from '@uql/core/type';
import { Transactional, InjectQuerier } from '@uql/core/querier/decorator';

class ConfirmationService {

  @Transactional()
  async confirmAction(body: Confirmation,. @InjectQuerier() querier?: Querier): Promise<void> {
    if (body.type === 'register') {
      const newUser: User = {
        name: body.name,
        email: body.email,
        password: body.password,
      };
      await querier.insertOne(User, newUser);
    } else {
      const userId = body.user as string;
      await querier.updateOneById(User, userId, { password: body.password });
    }

    await querier.updateOneById(Confirmation, body.id, { status: CONFIRM_STATUS_VERIFIED });
  }
}

export const confirmationService = new ConfirmationService();

// then you could just import the constant `confirmationService` in another file,
// and when you call `confirmAction` function, all the operations there
// will (automatically) run inside a single transaction
await confirmationService.confirmAction(data);

:hammer_and_wrench: Programmatic Transactions

uql supports both, declarative and programmatic transactions, with the former you can just describe the scope of your transactions, with the later you have more flexibility (hence more responsibility).

  1. obtain the querier object with await getQuerier()
  2. open a try/catch/finally block
  3. start the transaction with await querier.beginTransaction()
  4. perform the different operations using the querier
  5. commit the transaction with await querier.commitTransaction()
  6. in the catch block, add await querier.rollbackTransaction()
  7. release the querier back to the pool with await querier.release() in the finally block.
import { getQuerier } from '@uql/core';

async function confirmAction(confirmation: Confirmation): Promise<void> {
  const querier = await getQuerier();

  try {
    await querier.beginTransaction();

    if (confirmation.entity === 'register') {
      const newUser: User = {
        name: confirmation.name,
        email: confirmation.email,
        password: confirmation.password,
      };
      await querier.insertOne(User, newUser);
    } else {
      // confirm change password
      const userId = confirmation.user as string;
      await querier.updateOneById(User, userId, { password: confirmation.password });
    }

    await this.querier.updateOneById(Confirmation, body.id, { status: CONFIRM_STATUS_VERIFIED });

    await querier.commitTransaction();
  } catch (error) {
    await querier.rollbackTransaction();
    throw error;
  } finally {
    await querier.release();
  }
}

:zap: Generate REST APIs from Express

uql provides a express plugin to automatically generate REST APIs for your entities.

  1. Install express plugin in your server project:
npm install @uql/express --save

or with yarn

yarn add @uql/express
  1. Initialize the express middleware in your server code to generate CRUD REST APIs for your entities
import * as express from 'express';
import { entitiesMiddleware } from '@uql/express';

const app = express();

app
  // ...other routes may go before and/or after (as usual)
  .use(
    '/api',
    // this will generate CRUD REST APIs for the entities.
    // all entities will be automatically exposed unless
    // 'include' or 'exclude' options are provided
    entitiesMiddleware({
      exclude: [Confirmation],
    })
  );

:globe_with_meridians: Consume REST APIs from Frontend

uql provides a client plugin to consume the REST APIs from the frontend.

  1. Install client plugin in your frontend project:
npm install @uql/client --save

or with yarn

yarn add @uql/client
  1. Use the client to call the uql CRUD API
import { querier } from '@uql/client';

// 'Item' is an entity class
const lastItems = await querier.find(Item, {
  sort: { createdAt: -1 },
  limit: 100,
});

:book: Frequently Asked Questions

Why uql if there already are GraphQL, TypeORM, Mikro-ORM, Sequelize?

GraphQL requires additional servers and also learning a new language; uql should allow same this, but without need to configure and maintaining additional components.

On the other hand, existing ORMs like TypeORM, Mikro-ORM, and Sequelize; are in one way or another, coupled to databases; uql uses a declarative JSON syntax (agnostic from the datasource) which can easily be serialized and send as messages (e.g. through the network) between different components of a system (e.g. micro-services), and then each one has the flexibility to decide how to process these messages.

At last but not at least, uql helps with the communication between the different tiers of your system, e.g. it allows the frontend to send dynamic requests to the backend (like GraphQL).

Keywords

FAQs

Package last updated on 15 May 2021

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc