Sequelize

 

by Thiago Bonfim @ Avenue Code
tbonfim@avenuecode.com

Sep 30th, 2014

AGENDA

  • Introduction - ORM
  • Sequelize
  • Installing
  • Connection
  • Models
    • Data Types
    • Getters & Setters
  • Validation
  • Finders
  • Instances
______________________________________________
Sequelize - A Node Js ORM library

AGENDA



  • Associations
  • Hooks
  • Raw SQL
  • DB Syncrhronization
  • Conclusion
  • Learn More
  • Challenge

______________________________________________
Sequelize - A Node Js ORM library

pre-requisites




Javascript - Intermediate

Notions of databases

Notions of Node.js


______________________________________________
Sequelize - A Node Js ORM library

ORM 



Object-Relational Mapping
A layer between the application and persistence

Avoid the need to write raw SQL
 SELECT * FROM Users WHERE id = 4
Become 
 user = Users.find(4);

______________________________________________
Sequelize - A Node Js ORM library

ORM



Another commercial solutions

  • EJB, Hibernate - Java
  • Doctrine - PHP
  • ADO.NET Entity Framework - .Net


______________________________________________
Sequelize - A Node Js ORM library

SEQUELIZE




"The Sequelize library provides easy access to MySQL, MariaDB, SQLite or PostgreSQL databases by mapping database entries to objects and vice versa"


______________________________________________
Sequelize - A Node Js ORM library

Sequelize


  • Entirely written in JavaScript

  • Can be used with Node.js


  •  
                    • MySQL
                    • SQLite
                    • PostgreSQL
                    • MariaDB

    ______________________________________________
    Sequelize - A Node Js ORM library

    Installing



    $ npm install sequelize
    $ npm install mysql 
    

    On your application you need to require the library

     var Sequelize = require("sequelize");
    ______________________________________________
    Sequelize - A Node Js ORM library

    Connection


    var sequelize = new Sequelize('db', 'username'[, 'password'] [,'options']);
    
    // You can also specify a non-default host/port
    var sequelize = new Sequelize('database', 'username', 'password', {
      host: "my.server",
      port: 12345
    });
    
    Using connection string:
     var sequelize = new Sequelize('mysql://user:pass@example.com:9821/dbname'[, 'options']);
    Options 

    ______________________________________________
    Sequelize - A Node Js ORM library

    Models



    • Represent tables
    var Book = sequelize.define('Book', {
      title: Sequelize.STRING,
      description: Sequelize.TEXT,
      publication: Sequelize.DATE
    });
    ______________________________________________
    Sequelize - A Node Js ORM library

    Models


    • You can set options on each column
    // Allow null, default value
    flag: { type: Sequelize.BOOLEAN, allowNull: false, defaultValue: true}
    
    // Unique values
    someUnique: {type: Sequelize.STRING, unique: true}
    
    // Primary Key 
    id: { type: Sequelize.INTEGER, primaryKey: true}
    
    // autoIncrement 
    increment: { type: Sequelize.INTEGER, autoIncrement: true }
    
    // comments - only for MySQL and PG
    hasComment: { type: Sequelize.INTEGER, comment: "Comment!" }
    
    ______________________________________________
    Sequelize - A Node Js ORM library

    Data types


    Sequelize.STRING(1234)                // VARCHAR(1234)
    Sequelize.STRING.BINARY               // VARCHAR BINARY
    Sequelize.TEXT                        // TEXT
    Sequelize.INTEGER                     // INTEGER
    Sequelize.BIGINT(11)                  // BIGINT(11)
    Sequelize.FLOAT(11, 12)               // FLOAT(11,12)
    Sequelize.DECIMAL(10, 2)              // DECIMAL(10,2)
    Sequelize.DATE                        // DATETIME for mysql/sqlite; TIMESTAMP
                                          // WTZ Postgres
    Sequelize.BOOLEAN                     // TINYINT(1)
    Sequelize.ENUM('value 1', 'value 2')  // ENUM
    Sequelize.ARRAY(Sequelize.TEXT)       // Defines an array. PostgreSQL only
    Sequelize.BLOB('tiny')                // Other options are medium and long
    Sequelize.UUID                        // UUID for PostgreSQL and SQLite,
                                          // CHAR(36) BINARY for MySQL
    
    ______________________________________________
    Sequelize - A Node Js ORM library

    Getters & setters



    • You can define the way to access your module values

      • Defining as part of a property:
     var Book = sequelize.define('Book', {
       title: {
        type     : Sequelize.STRING,
        get      : function()  {
                    return "Book title" 
                   },
        set      : function(value) { /*...*/}
      }
    });
    
    ______________________________________________
    Sequelize - A Node Js ORM library

    GETTERS & SETTERS


      • Defining as part of the model options
        var Book = sequelize.define('Book', {
            title:Sequelize.STRING  
            }
          }, 
          {
            getterMethods   : {
              title       : function()  {/* Return a value  */}
              },
            setterMethods   : {
              title       : function(v) { /*...*/ }
            }
        });
        
    ______________________________________________
    Sequelize - A Node Js ORM library

    GETTERS & SETTERS


    Helpers

    • getDataValue()

     function() {
        return this.getDataValue('title');
    }

    • setDataValue()

     function(title) {
        return this.setDataValue('title', title.toString().toLowerCase());
    }

    ______________________________________________
    Sequelize - A Node Js ORM library
    ______________________________________________
    Sequelize - A Node Js ORM library

    VALIDATION



    Property level:
    var Book= sequelize.define('Book', {
      title: {
        type: Sequelize.STRING,
        validate: {
          isAlphanumeric: true,
          notEmpty: true
        }
      }
    });

    ______________________________________________
    Sequelize - A Node Js ORM library

    VALIDATION


    Model Level
    var Contact = Sequelize.define('Contact', {
      name: { type: Sequelize.STRING },
      address1: { type: Sequelize.STRING },
      address2: { type: Sequelize.STRING },
        ,
    }, {
      validate: {
        atLeastOneAddress: function() {
          if ((this.address1 === "") && (this.address2 === "")) {
            throw new Error('Require at least one address');
          }
        }
      }
    })
    

    ______________________________________________
    Sequelize - A Node Js ORM library

    VALIDATION

    Built-in validators
          is: /^[a-z]+$/i,          // RegExp
          not: ["[a-z]",'i'],       // will not allow letters
          isEmail: true,            // checks for email format (foo@bar.com)
          isUrl: true,              // checks for url format (http://foo.com)
          isAlpha: true,            // will only allow letters
          isNumeric: true           // will only allow numbers
          isInt: true,              // checks for valid integers
          isFloat: true,            // checks for valid floating point numbers
          isNull: true,             // only allows null
          len: [2,10],              // allow values with length between 2 and 10
          isDate: true,             // only allow date strings
          isAfter: "2011-11-05",    // allow date strings after a specific date
          isBefore: "2011-11-05",   // allow date strings before a specific date
          max: 23,                  // only allow values <= 23
          min: 23,                  // only allow values >= 23
          isCreditCard: true,       // check for valid credit card numbers

    ______________________________________________
    Sequelize - A Node Js ORM library

    VALIDATION

    Custom validators

      isEven: function(value) {
            if(parseInt(value) % 2 != 0) {
              throw new Error('Only even values are allowed!')
            }
         }
    Custom error messages
     isInt: {
      msg: "Must be an integer number of pennies"
    }

    ______________________________________________
    Sequelize - A Node Js ORM library

    Finders


    • find()
      • returns a single entry
    // search for a known id
    Project.find(123).success(function(project) {});
     
    // search for attributes
    Project.find({ where: {title: 'aProject'} }).success(function(project) {});
     
    // only select some attributes and rename one
    Project.find({
      where: {title: 'aProject'},
      attributes: ['id', ['name', 'title']]
    }).success(function(project) {});

    ______________________________________________
    Sequelize - A Node Js ORM library

    FINDERS


    • findOrCreate()
      • Check if an element exists and if not, create it

     User.findOrCreate(
             { username: 'tbonfim' }, 
             { fullname: 'Thiago Bonfim' })
         .success(function(user, created) {});
    

    The success callback function will receive the retrieved/created user and the flag 'created' 
    ______________________________________________
    Sequelize - A Node Js ORM library

    FINDERS


    • findAndCountAll()
      • Returns an object with two properties, the total number of records and an array of objects containing the records
        Project.findAndCountAll({
             where: ["title LIKE 'NodeJS%'"]
          })
          .success(function(result) {
            /* result.count and result.rows */
        });
    ______________________________________________
    Sequelize - A Node Js ORM library

    FINDERS

    • findAll()
      • Search for multiple elements in the database
        Project.findAll().success(function(projects) {
          // returns all instances of projects
        });
        
        // Using where
        Project.findAll({
          where: {
            id: {
              gt: 6,              // id > 6  gte: 6  // id >= 6
              lt: 1,             // id < 1 lte: 1, // id <= 1
              ne: 20,             // id != 20
              between: [6, 10],   // BETWEEN 6 AND 10
              nbetween: [11, 15]  // NOT BETWEEN 11 AND 15
            }
          }
        });
        

    ______________________________________________
    Sequelize - A Node Js ORM library

    FINDERS

    • count()
       Project.count([where]).success(function(c) {});
    • max()
       Project.max('Column', [where]).success(function(max) {});
    • min()
       Project.min('Column', [where]).success(function(min) {});
    • sum()
       Project.sum('Column', [where]).success(function(sum) {});
    ______________________________________________
    Sequelize - A Node Js ORM library

    Instances


    • build()
      • Create an unsaved object
    var Task = sequelize.define('Project', {
      title: Sequelize.STRING,
      rating: { type: Sequelize.STRING, defaultValue: 3 }
    });
     
    var task = Task.build({title: 'very important task'});
    Note: When you use build() you have to use the save() method to store values!
    ______________________________________________
    Sequelize - A Node Js ORM library

    INSTANCES

    • create()
      • create and store an instance
    Task.create({ 
                  title: 'Task 1', 
                  description: 'A hard task', 
                  deadline: new Date() })
               .success(function(task) {});
    
    You can define which attributes to set
    User.create({ username:'tbonfim', isAdmin:true}, [ 'username' ])    .success(function(user) { // only the attribute 'username' will be set});
    ______________________________________________
    Sequelize - A Node Js ORM library

    INSTANCES


    • save()
    task.title = 'Another title';
    task.save().success(function() {});
    You can also set the properties you want to save
    task.title = 'Another title';
    task.description = 'Very easy task';
    task.save(['title']).success(function() {
     // will only save title
    });

    ______________________________________________
    Sequelize - A Node Js ORM library

    INSTANCES

    • updateAttributes()
      • another way to update instance values

    task.updateAttributes({
      title: 'Another title'
    }, [<attributes to save>]).success(function() {});
    

  • As in save(), you can also specify which attributes to save
  • ______________________________________________
    Sequelize - A Node Js ORM library

    INSTANCES

    • destroy()
      • Delete an object from the database

     task.destroy().success(function() { });
    Can be used to delete multiple instances
     Task.destroy({ subject: 'programming'})
        .success(function(affectedRows){});
    

    ______________________________________________
    Sequelize - A Node Js ORM library

    INSTANCES

    • bulkCreate()
      • Create bulks of instances
    Task.bulkCreate([
      {subject: 'programming', status: 'executing'},
      {subject: 'reading', status: 'executing'},
      {subject: 'programming', status: 'finished'}
    ]).success(function() {});
    
    • update()
      • Update bulks of instances
     Task.update(
        {status: 'inactive'}, // set status = 'inactive'
        {subject: 'programming'} // where subject = 'programming'
      ).success(function(affectedRows) {});
    ______________________________________________
    Sequelize - A Node Js ORM library

    ASSOCIATIONS


    You can specify associations between multiple modules 
    Automatically create indexes to control the relationship between tables 

    • One-To-One
    • One-To-Many
    • Many-To-Many
    ______________________________________________
    Sequelize - A Node Js ORM library

    One-To-One associations


    Connect one source with exactly one target
    Methods belongsTo() and hasOne()

    var User = sequelize.define('User', {/* ... */});
    var Project = sequelize.define('Project', {/* ... */});
     
    // One-way associations, from Project to User
    Project.hasOne(User);
    // To get the association working from User to Project, we need to do this:
    User.belongsTo(Project);

    ______________________________________________
    Sequelize - A Node Js ORM library

    One-To-Many associations

    Connect one source with multiple targets
    Targets however are connected to only one source

    var User = sequelize.define('User', {/* ... */});
    var Project = sequelize.define('Project', {/* ... */});
     
    Project.hasMany(User, {as: 'Workers'});

    ______________________________________________
    Sequelize - A Node Js ORM library

    Many-To-Many associations

    Connect multiple resources with multiple targets
    Project.hasMany(User, { as: 'Workers' });
    User.hasMany(Project);
    
    Will create a new model called ProjectUsers
    You can specify the name of an existing join table
    Project.hasMany(User, {through: 'project_has_users'});
    User.hasMany(Project, {through: 'project_has_users'});
    You can also add attributes to the join table
    UserProjects = sequelize.define('UserProjects', {status: DataTypes.STRING});
    User.hasMany(Project, { through: UserProjects });
    Project.hasMany(User, { through: UserProjects });

    ______________________________________________
    Sequelize - A Node Js ORM library

    Associating objects

    After setting the associations, you will be able to use helper methods to access associated instances
    // many associations
    project.getTasks().success(function(associatedTasks) {});
    project.setTasks(tasks).success(function(associatedTasks) {});
    // one associations
    project.getTask().success(function(associatedTasks) {});
    project.setTask(task).success(function(associatedTasks) {});
    
    // add/ remove 
    project.removeTask(task).success(function() {}); 
    project.addTask(task).success(function() {});
    
    // checking associations
    project.hasUser(u).success(function(result){// result will be true or false});
    

    ______________________________________________
    Sequelize - A Node Js ORM library

    HOOKS

    Functions called before and after calls in Sequelize are executed

    beforeBulkCreate(daos, fields, fn)/ afterBulkCreate(daos, fields, fn)
    beforeBulkDestroy(daos, fields, fn)/ afterBulkDestory(daos, fields, fn)
    beforeBulkUpdate(daos, fields, fn)/ afterBulkUpdate(daos, fields, fn)
    beforeCreate(dao, fn)/ afterCreate(dao, fn)
    beforeDestroy(dao, fn)/ afterDestroy(dao, fn)
    beforeUpdate(dao, fn)/ afterUpdate(dao, fn)
    beforeValidate(dao, fn)/afterValidate(dao, fn)
    
    


    ______________________________________________
    Sequelize - A Node Js ORM library

    HOOKS


    var User = sequelize.define('User', {  username: DataTypes.STRING }, {  hooks: {
        beforeValidate: function(user, fn) {
          /*  fn(null, user); */
        }
      }
    });
    
    // another way to add a hook
    User.hook('beforeValidate', function(user, fn) {
      /*  fn(null, user); */
    }); 
    

    ______________________________________________
    Sequelize - A Node Js ORM library

    Executing raw SQL queries


    Sometimes its just easier to execute raw/ already existing  SQL queries

    • query()

    sequelize.query('query', [, model], [, options], [, replacements])
    .success(function(rows) {});
    

    ______________________________________________
    Sequelize - A Node Js ORM library

    Database synchronization


    Use Sequelize to create the needed database structure
    After defining models just call the method sync()
    Project.sync()
                  .success(function(){})
                  .error(function(error){});
    Project.sync({force: true}); // drop the table if exists and then create
    Project.drop();
    
    // Instead of synchronizing all of your models, you can use Sequelize to just
    // synchronize your database once:
    sequelize.sync()
                  .success(function(){})
                  .error(function(error){});
    sequelize.sync({force: true});
    sequelize.drop();
    

    ______________________________________________
    Sequelize - A Node Js ORM library

    CONCLUSION


    ORM solution is a must to have

    Sequelize is a mature solution

    Another solutions
    ______________________________________________
    Sequelize - A Node Js ORM library

    CONCLUSION


    ______________________________________________
    Sequelize - A Node Js ORM library

    Learn More



    Sequelize - Documentation, articles, blog...


    ______________________________________________
    Sequelize - A Node Js ORM library

    Challenge


    • Create 3 models with at least 3 attributes
    • Associate the models using at least one One-to-Many relationship and one Many-to-Many
    • Create multiple instances with sample data (you can choose creating one by one or bulk create)
    • Retrieve your instances by using one of the Finders using 'where' conditions
    • Destroy your instances
    • Send me your solution using a GitHub repository

    ______________________________________________
    Sequelize - A Node Js ORM library

    Sequelize

    By Thiago Oliveira Bonfim

    Sequelize

    A presentation about Sequelize, an ORM tool for Node.js

    • 4,712