King Somto
10 Jan 2022
•
5 min read
So I got hired as a backend engineer my main task was to convert a legacy PHP codebase to typescript I know what you thinking they probably aren't paying you enough and maybe your right but am having fun and that’s what matters, building out the new system from the legacy system we have to carry over some old technology and one of them is the MySQL Database, am very conversant in creating MySQL query from my PHP days but this is 2021 we opted to use an ORM and what my CTO chose was objection.js
an amazing tool built on top of another ORM
called knex
, I would be going over what these tools are.
An Object Relational Mapping or ORM
is a technique usually bundled up in libraries for accessing relational databases using object-oriented programming
languages an example would be javascript. object Relational Mapping is a way for our application to manage relational databases like MYSQL
without us having to learn the query language it maps tables to model classes and instances of those models, it also supports multiple database languages so switching databases eg moving from MYSQL to POSTGRES won't be an issue because we have an ORM that supports all these databases.
Knex.js
(pronounced /kəˈnɛks/) is an SQL query builder for multiple query languages such as SQLite3 CockroachDB, Redshift, PostgreSQL, MariaDB, Oracle, MSSQL, MySQL
, and Amazon
designed to be flexible, portable, and easy to use. It supports queries being used as async-await
and also promises
and also some other cool things like making transactions and connection pooling.
Knex
is ...an interesting library because it is used as a foundation for other ORM libraries.
A good resource is a cheat sheet made by a guy named Rico Sta Cruz .
Objection.js
is an ORM focused on JavaScript that helps developers connect to query language databases to perform data manipulation fetch data and save data making it possible to use the full power of the underlying database without having to learn the query language.
Objection.js is regarded as an ORM but more accurately it’s a relational query builder that lets developers create simple to complex queries to databases, it provides all the tools for creating queries while exposing functions that help manipulate the data.
A fun fact like mentioned above objection.js is built on knex which means it has all the functionality ok knex and a bit more.it supports all databases supported by knex.
*It abstracts functionality from tools like knex to provide an easier interface to build queries.
*Makes building simple queries and also complex queries easier without learning the query language.
*Optional data validation that can be defined in a model class it us Let’s perform Optional operations on data being updated or added to the DB.
……. It’s a good tool I think I’ve proved my point.
Setting up we need to first generate our TS project
mkdir objection-tutorial
Cd objection-tutorial
npm init -y
npm install typescript --save-dev
That provides us with our typescript compiler to help us compile our Ts codebase to javascript.
Create a file called tsconfig.json
in our root directory and paste
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"lib": ["es6"],
"allowJs": true,
"outDir": "build",
"rootDir": "src",
"strict": true,
"noImplicitAny": true,
"esModuleInterop": true,
"resolveJsonModule": true
}
}
To do this we need to create an index.ts
file in the src
directory and paste
Now we have set up a Ts node project, the next step would be to set up our Objection
npm install objection knex
This installs Objection and Knex to our project.
We also need to install MySQL
in the project since it would be our database
npm install MySQL
This can be done in our index.ts file and called at the beginning of our application
const { Client } = require('pg');
const client = new Client();
Const dbName = “database”
Const createDBFunctioon async () => {
try{
await client.connect();
await client.query(`CREATE DATABASE ${dbName}`);
await client.end();
}catch{
}
}
createDBFunctioon()
This function tries to create our database and fails if it’s already created
This creates a way for us to create tables and alter changes towards them in a sequential manner, Knex helps us create files in our migration folder and also helps us run each migration sequentially.
To do this we need to add a command to our package.json
file
“make”:”knex migrate:make create_tasks_table”
Running this command generates a file in our migration folder and we can generate a file with the below content.
exports.up = function (knex, Promise) {
};
exports.down = function (knex, Promise) {
};
```
Making edits to the file we get this
```
exports.up = knex => {
// Create the tasks table
return knex.schema.createTable(tableName, table => {
table.increments('id').primary();
table.increments(‘name’);
table.string('item_id');
table.date('due_by');
table.boolean('is_done').defaultTo(false);
table.timestamps(true, true);
table.timestamps(true, true);
table.timestamps(true, true);
table.unique(['name']);
});
};
exports.down = knex => {
// Drop the tasks table
return knex.schema.dropTableIfExists(tableName);
};
```
To run our migration we add a new command to our package.json
`“make: migration”: “knex migrate:latest”`
This runs our migration and creates a table of loans in our database
### Models
Interacting with our `DB` we would need to make use of classes that extend the model class from objection, the model is like a schema or blueprint(actually both) of the DB column, we can define the table name, columns, and even primary column for our table.
The model class goes further to allow us to be able to perform actions to data before saving the data or updating (in short it's useful).
Create a folder called `moodels` i advice you to use the naming convention `table_name.model.ts`.
And paste the following example
```
import { mysqlDateTime } from '@/utils/util';
import { Model, ModelObject, StringReturningMethod } from 'objection';
export class LoanModel extends Model {
id: number;
item_id: number;
due_by: date;
is_done: boolean;
name: string;
static tableName = 'loans'; // database table name
static idColumn = 'id'; // id column name
$beforeInsert() {
////perform operations on data before adding
}
$beforeUpdate() {
////perform operations on data before updating
}
}
export type LoanShape = ModelObject<LoanModel>;
```
Here we have our simple model class able to let us manipulate data by fetching, updating, and adding new data (with a host of many others).
Now let's see how to use a model
There are 3 main basic operations we can create with the model, FETCH CREATE and UPDATE, lets look at them individually.
#### CREATE
Create uses our model to `insert` new data into the database lets look at an example
```
const exampleLoan = await LoanModel.query().insert({
item_id: 1;
due_by: new Date();
is_done: false;
name: ‘Example loan’;
});
console.log(exampleLoan instanceof LoanModel); // --> true
console.log(exampleLoan.name); // --> Example loan
console.log(jennifer.is_done()); // --> false
```#### FETCH
This helps us fetch items from our DB that match our query
```
const loans = await LoanModel.query();
console.log(loans[0] instanceof loan); // --> true
console.log('there are', loans.length, Loans in total');
```
#### UPDATE
We can here update our rows in the DB that match our current search query.
```
const loans = await LoanModel.query()
.patch({
is_done: false
});
```
#### Conclusion
Working with SQL databases can be stressful because we may have to work on a query language we don't know or understand `ORMs` like `objectiioon.js` help us build an interface around that, which enables us to be able to perform database operations without learning the language, best of all it Objection.js provides us with an interface for building queries very easily.
Ground Floor, Verse Building, 18 Brunswick Place, London, N1 6DZ
108 E 16th Street, New York, NY 10003
Join over 111,000 others and get access to exclusive content, job opportunities and more!