![Coverage Status](https://coveralls.io/repos/C2FO/patio/badge.svg?branch=master)
![NPM](https://nodei.co/npm/patio.png?downloads=true)
Patio is a Sequel inspired query engine.
Installation
To install patio run
npm install comb patio
If you want to use the patio executable for migrations
npm install -g patio
Running Tests
To run the tests
grunt test
To run just the postgres tests
grunt test-pg
To run just the mysql tests
grunt test-mysql
Running Tests with Docker
In order to provide a consistent test environment and make it easier to test,
we have included a Dockerfile
and a docker-compose.yml
to make it easy to
test in an isolated environment. You can do so with:
docker-compose build
docker-compose up -d mysql postgres
sleep 10
docker-compose up patio
Why Use Patio?
Patio is different because it allows the developers to choose the level of abtraction they are comfortable with.
If you want to use the ORM functionality you can. If you don't you can just use the Database and Datasets as a querying API, and if you need to you can write plain SQL
Concepts
-
Model definitions are defined by the tables in the database.
As you add models the definition is automatically defined from the table definition. This is particularly useful when you want to define your model from a schema designed using another tool (i.e. ActiveRecord, Sequel, etc...)
-
Patio tries to stay out of your way when querying.
When you define a model you still have the freedom to do any type of query you want.
Only want certain columns?
MyModel.select("id", "name", "created").forEach(function(record){
});
You want to join with another table?
MyModel.join("otherTable", {id: patio.sql.identifier("myModelId"}).forEach(function(record){
});
You want to run raw SQL?
MyModel.db.run("select * from my_model where name = 'Bob'").all().chain(function(records){
});
You want to just query the database and not use a model?
var DB = patio.connect("pg://test:test@127.0.0.1:5432/test_db");
DB.from("myTable").filter({id: [1,2,3]}).all().function(records){
});
Getting Started
All the code for this example can be found here
-
Create a new database
PostgreSQL
psql -c "CREATE DATABASE reademe_example"
MySQL
mysql -e "CREATE DATABASE readme_example"
-
Create a migration
mkdir migration
patio migration-file -n createInitialTables ./migration
This will add a migration name createdInitialTables
in your migration directory.
-
Add the following code to your migration
module.exports = {
up: function (db) {
return db
.createTable("state", function () {
this.primaryKey("id");
this.name(String);
this.population("integer");
this.founded(Date);
this.climate(String);
this.description("text");
})
.chain(function () {
return db.createTable("capital", function () {
this.primaryKey("id");
this.population("integer");
this.name(String);
this.founded(Date);
this.foreignKey("stateId", "state", {key: "id", onDelete: "CASCADE"});
});
});
},
down: function (db) {
return db.dropTable("capital", "state");
}
};
-
Run your migration
patio migrate -v --camelize -u "<DB_CONNECTION_STRING>" -d ./migration
-
Connect and query!
var patio = require("patio");
patio.camelize = true;
patio.connect("pg://postgres@127.0.0.1:5432/readme_example");
var State = patio.addModel("state").oneToOne("capital");
var Capital = patio.addModel("capital").manyToOne("state");
State
.save({
name: "Nebraska",
population: 1796619,
founded: new Date(1867, 2, 4),
climate: "continental",
capital: {
name: "Lincoln",
founded: new Date(1856, 0, 1),
population: 258379
}
})
.chain(function () {
return Capital.save({
name: "Austin",
founded: new Date(1835, 0, 1),
population: 790390,
state: {
name: "Texas",
population: 25674681,
founded: new Date(1845, 11, 29)
}
});
})
.chain(function () {
return State.order("name").forEach(function (state) {
return state.capital.chain(function (capital) {
console.log("%s's capital is %s.", state.name, capital.name);
});
});
})
.chain(process.exit, function (err) {
console.log(err)
process.exit(1);
});
Guides
Features
- Comprehensive documentation with examples.
- > 80% test coverage
- Support for connection URIs
- Supported Databases
- Models
- Simple adapter extensions
- Migrations
- Integer and Timestamp based.
- Powerful Querying API
- Transactions with
- Savepoints
- Isolation Levels
- Two phase commits
- SQL Datatype casting
- Full database CRUD operations