一些原则
- 过早优化乃万恶之源
- 如果没办法量化性能,就不要尝试优化性能
- 开发效率>可读性>运行效率
- 可用性>易用性>美观
永远不要删除数据
博客系统
- 用户可以登录,注册,注销。但是不可以重置密码
- 重置密码联系管理员
- 用户可以对博客进行增删改查
- 用户可以对博客进行评论,但不能修改评论
- 用户不可以编辑用户名密码姓名头像
- 可用性要求
- 手机上也能完成操作
其他要求
需求
- 简单的增删改查
- 主要表有users/posts/comments
- 主要数据
- user(id/username/password_digest)
- posts(id/user_id/title/content)
- comments(id/user_id/post_id/content)
- 其他
- 手机适配:一开始就设计两套界面PC+mobile
- SEO:多用SSG或SSR,少用BSR
代码
删除之前的容器
$ docker ps
$ docker kill xxx
$ docker rm xxx
创建新容器
docker run -v "blog-data":/var/lib/postgresql/data -p 5432:5432 -e POSTGRES_USER=blog -e POSTGRES_HOST_AUTH_METHOD=trust -d postgres:12.2

$ docker exec -it xxx bash
# psql -U blog
# /l
# drop database blog_development;
创建新数据库
$ CREATE DATABASE xxx ENCODING 'UTF8' LC_COLLATE 'en_US.utf8' LC_CTYPE 'en_US.utf8';
清空src内的entity和migration,清空dist文件夹
seed.tsx
import "reflect-metadata";import { createConnection } from "typeorm";createConnection().then(async connection => {connection.close()}).catch(error => console.log(error));
创建表
package.json写入命令
“migration:create”: “typeorm migration:create”,
或者简写成
“m:create”: “typeorm migration:create”, $ yarn m:create -n CreateUsers

1627888…..
import { MigrationInterface, QueryRunner, Table } from "typeorm";export class CreateUsers1627888334255 implements MigrationInterface {public async up(queryRunner: QueryRunner): Promise<void> {return await queryRunner.createTable(new Table({name: 'users',columns: [{name: 'id',isGenerated: true,type: 'int',generationStrategy: 'increment',isPrimary: true},{name: 'username',type: 'varchar'},{name: 'passwordDigest',type: 'varchar'}]}))}public async down(queryRunner: QueryRunner): Promise<void> {return await queryRunner.dropTable('users')}}

$ yarn m:create -n CreatePosts
import { MigrationInterface, QueryRunner,Table } from "typeorm";export class CreatePosts1627889702787 implements MigrationInterface {public async up(queryRunner: QueryRunner): Promise<void> {return await queryRunner.createTable(new Table({name: 'posts',columns: [{name: 'id',isGenerated: true,type: 'int',generationStrategy: 'increment',isPrimary: true},{name: 'title',type: 'varchar'},{name: 'content',type: 'text'},{name: 'authorId',type: 'int'}]}))}public async down(queryRunner: QueryRunner): Promise<void> {return await queryRunner.dropTable('posts')}}
$ yarn m:create -n CreateComments
import { MigrationInterface, QueryRunner, Table } from "typeorm";export class CreateComments1627890376988 implements MigrationInterface {public async up(queryRunner: QueryRunner): Promise<void> {return await queryRunner.createTable(new Table({name: 'comments',columns: [{name: 'id',isGenerated: true,type: 'int',generationStrategy: 'increment',isPrimary: true},{name: 'userId',type: 'int'},{name: 'postId',type: 'int'},{name: 'content',type: 'text'}]}))}public async down(queryRunner: QueryRunner): Promise<void> {return await queryRunner.dropTable('comments')}}
$ yarn m:create -n AddCreatedAtAndUpdatedAt
import { MigrationInterface, QueryRunner, TableColumn } from "typeorm";export class AddCreatedAtAndUpdatedAt1627891112814 implements MigrationInterface {public async up(queryRunner: QueryRunner): Promise<void> {await queryRunner.addColumns('users', [new TableColumn({name: 'createdAt',type: 'time',isNullable: false,default: 'now()'}),new TableColumn({name: 'updatedAt',type: 'time',isNullable: false,default: 'now()'})])await queryRunner.addColumns('posts', [new TableColumn({name: 'createdAt',type: 'time',isNullable: false,default: 'now()'}),new TableColumn({name: 'updatedAt',type: 'time',isNullable: false,default: 'now()'})])return await queryRunner.addColumns('comments', [new TableColumn({name: 'createdAt',type: 'time',isNullable: false,default: 'now()'}),new TableColumn({name: 'updatedAt',type: 'time',isNullable: false,default: 'now()'})])}public async down(queryRunner: QueryRunner): Promise<void> {await queryRunner.dropColumn('users', 'createdAt')await queryRunner.dropColumn('users', 'updatedAt')await queryRunner.dropColumn('posts', 'createdAt')await queryRunner.dropColumn('posts', 'updatedAt')await queryRunner.dropColumn('comments', 'createdAt')return await queryRunner.dropColumn('comments', 'updatedAt')}}
删除dits 然后$ yarn dev 会重新创建dist文件夹$ yarn m:run
创建关联
这三张表之间的内容有这样的关系
- users表
- 一个user有很多posts
- 一个user有很多comments
- posts表
- 一个post属于一个user
- 一个post有很多comments
- comments
- 一个comment属于一个user
- 一个commnet属于一个post
创建entity中的实体
package.json
“e:create”: “typeorm entity:create”
$ yarn e:create -n User$ yarn e:create -n Post$ yarn e:create -n Comment
/src/entity/User.ts
import { Column, CreateDateColumn, Entity, OneToMany, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm';import { Comment } from './Comment';import { Post } from './Post'@Entity('users')export class User {@PrimaryGeneratedColumn('increment')id: string;@Column('varchar')username: string;@Column('varchar')passwordDigest: string;@CreateDateColumn()createdAt: Date;@UpdateDateColumn()updatedAt: Date;@OneToMany(type => Post, post => post.author)posts: Post[]@OneToMany(type => Comment, comment => comment.user)comments: Comment[]}
/src/entity/Post.ts
import { Column, CreateDateColumn, Entity, ManyToOne, OneToMany, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm';import { User } from './User';import { Comment } from './Comment';@Entity('posts')export class Post {@PrimaryGeneratedColumn('increment')id: string;@Column('varchar')title: string;@Column('text')content: string;@CreateDateColumn()createdAt: Date;@UpdateDateColumn()updatedAt: Date;@ManyToOne(type => User, user => user.posts)author: User;@OneToMany(type => Comment, comment => comment.post)comments: Comment[]}
/src/entity/Comment.ts
import { Column, CreateDateColumn, Entity, ManyToOne, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm';import { Post } from './Post';import { User } from './User';@Entity('comments')export class Comment {@PrimaryGeneratedColumn('increment')id: string;@Column('text')content: string;@CreateDateColumn()createdAt: Date;@UpdateDateColumn()updatedAt: Date;@ManyToOne(type => User, user => user.comments)user: User;@ManyToOne(type => Post, post => post.comments)post: Post;}
填充数据
/src/seeds.ts
import "reflect-metadata";import { createConnection } from "typeorm";import { Comment } from "./entity/Comment";import { Post } from "./entity/Post";import { User } from './entity/User';createConnection().then(async connection => {const { manager } = connection;//创建userconst u1 = new User()u1.username = 'gouson'u1.passwordDigest = 'xxx'await manager.save(u1)//创建postconst p1 = new Post()p1.title = "Post 1"p1.content = "yyyyyyyyyyyyyyyyyy"p1.author = u1await manager.save(p1)//创建commentconst c1 = new Comment()c1.content = 'zzzzzz'c1.user = u1c1.post = p1await manager.save(c1)console.log(u1.id)connection.close()}).catch(error => console.log(error));
$ yarn dev$ node dist/seed.js



创建成功
