User model

Although the ultimate goal of the previous post is to make a signup page for our site, it would do little good now to accept information for new users: we don’t currently have any place to put it. Thus, the first step in signing up users is to make a data structure to capture and store their information.

Database migrations

Create the database configuration with generate database command.

~/sample_app $ trainjs generate database sqlite
      create  .sequelizerc
      create  config/database.json

The analogous command for making a model is generate model, which we can use to generate a User model with name and email attributes.

~/sample_app $ trainjs generate model User name:string email:string
	   create  app/models/user.js
	   create  db
	   create  db/migrate
	   create  db/migrate/20160119110300_create_users.js
	   create  test/models/user_test.js

Install all modules listed as dependencies in package.json

~/sample_app $ npm install

One of the results of the generate command is a new file called a migration. Migrations provide a way to alter the structure of the database incrementally, so that our data model can adapt to changing requirements. In the case of the User model, the migration is created automatically by the model generation script; it creates a user table with two columns, name and email

db/migrate/[timestamp]_create_users.js

module.exports = {
	up: function(migration, DataTypes, done) {
		// add altering commands here, calling 'done' when finished
		migration.createTable('user', {
			id: {
				type: DataTypes.INTEGER,
				primaryKey: true,
				autoIncrement: true
			},
			name: DataTypes.STRING,
			email: DataTypes.STRING,

			createdAt: DataTypes.DATE,
			updatedAt: DataTypes.DATE,
		});
		done();
	},
	down: function(migration, DataTypes, done) {
		// add reverting commands here, calling 'done' when finished
		done();
	}
}

Note that the name of the migration file is prefixed by a timestamp based on when the migration was generated. We can run the migration, known as migrating up, using the sequelize command

~/sample_app $ sequelize db:migrate
Loaded configuration file "config/database.json".
Using environment "development".
Using gulpfile /usr/lib/node_modules/sequelize-cli/lib/gulpfile.js
Starting 'db:migrate'...
Finished 'db:migrate' after 411 ms
== 20160119110300_create_users: migrating =======
== 20160119110300_create_users: migrated (0.272s)

Creating user objects

Using node console to explore data models.

~/sample_app $ node

Load config file and models file

> require('trainjs').initServer()

In the console session, we created a new user object with User.build

> User.build()

When called with no arguments, User.build returns an object with all NULL attributes. Now we created a user with name and email attributes.

> var user = User.build({name: "Dang Thanh", email: "[email protected]"})
undefined
> user
{ dataValues: { id: null, name: 'Dang Thanh', email: [email protected]' },
...

User.build only creates an unsaved object. In order to save the User object to the database, we need to call the save method on the user variable.

> user.save()
Executing (default): INSERT INTO `user` (`id`,`name`,`email`,`updatedAt`,`createdAt`) VALUES (NULL,'Dang Thanh',[email protected]','2016-01-20 09:39:59.293 +00:00','2016-01-20 09:39:59.293 +00:00');

You may have noticed that the new user object had null values for the id and the magic columns createdAt and updatedAt attributes. Let’s see if our save changed anything

> user
{ dataValues:
   { id: 1,
	 name: 'Dang Thanh',
	 email: [email protected]',
	 updatedAt: Wed Jan 20 2016 16:39:59 GMT+0700 (ICT),
	 createdAt: Wed Jan 20 2016 16:39:59 GMT+0700 (ICT) },
	 ...

We see that the id has been assigned a value of 1, while the magic columns have been assigned the current time and date. As with the User class, instances of the User model allow access to their attributes using a dot notation

> user.name
'Dang Thanh'
> user.email
[email protected]'
> user.updatedAt
Wed Jan 20 2016 16:39:59 GMT+0700 (ICT)

We can create an user into one step with User.create

> User.create({name: "A Nother", email: "[email protected]"})
Executing (default): INSERT INTO `user` (`id`,`name`,`email`,`updatedAt`,`createdAt`) VALUES (NULL,'A Nother',[email protected]','2016-01-20 09:50:40.137 +00:00','2016-01-20 09:50:40.137 +00:00');
> var foo
undefined
> User.create({name: "Foo", email: "[email protected]"}).then(function(data){ foo = data })
Executing (default): INSERT INTO `user` (`id`,`name`,`email`,`updatedAt`,`createdAt`) VALUES (NULL,'Foo',[email protected]','2016-01-20 09:53:15.966 +00:00','2016-01-20 09:53:15.966 +00:00');

The inverse of create is destroy

> foo.destroy()
Executing (default): DELETE FROM `user` WHERE `id` = 3

Finding user objects

Sequelize provides several options for finding objects. Let’s use them to find the first user we created while verifying that the third user (foo) has been destroyed. We’ll start with the existing user

> User.findById(1).then(function(data){ console.log(data) })
{ dataValues:
   { id: 1,
	 name: 'Dang Thanh',
	 email: [email protected]',
	 createdAt: Wed Jan 20 2016 16:39:59 GMT+0700 (ICT),
	 updatedAt: Wed Jan 20 2016 16:39:59 GMT+0700 (ICT) },
	 ...

Here we’ve passed the id of the user to User.find; Sequelize returns the user with that id.

Let’s see if the user with an id of 3 still exists in the database

> User.findById(3).then(function(data){ console.log(data) })
null

Since we destroyed our third user, Sequelize can’t find it in the database.

Sequelize also allows us to find users by specific attributes

> User.findOne( { where: {email: "[email protected]"} } ).then(function(data){ console.log(data) })
{ dataValues:
   { id: 1,
	 name: 'Dang Thanh',
	 email: [email protected]',
	 createdAt: Wed Jan 20 2016 16:39:59 GMT+0700 (ICT),
	 updatedAt: Wed Jan 20 2016 16:39:59 GMT+0700 (ICT) },
	   ...

Updating user objects

Once we’ve created objects, we often want to update them. There are two basic ways to do this. First, we can assign attributes individually

> user
{ dataValues:
   { id: 1,
	 name: 'Dang Thanh',
	 email: [email protected]',
	 createdAt: Wed Jan 20 2016 16:39:59 GMT+0700 (ICT),
	 updatedAt: Wed Jan 20 2016 16:39:59 GMT+0700 (ICT) },
	   ...
> user.email = "[email protected]"
[email protected]'
> user.save()
Executing (default): UPDATE `user` SET `email`=[email protected]',`updatedAt`='2016-01-20 15:34:28.479 +00:00' WHERE `id` = 1

The second main way to update multiple attributes is to use update

> user.update({name: "The Dude", email: "[email protected]"})
Executing (default): UPDATE `user` SET `name`='The Dude',`email`=[email protected]',`updatedAt`='2016-01-20 15:36:21.866 +00:00' WHERE `id` = 1
> user.name
'The Dude'
> user.email
[email protected]'