# Models

# Defining SQL Models

To get started, let’s create a Users model. Models typically live in the app directory.

The easiest way to create a model instance is using the make-sql-model command:

node maker make-sql-model User

If you would like to generate a database migration when you generate the model, you may use the –migration or –m option:

 node maker make-sql-model User -m
              OR
 node maker make-sql-model User -migration

# SQL Model Conventions

Now, let’s look at an example User model, which we will use to retrieve and store information from our users database table:

# Examples

const Model = require("@elucidate/Model");

class User extends Model {
  static get tableName() {
    return "userTable";
  }
}

module.exports = User;

# SQL JSON Model Validation

Let's add a validation to our UserModel

const Model = require("@elucidate/Model");

class User extends Model {
  static get tableName() {
    return "userTable";
  }

  // Optional JSON schema. This is not the database schema!
  // No tables or columns are generated based on this. This is only
  // used for input validation. Whenever a model instance is created
  // either explicitly or implicitly it is checked against this schema.
  // See http://json-schema.org/ for more info.
  static get jsonSchema() {
    return {
      type: "object",
      required: ["firstName", "lastName"],

      properties: {
        id: { type: "integer" },
        parentId: { type: ["integer", "null"] },
        firstName: { type: "string", minLength: 1, maxLength: 255 },
        lastName: { type: "string", minLength: 1, maxLength: 255 },
        age: { type: "number" },

        // Properties defined as objects or arrays are
        // automatically converted to JSON strings when
        // writing to database and back to objects and arrays
        // when reading from database. To override this
        // behaviour, you can override the
        // Model.jsonAttributes property.
        address: {
          type: "object",
          properties: {
            street: { type: "string" },
            city: { type: "string" },
            zipCode: { type: "string" },
          },
        },
      },
    };
  }
}

module.exports = User;

# Relationships

Database tables are often related to one another. For example, a blog post may have many comments or an order could be related to the user who placed it.

  • One To One (BelongsToOneRelation)
  • One To Many (HasManyRelation)
  • Many To Many (ManyToManyRelation)

While relations are usually created between the primary key of one table and a foreign key reference of another table, ExpressWebJs has no such limitations. You can create relationship using any two columns (or any sets of columns). You can even create relation using values nested deep inside json columns.

# One To One (BelongsToOneRelation) Relation

BelongsToOneRelation: Use this relation when the source model has the foreign key

const Model = require("@elucidate/Model");

class User extends Model {
  static tableName = 'users';

  static relationMappings = {
    const Profile = require('./Profile');
    profile: {
      relation: Model.BelongsToOneRelation,
      modelClass: Profile,
      join: {
        from: 'user.id',
        to: 'profile.id'
      }
    }
  };
}

# One To Many (HasManyRelation) Relation

HasManyRelation: Use this relation when the related model has the foreign key

const Model = require("@elucidate/Model");

class Person extends Model {
  static tableName = 'persons';

  static relationMappings = {
    const Car = require('./Car');
    car: {
      relation: Model.HasManyRelation,
      modelClass: Car,
      join: {
        from: 'persons.id',
        to: 'car.ownerId'
      }
    }
  };
}

HasOneRelation: Just like HasManyRelation but for one related row

const Model = require("@elucidate/Model");

class Person extends Model {
  static tableName = 'persons';

  static relationMappings = {
    const Car = require('./Car');
    car: {
      relation: Model.HasOneRelation,
      modelClass: Car,
      join: {
        from: 'persons.id',
        to: 'cars.ownerId'
      }
    }
  };
}

# Many To Many (ManyToManyRelation) Relation

ManyToManyRelation: Use this relation when the model is related to a list of other models through a join table

const Model = require("@elucidate/Model");

class Person extends Model {
  static tableName = 'persons';

  static relationMappings = {
    const Movie = require('./Movie');
    movies: {
      relation: Model.ManyToManyRelation,
      modelClass: Movie,
      join: {
        from: 'persons.id',
        through: {
          // persons_movies is the join table.
          from: 'persons_movies.personId',
          to: 'persons_movies.movieId'
        },
        to: 'movies.id'
      }
    }
  };
}

HasOneThroughRelation: Use this relation when the model is related to a list of other models through a join table

const Model = require("@elucidate/Model");

class Person extends Model {
  static tableName = 'persons';

  static relationMappings = {
    const Movie = require('./Movie');
    movies: {
      relation: Model.HasOneThroughRelation,
      modelClass: Movie,
      join: {
        from: 'persons.id',
        through: {
          // persons_movies is the join table.
          from: 'persons_movies.personId',
          to: 'persons_movies.movieId'
        },
        to: 'movies.id'
      }
    }
  };
}