npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

patio

v4.2.1

Published

Patio query engine and ORM

Downloads

389

Readme

Build Status Coverage Status

NPM

Patio

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 # Wait for databases to come up
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

  1. 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...)

  2. 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){
        //record only has the id, name, and created columns
    });

    You want to join with another table?

    MyModel.join("otherTable", {id: patio.sql.identifier("myModelId"}).forEach(function(record){
        //Record has columns from your join table now!
    });

    You want to run raw SQL?

    MyModel.db.run("select * from my_model where name = 'Bob'").all().chain(function(records){
        //all records with a name that equals bob.
    });

    You want to just query the database and not use a model?

    var DB = patio.connect("pg://test:[email protected]:5432/test_db");
    DB.from("myTable").filter({id: [1,2,3]}).all().function(records){
       //records with id IN (1,2,3)
    });

Getting Started

All the code for this example can be found here

  1. Create a new database

    PostgreSQL

    psql -c "CREATE DATABASE reademe_example"

    MySQL

    mysql -e "CREATE DATABASE readme_example"
  2. Create a migration

    mkdir migration
    patio migration-file -n createInitialTables ./migration

    This will add a migration name createdInitialTables in your migration directory.

  3. Add the following code to your migration

    module.exports = {
        //up is called when you migrate your database up
        up: function (db) {
            //create a table called state;
            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 () {
                    //create another table called capital
                    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 is called when you migrate your database down
        down: function (db) {
            //drop the state and capital tables
            return db.dropTable("capital", "state");
        }
    };
  4. Run your migration

    patio migrate -v --camelize -u "<DB_CONNECTION_STRING>" -d ./migration
  5. Connect and query!

    var patio = require("patio");
    
    //set camelize = true if you want snakecase database columns as camelcase
    patio.camelize = true;
    patio.connect("pg://[email protected]:5432/readme_example");
    
    //define a State model with a relationship to capital
    var State = patio.addModel("state").oneToOne("capital");
    
    //define a Capital model with a relationship to State
    var Capital = patio.addModel("capital").manyToOne("state");
    
    //save a state
    State
        .save({
            name: "Nebraska",
            population: 1796619,
            founded: new Date(1867, 2, 4),
            climate: "continental",
            //notice the capital relationship is inline
            capital: {
                name: "Lincoln",
                founded: new Date(1856, 0, 1),
                population: 258379
            }
        })
        .chain(function () {
            //save a Capital
            return Capital.save({
                name: "Austin",
                founded: new Date(1835, 0, 1),
                population: 790390,
                //define the state inline
                state: {
                    name: "Texas",
                    population: 25674681,
                    founded: new Date(1845, 11, 29)
                }
            });
        })
        .chain(function () {
            //Query all the states by name
            return State.order("name").forEach(function (state) {
                //Get the associated capital
                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