Attributes

Overview

Model attributes are basic pieces of information about a model. A model called Person might have attributes called firstName, lastName, phoneNumber, age, birthDate and emailAddress.

Attribute Options

These options can be used to enforce various constraints and add special enhancements to our model attributes.

type

Specifies the type of data that will be stored in this attribute. One of:

  • string
  • text
  • integer
  • float
  • date
  • datetime
  • boolean
  • binary
  • array
  • json
email

Checks the incoming value for a valid email address.

attributes: {
  email: {
    type: 'string',
    email: true
  }
}
defaultsTo

When a record is created, if no value was supplied, the record will be created with the specified defaultsTo value.

attributes: {
  phoneNumber: {
    type: 'string',
    defaultsTo: '111-222-3333'
  }
}
autoIncrement

Sets up the attribute as an auto-increment key. When a new record is added to the model, if a value for this attribute is not specified, it will be generated by incrementing the most recent record's value by one. Note: Attributes which specify autoIncrement should always be of type: integer. Also, bear in mind that the level of support varies across different datastores. For instance, MySQL will not allow more than one auto-incrementing column per table.

attributes: {
  placeInLine: {
    type: 'integer',
    autoIncrement: true
  }
}
unique

Ensures no two records will be allowed with the same value for the target attribute. This is an adapter-level constraint, so in most cases this will result in a unique index on the attribute being created in the underlying datastore.

attributes: {
  username: {
    type: 'string',
    unique: true
  }
}
primaryKey

Use this attribute as the the primary key for the record. Only one attribute per model can be the primaryKey. Note: This should never be used unless autoPK is set to false.

attributes: {
  uuid: {
    type: 'string',
    primaryKey: true,
    required: true
  }
}
enum

A special validation property which only saves data which matches a whitelisted set of values.

attributes: {
  state: {
    type: 'string',
    enum: ['pending', 'approved', 'denied']
  }
}
size

If supported in the adapter, can be used to define the size of the attribute. For example in MySQL, size can be specified as a number (n) to create a column with the SQL data type: varchar(n).

attributes: {
  name: {
    type: 'string',
    size: 24
  }
}
columnName

Inside an attribute definition, you can specify a columnName to force Sails/Waterline to store data for that attribute in a specific column in the configured connection (i.e. database). Be aware that this is not necessarily SQL-specific-- it will also work for MongoDB fields, etc.

While the columnName property is primarily designed for working with existing/legacy databases, it can also be useful in situations where your database is being shared by other applications, or you don't have access permissions to change the schema.

To store/fetch your model's numberOfWheels attribute into/from the number_of_round_rotating_things column:

  // An attribute in one of your models:
  // ...
  numberOfWheels: {
    type: 'integer',
    columnName: 'number_of_round_rotating_things'
  }
  // ...

Now for a more thorough/realistic example.

Let's say you have a User model in your Sails app that looks like this:

// api/models/User.js
module.exports = {
  connection: 'shinyNewMySQLDatabase',
  attributes: {
    name: 'string',
    password: 'string',
    email: {
      type: 'email',
      unique: true
    }
  }
};

Everything works great, but instead of using an existing MySQL database sitting on a server somewhere that happens to house your app's intended users:

// config/connections.js
module.exports = {
  // ...

  // Existing users are in here!
  rustyOldMySQLDatabase: {
    adapter: 'sails-mysql',
    user: 'bofh',
    host: 'db.eleven.sameness.foo',
    password: 'Gh19R!?had9gzQ#Q#Q#%AdsghaDABAMR>##G<ADMBOVRH@)$(HTOADG!GNADSGADSGNBI@(',
    database: 'jonas'
  },
  // ...
};

Let's say there's a table called our_users in the old MySQL database that looks like this:

the_primary_key email_address full_name seriously_encrypted_password
7 [email protected] Mike McNeil ranchdressing
14 [email protected] Nick Crumrine thousandisland

In order to use this from Sails, you'd change your User model to look like this:

// api/models/User.js
module.exports = {
  connection: 'rustyOldMySQLDatabase',
  tableName: 'our_users',
  attributes: {
    id: {
      type: 'integer',
      unique: true,
      primaryKey: true,
      columnName: 'the_primary_key'
    },
    name: {
      type: 'string',
      columnName: 'full_name'
    },
    password: {
      type: 'string',
      columnName: 'seriously_encrypted_password'
    },
    email: {
      type: 'email',
      unique: true,
      columnName: 'email_address'
    }
  }
};

You might have noticed that we also used the tableName property in this example. This allows us to control the name of the table that will be used to house our data.