@seanmcgary/database
Database boilerplate using Sequelize.
Install
yarn add @seanmcgary/database
Use
Usage caveats and notes due to some sequelize weirdness:
- Column and table names should be camelCased when used in JS/TS. Sequelize will automatically convert to/from snake_case since that is how things are represented in Postgres
-
createdAt
andupdatedAt
columns are automatically added for each table - Each table will automatically get a column called
id
which will be aSERIAL
type and set as the primary key. To override it, simple add anid
column manually and give it a type.
Example directory structure and files:
.
├── package.json
├── src
│ ├── db
│ │ └── index.ts
│ ├── migrations
│ │ └── 20180407084900-example-migration.ts
│ └── models
│ └── exampleUserModel.ts
├── tsconfig.json
└── yarn.lock
4 directories, 6 files
src/db/index.ts
import { DB, MigrationConfig, DBConfig } from '@seanmcgary/database';
import * as path from 'path';
import exampleUserModel from '../models/exampleUserModel';
const databaseConfig = {
username: 'some-username',
password: 'some-password',
database: 'example-db',
host: '127.0.0.1'
};
const migrationConfig = {
path: path.normalize(`${__dirname}/../migrations`)
};
const db = new DB(
<DBConfig>databaseConfig,
<MigrationConfig>migrationConfig
);
db.init((db: DB) => {
const User = db.setModel('User', db.loadModel(exampleUserModel));
});
db.migrate();
export default db;
src/models/exampleUserModel.ts
import { Sequelize, ModelOptions, Model, DataTypes, BuildOptions, ModelAttributes } from 'sequelize';
import { ModelWrapper, StaticModel, AllowedFields, FieldMessages } from '@seanmcgary/database';
export interface UserInstanceFields {
password: string;
username: string;
email: string;
}
// tslint:disable-next-line:no-any
export interface UserInstance extends UserInstanceFields, Model {
doesPasswordMatch(storedPassword: string, providedPassword: string): boolean;
toJSON(sanitize?: boolean): UserInstanceFields;
}
type UserInstanceStatic = StaticModel<UserInstance>;
export class User extends ModelWrapper<UserInstance, UserInstanceStatic> {
constructor(db: Sequelize, modelName: string, attributes: ModelAttributes, options: ModelOptions) {
super(db, modelName, attributes, options);
}
get allowedFields(): AllowedFields {
return {
create: ['email', 'password', 'username'],
update: ['email', 'password', 'username']
};
}
get fieldMessages(): FieldMessages {
return User.fieldMessages;
}
static get fieldMessages(): FieldMessages {
return {
email: {
invalid: 'Please provide a valid email address'
},
password: {
invalid: 'Password must be at least 8 characters'
},
username: {
invalid: 'Please provide a valid username',
unique: 'That username is already taken'
}
};
}
}
export default function(db: Sequelize): User {
return new User(db, 'users', {
email: {
type: DataTypes.STRING,
allowNull: true,
defaultValue: null,
validate: {
isEmail: true,
notEmpty: true
}
},
username: {
type: DataTypes.STRING,
allowNull: false,
validate: {
notEmpty: true,
len: [1, 128]
},
unique: true
},
password: {
type: DataTypes.STRING,
allowNull: false,
validate: {
len: [8, 255]
}
}
}, {
freezeTableName: true,
timestamps: true
});
}