新建项目文件夹
$ mkdir demo
$ cd demo
初始化TypeScript配置
$ npx tsc --init
安装 Sequelize Sequelize-cli
$ npm install --save-dev @types/node @types/validator
$ npm install sequelize reflect-metadata sequelize-typescript
$ npm install --save-dev ts-node @types/express @types/node @types/sequelize
调整部分TypeScript配置
$ vi tsconfig.json
"target": "es2022",
"experimentalDecorators": true,
"emitDecoratorMetadata": true
"useDefineForClassFields": false,
"module": "es2022",
"moduleResolution": "node",
"baseUrl": "./src",
"allowJs": true,
"allowSyntheticDefaultImports": true,
"skipLibCheck": true,
使用一个sequelize配置文件,并进行sequelize初始化
$ vi .sequelizerc
// .sequelizerc
const path = require('path');
module.exports = {
config: path.resolve('src/database', 'sequelize.config.js'),
'models-path': path.resolve('src/database', 'models'),
'seeders-path': path.resolve('src/database', 'seeders'),
'migrations-path': path.resolve('src/database', 'migrations'),
};
$ npx sequelize init
修改sequelize生成的数据库配置信息,使用sqlite,以及项目目录结构
$ vi src/database/sequelize.config.js
--> .cjs
require('ts-node/register');
module.exports = {
env: 'development',
dialect: 'sqlite',
storage: './database.sqlite'
};
生成User信息model
$ npx sequelize-cli model:generate --name User --attributes firstname:string,lastname:string,email:string,password:string,memo:string
会创建两个文件
- models/user.js
- migrations/XXXXXXXXXXXXXX-create-user.js
其中:XXXXXXXXXXXXXX- 是按时间戳生成的随机文件名
再生成一个美食Model
$ npx sequelize-cli model:generate --name Recipe --attributes userid:integer,title:string,ingredients:string,direction:string,memo:string
会创建两个文件
- models/recipe.js
- migrations/XXXXXXXXXXXXXX-create-recipe.js
其中:XXXXXXXXXXXXXX- 是按时间戳生成的随机文件名
用Model产生的数据定义脚本在数据库建表
$ npx sequelize-cli db:migrate
执行后在demo目录下生成一个database.sqlite文件,存放User信息model、美食Model表结构,除指定字段信息外,还有sequelize附加的字段。
测试创建一个user
$ npx sequelize-cli seed:generate --name first-user
会创建在seeders目录
- migratiseedersons/XXXXXXXXXXXXXX-first-user.js
执行测试文件在数据库User表增加用户信息
$ npx sequelize-cli db:seed:all
修改美食Model增加关联到User信息Model
// associate
Recipe.belongsTo(User, {
as: 'user',
foreignKey: {
name: 'userid',
allowNull: false,
},
foreignKeyConstraint: true,
});
修改User信息Model关联到美食Model
// associate
User.hasMany(Recipe,{
as: 'recipes',
foreignKey: {
name: 'userid',
allowNull: false,
},
foreignKeyConstraint: false,
})
创建sequelize数据连接文件
$ vi src/database/connect.ts
import {Sequelize} from 'sequelize-typescript';
import {Dialect} from 'sequelize';
import { DIALECT,DB_STORAGE,DB_DATABASE, DB_TIMEZONE, DB_HOST, DB_PORT, DB_PASSWORD, DB_USERNAME } from '../configs.js';
const sqlite: Dialect = DIALECT as Dialect;
let opt = {
dialect: sqlite,
storage: DB_STORAGE,
database: DB_DATABASE,
username: DB_USERNAME,
password: DB_PASSWORD,
host: DB_HOST,
port: DB_PORT,
//timezone: DB_TIMEZONE,
}
const dataSource: Sequelize = new Sequelize(opt);
export default dataSource;
安装 Apollo Server 4、 GraphQL以及其他组件包
$ npm install @apollo/server http express graphql graphql-tag bcryptjs
创建GraphQL的typeDefs文件
$ vi src/graphql/api/typeDefs.ts
import gql from 'graphql-tag';
export const typeDefs = gql`#graphql
type User {
id: Int!
firstname: String!
lastname: String!
email: String!
memo: String
recipes: [Recipe!]!
}
type Recipe {
id: Int!
title: String!
ingredients: String!
direction: String!
memo: String
user: User!
}
type Query {
user(id: Int!): User
allRecipes: [Recipe!]!
recipe(id: Int!): Recipe
allUsers: [User!]!
}
type Mutation {
createUser(firstname: String!, lastname: String!, email: String!, password: String!, memo: String): User
createRecipe(
userid: Int!
title: String!
ingredients: String!
direction: String!
memo: String
): Recipe
}
`;
export default typeDefs;
创建GraphQL的resolvers文件
$ vi src/graphql/api/resolvers.ts
import bcrypt from 'bcryptjs';
import User from '../../database/models/user.model.js';
import Recipe from '../../database/models/recipe.model.js';
export const resolvers = {
Query: {
user: async (root: any, args: { id: any; }, context: any, info: any) => {
return User.findByPk(args.id);
},
allRecipes: async (parent: any, args: {}, context: any, info: any) => {
return Recipe.findAll(info);
},
recipe: async (parent: any, args: { id: any; }, context: any, info: any) => {
return Recipe.findByPk(args.id);
},
allUsers: async (parent: any, args: {}, context: any, info: any) => {
return User.findAll();
},
},
Mutation: {
async createUser(parent: any,
args: { firstname: any, lastname: any, email: any, password: any, memo: any },
context: any,
info: any
) {
return User.create({
firstname: args.firstname,
lastname: args.lastname,
email: args.email,
password: await bcrypt.hash(args.password, 10),
memo: args.memo
});
},
async createRecipe(
parent: any,
args: { userid: any, title: any, ingredients: any, direction: any, memo: any },
context: any,
info: any
) {
return Recipe.create({
userid: args.userid,
title: args.title,
ingredients: args.ingredients,
direction: args.direction,
memo: args.memo
});
},
},
User: {
async recipes(user: any) {
return user.getRecipes();
},
},
Recipe: {
async user(recipe: any) {
return recipe.getUser();
},
},
};
export default resolvers;
创建项目主文件,使用Apollo组件包
$ vi src/index.ts
import { ApolloServer } from '@apollo/server';
import { expressMiddleware } from '@apollo/server/express4';
import { ApolloServerPluginDrainHttpServer } from '@apollo/server/plugin/drainHttpServer';
import cors from 'cors';
import express from 'express';
import http from 'http';
import pkg from 'body-parser';
const { json } = pkg;
import { typeDefs } from './graphql/api/typeDefs.js';
import { resolvers } from './graphql/api/resolvers.js';
import dbTables from './database/models/index.js';
import { SERVICE_PORT } from "./configs.js";
const app = express();
// Our httpServer handles incoming requests to our Express app.
// Below, we tell Apollo Server to "drain" this httpServer,
// enabling our servers to shut down gracefully.
const httpServer = http.createServer(app);
interface ContextValue {
dbTables?: typeof dbTables;
}
const server = new ApolloServer({
typeDefs,
resolvers,
plugins: [
// Proper shutdown for the HTTP server.
ApolloServerPluginDrainHttpServer({ httpServer }),
],
});
await server.start();
app.use(
cors(),
json(),
expressMiddleware(server, {
context: async ({ req }) => ({
token: req.headers.token,
dbTables: dbTables,
}),
}),
);
const port = SERVICE_PORT || 4000;
app.listen({ port: port }, () => console.log(`Server ready at http://localhost:${port}`))
修改 package.json, 增加编译和执行
$ vi package.json
"scripts": {
"build": "tsc",
"start": "nodemon --exec ts-node-esm build/index.js",
"dev": "node --loader ts-node/esm --no-warnings=ExperimentalWarning src/index.ts",
},
最终来到运行和燕子示例
$ npm run build
$ npm run start
或者
$ npm run dev

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?