新建项目文件夹
$ 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;
安装 GraphQL Server 、 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", },
最终来到运行和燕子示例
标签:typescript,String,args,Server,GraphQL,User,import,sequelize,any From: https://www.cnblogs.com/ProgArt/p/18447780
$ npm run build
$ npm run start
或者
$ npm run dev