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:
cond could be another object that can contain another
relation/cond object and so on.
|
where({ |
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.
|
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) => { |
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;