Skip to content

feat: add sequelize-ts-example #109

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jun 13, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ before_install:
- 'mv zookeeper-3.4.6/conf/zoo_sample.cfg zookeeper-3.4.6/conf/zoo.cfg'
- './zookeeper-3.4.6/bin/zkServer.sh start'
- mysql -e 'CREATE DATABASE IF NOT EXISTS `egg-sequelize-example-unittest`;'
- mysql -e 'CREATE DATABASE IF NOT EXISTS `egg-sequelize-ts-unittest`;'
install:
- npm i npminstall && npminstall
script:
Expand Down
1 change: 1 addition & 0 deletions sequelize-ts/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
typings/
9 changes: 9 additions & 0 deletions sequelize-ts/.sequelizerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
'use strict';

const path = require('path');

module.exports = {
config: path.join(__dirname, 'database/config.json'),
'migrations-path': path.join(__dirname, 'database/migrations'),
'seeders-path': path.join(__dirname, 'database/seeders'),
};
53 changes: 53 additions & 0 deletions sequelize-ts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# sequelize-ts-example

The [egg] example project that uses [egg-sequelize] plugin. It will show you how to use sequelize in egg project, use [migrations] to help you manage changes of database and use [factory-girl] to help you write test cases more maintainable.

## QuickStart

### Dependencies

- install mysql and create database

```bash
brew install mysql # macOS
brew service start mysql

mysql
> create database `egg-sequelize-ts-dev`;
> create database `egg-sequelize-ts-unittest`;
```

- install dependencies

```bash
npm install
```

### Start Server and Run Test

- prepare database structure

```bash
# for develop
npm run sequelize -- db:migrate
# for unittest
NODE_ENV=test npm run sequelize -- db:migrate
```

- start project

```bash
npm run dev
```

- run test

```bash
npm test
```

[egg]: https://eggjs.org
[egg-sequelize]: https://github.com/eggjs/egg-sequelize
[sequelize]: http://docs.sequelizejs.com/
[migrations]: http://docs.sequelizejs.com/manual/tutorial/migrations.html
[factory-girl]: https://github.com/aexmachina/factory-girl
53 changes: 53 additions & 0 deletions sequelize-ts/README.zh-CN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# sequelize-ts-example

这个 [egg] 示例项目示范如何使用 [egg-sequelize] 插件。它会展示如何在 egg 项目中使用 [sequelize] 连接数据库,使用 [migrations] 来管理数据结构变更,并通过 [factory-girl] 来编写更易于维护的测试用例。

## 快速开始

### 安装依赖

- 安装 mysql 并建立数据库

```bash
brew install mysql # macOS
brew services start mysql

mysql
> create database `egg-sequelize-ts-dev`;
> create database `egg-sequelize-ts-unittest`;
```

- 安装 node 依赖

```bash
npm install
```

### 启动和测试

- 执行 migration 执行数据变更

```bash
# for develop
npm run sequelize -- db:migrate
# for unittest
NODE_ENV=test npm run sequelize -- db:migrate
```

- 启动项目

```bash
npm run dev
```

- 运行测试

```bash
npm test
```

[egg]: https://eggjs.org
[egg-sequelize]: https://github.com/eggjs/egg-sequelize
[sequelize]: http://docs.sequelizejs.com/
[migrations]: http://docs.sequelizejs.com/manual/tutorial/migrations.html
[factory-girl]: https://github.com/aexmachina/factory-girl
44 changes: 44 additions & 0 deletions sequelize-ts/app/controller/post.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
'use strict';

import { Controller } from 'egg';

export default class PostController extends Controller {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个文件没看出 ts 跟 js 有啥差别。。。

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

对,controller 的写法 ts 跟 js 区别不大

async index() {
const ctx = this.ctx;
const query = {
limit: ctx.helper.parseInt(ctx.query.limit),
offset: ctx.helper.parseInt(ctx.query.offset),
};
ctx.body = await ctx.service.post.list(query);
}

async show() {
const ctx = this.ctx;
ctx.body = await ctx.service.post.find(ctx.helper.parseInt(ctx.params.id));
}

async create() {
const ctx = this.ctx;
const post = await ctx.service.post.create(ctx.request.body);
ctx.status = 201;
ctx.body = post;
}

async update() {
const ctx = this.ctx;
const id = ctx.params.id;
const updates = {
title: ctx.request.body.title,
content: ctx.request.body.content,
};
ctx.body = await ctx.service.post.update({ id, user_id: ctx.request.body.user_id, updates });
}

async destroy() {
const ctx = this.ctx;
const id = ctx.helper.parseInt(ctx.params.id);
const user_id = ctx.helper.parseInt(ctx.request.body.user_id);
await ctx.service.post.destroy({ id, user_id });
ctx.status = 200;
}
}
41 changes: 41 additions & 0 deletions sequelize-ts/app/controller/user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
'use strict';

import { Controller } from 'egg';

export default class UserController extends Controller {
async index() {
const ctx = this.ctx;
const query = {
limit: ctx.helper.parseInt(ctx.query.limit),
offset: ctx.helper.parseInt(ctx.query.offset),
};
ctx.body = await ctx.service.user.list(query);
}

async show() {
const ctx = this.ctx;
ctx.body = await ctx.service.user.find(ctx.helper.parseInt(ctx.params.id));
}

async create() {
const ctx = this.ctx;
const user = await ctx.service.user.create(ctx.request.body);
ctx.status = 201;
ctx.body = user;
}

async update() {
const ctx = this.ctx;
const id = ctx.helper.parseInt(ctx.params.id);
const body = ctx.request.body;
ctx.body = await ctx.service.user.update({ id, updates: body });
}

async destroy() {
const ctx = this.ctx;
const id = ctx.helper.parseInt(ctx.params.id);
await ctx.service.user.del(id);
ctx.status = 200;
}
}

7 changes: 7 additions & 0 deletions sequelize-ts/app/extend/helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default {
parseInt(str: string | number) {
if (typeof str === 'number') return str;
if (!str) return 0;
return parseInt(str) || 0;
},
}
32 changes: 32 additions & 0 deletions sequelize-ts/app/model/post.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
'use strict';

import { Application } from 'egg';

export default function(app: Application) {
const { STRING, INTEGER, DATE } = app.Sequelize;

const Post = app.model.define('post', {
id: {
type: INTEGER,
primaryKey: true,
autoIncrement: true,
},
title: STRING(30),
content: STRING(255),
user_id: INTEGER,
created_at: DATE(6),
updated_at: DATE(6),
});

return class extends Post {
static associate() {
app.model.Post.belongsTo(app.model.User, { as: 'user', foreignKey: 'user_id' });
}

static async findByIdWithUser(id: number, userId: number) {
return await this.findOne({
where: { id, user_id: userId },
});
}
}
}
24 changes: 24 additions & 0 deletions sequelize-ts/app/model/user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
'use strict';

import { Application } from 'egg';

export default function(app: Application) {
const { STRING, INTEGER, DATE } = app.Sequelize;
const User = app.model.define('user', {
id: {
type: INTEGER,
primaryKey: true,
autoIncrement: true,
},
name: STRING(30),
age: INTEGER,
created_at: DATE(6),
updated_at: DATE(6),
});

return class extends User {
static associate() {
app.model.User.hasMany(app.model.Post, { as: 'posts' });
}
}
}
8 changes: 8 additions & 0 deletions sequelize-ts/app/router.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
'use strict';

import { Application } from 'egg';

export default function(app: Application) {
app.resources('users', '/users', app.controller.user);
app.resources('posts', '/posts', app.controller.post);
}
46 changes: 46 additions & 0 deletions sequelize-ts/app/service/post.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
'use strict';

import { Service } from 'egg';
import { CreateOptions } from 'sequelize';

export default class Post extends Service {
async list({ offset = 0, limit = 10, user_id = undefined }: { offset: number; limit: number; user_id?: number }) {
return this.ctx.model.Post.findAndCountAll({
offset,
limit,
attributes: [ 'id', 'title', 'user_id', 'created_at', 'updated_at' ],
order: [[ 'created_at', 'desc' ], [ 'id', 'desc' ]],
where: user_id ? { user_id } : undefined,
});
}

async find(id: number) {
const post = await this.ctx.model.Post.findByPk(id, {
include: [{
model: this.ctx.model.User,
as: 'user',
attributes: [ 'id', 'name', 'age' ],
}],
});
if (!post) {
this.ctx.throw(404, 'post not found');
}
return post;
}

async create(post: CreateOptions) {
return this.ctx.model.Post.create(post);
}

async update({ id, user_id, updates }: { id: number; user_id: number; updates: object }) {
const post = await this.ctx.model.Post.findByIdWithUser(id, user_id);
if (!post) this.ctx.throw(404, 'post not found');
return post!.update(updates);
}

async destroy({ id, user_id }: { id: number; user_id: number }) {
const post = await this.ctx.model.Post.findByIdWithUser(id, user_id);
if (!post) this.ctx.throw(404, 'post not found');
return post!.destroy();
}
}
44 changes: 44 additions & 0 deletions sequelize-ts/app/service/user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
'use strict';

import { Service } from 'egg';
import { CreateOptions } from 'sequelize';

class User extends Service {
async list({ offset = 0, limit = 10 }: { offset: number; limit: number; }) {
return this.ctx.model.User.findAndCountAll({
offset,
limit,
order: [[ 'created_at', 'desc' ], [ 'id', 'desc' ]],
});
}

async find(id: number) {
const user = await this.ctx.model.User.findByPk(id);
if (!user) {
this.ctx.throw(404, 'user not found');
}
return user!;
}

async create(user: CreateOptions) {
return this.ctx.model.User.create(user);
}

async update({ id, updates }: { id: number; updates: object }) {
const user = await this.ctx.model.User.findByPk(id);
if (!user) {
this.ctx.throw(404, 'user not found');
}
return user!.update(updates);
}

async del(id: number) {
const user = await this.ctx.model.User.findByPk(id);
if (!user) {
this.ctx.throw(404, 'user not found');
}
return user!.destroy();
}
}

module.exports = User;
Loading