Get Started

Oraios Queries is a light-weighted project aims to create an ORM for Databases queries (especially Relational Databases that performs flexible WHERE statements) to help developers create model classes for tables and query them using functions rather than plain string that is error-prune once the query start to gets a little long.

Currenlty, the package supports Postgres and Mysql

Installation

            
              $ npm install --save oraios-queries
            
          

Configuration

Connect to your database using pg or mysql2 package, then attach your connection with node-db-models:

Postgres

            
              const Pg = require("pg");
              const { Connection } = require('oraios-queries');
              
              //pg package init
              let pgModConn = new Pg.Pool({
                host: '127.0.0.1',
                user: 'admin',
                database: 'sampledb',
                password: '*******',
                port: 5432
              });

              //oraios init :)
              let conn = new Connection({
                connection: pgModConn,
                type: 'pg'
              });
            
          

MySQL

              
                const mysql = require('mysql2');
                const { Connection } = require('oraios-queries');

                //mysql2 package init
                const mysqlConn = mysql.createPool({
                  host: '127.0.0.1',
                  user: 'admin',
                  password: '*****',
                  database: 'sampledb',
                  waitForConnections: true,
                  connectionLimit: 10,
                  queueLimit: 0
                });

                //oraios init :)
                let conn = new Connection({
                  connection: mysqlConn,
                  type: 'mysql'
                });
              
            

Creating an object for the connection enables multiple db connections.

Models

Let's create models for our databse tables that will extend Model class that we imported above:

          
            const { Model, Util } = require('oraios-queries');

            class Post extends Model {
              tableName = 'posts';
              allowHtml = ['body'];
              selectable = ['title', 'body', 'author_id', 'created_at::date'];
              connection = conn;
              primaryKey = 'uuid'; //optional, default value is 'id'
              
              //optional default values setup
              defaultValue = {
                onInsert: {
                    created_at: Util.timestamp(),
                    updated_at: Util.timestamp()
                },
                onUpdate: {
                    updated_at: Util.timestamp()
                }
              }
            }

            module.exports = new Post();
          
        
Field Description Is Required?
tableName The name of the table which this class represents. YES
connection Pass the connection object after initiating new Connection(). YES
allowHtml Oraios strip html tags from all fields before storing to DB. If you do not want that for certain tags include them in this array. NO
selectable Select those column by default when select() method is not invoked. If not used SELECT * will be implemented. NO
defaultValue If you want to add values that will be inserted automatically on insert or update, you can use this field. Optimal situation of using this field would be changing or saving created_at and updated_at columns with current timestamp NO
primaryKey Identifies the primary key of this table in case it's not id. By default, it is set as id. NO

Query Builders

Now since you created your model(s). It's time to import the object of that class and start building queries:

          
            const post = require('./post.js');
            let postQuery = post.select(['title', 'body', 'created_at::date'])
                .where(["created_at", ">", "2019-01-01" ]);
            //some code ..
            postQuery = postQuery.orderBy([
                        {col: 'id', order: 'desc'}
                ]);
          
        

The above code builds your query, but does not execute it. You are free to chain to add to the query. You can use one of the following:

Methods Description Example
select(columns) Passes an array of columns to your query builder. select(['title', 'body', 'created_at::date'])
where(conditions) Accepts 2 cases:
  • One condition: this will be an array ["column", "operand", "value" ].
    Supported operands are =, ≠, >, ≥, <, ≤, like, ilike, in & not in.
  • Multiple conditions: in this case, it will accept an object with first key is relation which could be 'AND' or 'OR'. The second is cond and this will be an array of conditions like the ones exist in the first case
One of the conditions inside cond could be another object that can contain another relation/cond object and so on.
where({
relation: 'OR',
cond:[
['id', '=', 1],
['id', '=', 1]
]})
orderBy(orderList) Accepts an array of objects where you can add a list of order columns and order directions orderBy([{col: 'id', order: 'desc'},{col: 'created_at', order: 'asc'}])
groupBy(groupList) Accepts a list of columns you can group by groupBy(['author_id', 'post_id'])
set(values) A key value pairs of data that will be inserted or updated. Used only with insert and update. set({title: 'another blog post'})
setMany(values_list) A list of key value pairs of data that will be inserted as bulk of rows. Used only with insert. setMany([{title: 'blog post'}, {title: 'another blog post'}])
innerJoin(m, l, r)
leftJoin(m, l, r)
rightJoin(m, l, r)
The 3 methods performs inner, left and right joins (respectively) between the current model and another model.
  • (m) should be a Model object that you want join with.
  • (l) should be the column from the current model
  • (r) should be the column from the model that was added in the (m) parameter.
user.innerJoin(post, 'id', 'post_author')
toString() if included the query will not be executed. Instead, the query string will be returned. -

Query Executers

After the query is built, you are expected to chain a method that tells the query execution class how do you want the data to be returned.

          
            let postResults = await postQuery.list();
          
        

All the following methods return a promise:

Methods Description Example
list() Lists all results found in the form of array of objects. postQuery.list()
count() Counts the number of queried items. postQuery.count()
col(column_name) Returns an array of values of a certain column. postQuery.col('title')
listAfter(offset) Skip an offset amount of values and then list all values after it. postQuery.listAfter(5)
firstOne() Returns an object of the first row that meets conditions specified. postQuery.firstOne()
find(id) Returns an object of a certain model using it's id. postQuery.find(25)
slice(skip, count) Returns a count amount of rows after skipping another amount of rows. postQuery.slice(10, 10)
first(count) Return the first amount of rows that meets conditions specified. postQuery.first(10)
paginate(perPage, currentPage) Paginate through your results by passing rows per page and your current page. postQuery.paginate(10, 2)
chunk(count, callback) Instead of returning all elements in one chunk, you can process them in pieces using this method. You can pass the amount per chunk and the callback function to specify what you want to do for each chunk. postQuery.chunk(50, (rows) => {
//loop through a group of 50s
})
insert() Get chained after set(data) to insert data into database. The returned value is the id of the inserted row. post.set({title: 'sample title', body: 'sample body'}).insert()
update() Get chained after set(data) and a group of where() conditions to update certain rows in database. post.set({title: 'sample title', body: 'sample body'}).insert()
updateOrInsert() Tries to apply an update. If no rows get updated, then it will create a new row with the data to be updated. Make you that you are including all required columns. post.set({title: 'sample title', body: 'sample body'}).where(['id', '=', 5]).updateOrInsert()
delete() Get chained after a group of where() conditions to delete certain rows in database. post.where(['id', '=', 5]).delete()

Utilites

There are some utility functions that are provided to give your query more flexiblity:

          
            const { Util } = require('oraios-queries');

            let postQuery = post.select(['title', 'body', 'created_at::date'])
                .where(["created_at", ">", Util.raw("now() - INTERVAL '30 day'") ]);
          
        
Function Description Example
raw(sql) Added in the value section of a where statement to replace a matched value to native SQL code. Util.raw("now() - INTERVAL '30 day'")
distinct(col) Added as one of the selected columns in select() method to return only one unique value of this column. Basically, applies DISTINCT ON(). Util.distinct('author_id')
timestamp(Date date) This utility function returns a formatted timestamp YYYY-MM-dd hh:mm:ss That you can use in all kind of queries

The utilities is a new section that was just added in the latest version. More function is coming in the future.

Code Examples

Inserting new row to database:

          
            let insertedId = await post.set({title: 'blog post', body: 'Hello World'}).insert();
            if(insertedId){
                //success
            }
          
        

Inserting multiple rows to database:

          
            let insertedRows = await post.setMany([
                    {title: 'blog post', body: 'Hello World'},
                    {title: 'blog post 2', body: 'Hello Oraios'}
                ]).insert();
            if(insertedRows > 0){
                    //success
            }
          
        

Updating certain rows in database:

          
            let affectedRows = await post.set({title: 'another blog post'}).where(['id', '=', 25]).update();
            if(affectedRows !== 0){
                  //update successful
            }
          
        

Deleting a row in database:

          
            let rowDeleted = await post.where(['id', '=', 25]).delete();
            if(rowDeleted !== 0){
                //delete successful
            }
          
        

Find a row by id in database:

          
            let row = await post.find(25);
          
        

Chunk the data to loop through groups of data:

          
            let row = await post.find(25);
          
        

Perform a query with joins:

          
            let postQuery = post.list();
            await postQuery.chunk(50, (posts) => {
              for(const post of posts){
                console.log(`This is post #${post.id}`);
              }
            });
          
        

Select query with conditions using AND & OR with grouping:

          
            let conditions = nestedConditions = { cond: [] };

            conditions.relation = 'AND';
            conditions.cond.push(["created_at::date", ">", "2019-01-01" ]);
            conditions.cond.push(["author_id", "=", 25 ]);

            //include a nested condition
            nestedConditions.relation = 'OR';
            nestedConditions.cond.push(['created_at::date', ">", "2019-05-01"]);
            nestedConditions.cond.push(['created_at::date', "<", "2019-10-01"]);

            //add nested condition into the list of conditions
            conditions.cond.push(nestedConditions);
            let postQuery = post.select(['created_at::date', 'count(*) as posts'])
                  .where(conditions)
                  .groupBy(['created_at::date'])
                  .orderBy([{col: 'created_at::date', order: 'desc'}]);
                  
            let postRes = await postQuery.list();
          
        

The previous statement will produce a query like this:

          
            SELECT created_at::date, count(*) as posts 
            FROM posts 
            WHERE (
                    created_at::date > "2019-01-01" AND 
                    author_id, "=", 25 AND
                    (
                            created_at::date > "2019-05-01" OR
                            created_at::date < "2019-10-01"
                    )
            ) 
            GROUP BY created_at::date 
            ORDER BY created_at::date desc;