Skip to content

Commit 558590e

Browse files
committed
docs(examples): add TypeORM usage example
1 parent d973922 commit 558590e

File tree

11 files changed

+353
-13
lines changed

11 files changed

+353
-13
lines changed

dev.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ require("ts-node/register");
22
require("./tests/index.ts");
33
// require("./examples/01-simple-usage/index.ts");
44
// require("./examples/02-using-container/index.ts");
5+
// require("./examples/03-typeorm-usage/index.ts");
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { GraphQLObjectType, Field, Int} from "../../../src";
2+
import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from "typeorm";
3+
4+
import { User } from "./user";
5+
import { Recipe } from "./recipe";
6+
import { RelationColumn } from "../helpers";
7+
8+
@Entity()
9+
@GraphQLObjectType()
10+
export class Rate {
11+
@PrimaryGeneratedColumn()
12+
readonly id: number;
13+
14+
@Field(type => Int)
15+
@Column({ type: "int" })
16+
value: number;
17+
18+
@Field(type => User)
19+
@ManyToOne(type => User)
20+
user: User;
21+
22+
@RelationColumn()
23+
userId: number;
24+
25+
@ManyToOne(type => Recipe)
26+
recipe: Recipe;
27+
28+
@RelationColumn()
29+
recipeId: number;
30+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { Field, ID, GraphQLObjectType, Int, Float } from "../../../src";
2+
import { Entity, PrimaryGeneratedColumn, Column, OneToMany, ManyToOne } from "typeorm";
3+
4+
import { Rate } from "./rate";
5+
import { User } from "./user";
6+
import { RelationColumn } from "../helpers";
7+
8+
@Entity()
9+
@GraphQLObjectType()
10+
export class Recipe {
11+
@PrimaryGeneratedColumn()
12+
@Field(type => ID)
13+
readonly id: number;
14+
15+
@Field()
16+
@Column()
17+
title: string;
18+
19+
@Field({ nullable: true })
20+
@Column({ nullable: true })
21+
description?: string;
22+
23+
@Field(type => Rate)
24+
@OneToMany(type => Rate, rate => rate.recipe, { cascadeInsert: true })
25+
ratings: Rate[];
26+
27+
@Field(type => User)
28+
@ManyToOne(type => User)
29+
author: User;
30+
31+
@RelationColumn()
32+
authorId: number;
33+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { Field, ID, GraphQLObjectType } from "../../../src";
2+
import { PrimaryGeneratedColumn, Column, Entity } from "typeorm";
3+
4+
@GraphQLObjectType()
5+
@Entity()
6+
export class User {
7+
@PrimaryGeneratedColumn()
8+
@Field(type => ID)
9+
readonly id: number;
10+
11+
@Column()
12+
@Field()
13+
email: string;
14+
15+
@Column({ nullable: true })
16+
@Field({ nullable: true })
17+
nickname?: string;
18+
19+
@Column()
20+
password: string;
21+
}

examples/03-typeorm-usage/helpers.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { getRepository, Column, ColumnOptions } from "typeorm";
2+
3+
import { Recipe } from "./entities/recipe";
4+
import { Rate } from "./entities/rate";
5+
import { User } from "./entities/user";
6+
7+
export async function seedDatabase() {
8+
const recipeRepository = getRepository(Recipe);
9+
const ratingsRepository = getRepository(Rate);
10+
const userRepository = getRepository(User);
11+
12+
const defaultUser = userRepository.create({
13+
email: "test@github.com",
14+
nickname: "19majkel94",
15+
password: "s3cr3tp4ssw0rd",
16+
});
17+
await userRepository.save(defaultUser);
18+
19+
const recipes = recipeRepository.create([
20+
{
21+
title: "Recipe 1",
22+
description: "Desc 1",
23+
author: defaultUser,
24+
ratings: ratingsRepository.create([
25+
{ value: 2, user: defaultUser },
26+
{ value: 4, user: defaultUser },
27+
{ value: 5, user: defaultUser },
28+
{ value: 3, user: defaultUser },
29+
{ value: 4, user: defaultUser },
30+
]),
31+
},
32+
{
33+
title: "Recipe 2",
34+
author: defaultUser,
35+
ratings: ratingsRepository.create([
36+
{ value: 2, user: defaultUser },
37+
{ value: 4, user: defaultUser },
38+
]),
39+
},
40+
]);
41+
await recipeRepository.save(recipes);
42+
}
43+
44+
export type Lazy<T extends object> = Promise<T> | T;
45+
46+
export function RelationColumn(options?: ColumnOptions) {
47+
return Column({ nullable: true, ...options });
48+
}

examples/03-typeorm-usage/index.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import "reflect-metadata";
2+
import * as express from "express";
3+
import * as graphqlHTTP from "express-graphql";
4+
import { Container } from "typedi";
5+
import * as TypeGraphQL from "../../src";
6+
import * as TypeORM from "typeorm";
7+
8+
import { RecipeResolver } from "./resolvers/recipe-resolver";
9+
import { RateResolver } from "./resolvers/rate-resolver";
10+
import { Recipe } from "./entities/recipe";
11+
import { Rate } from "./entities/rate";
12+
import { User } from "./entities/user";
13+
import { seedDatabase } from "./helpers";
14+
15+
// register 3rd party IOC container
16+
TypeGraphQL.useContainer(Container);
17+
TypeORM.useContainer(Container);
18+
19+
(async () => {
20+
try {
21+
// create TypeORM connection
22+
await TypeORM.createConnection({
23+
type: "mysql",
24+
database: "type-graphql",
25+
username: "root",
26+
password: "qwerty123",
27+
port: 3306,
28+
host: "localhost",
29+
entities: [Recipe, Rate, User],
30+
synchronize: true,
31+
logger: "advanced-console",
32+
logging: "all",
33+
// logging: ["error"],
34+
dropSchema: true,
35+
});
36+
37+
// seed database with some data
38+
await seedDatabase();
39+
40+
// build TypeGraphQL executable schema
41+
const schema = TypeGraphQL.buildSchema({
42+
resolvers: [RecipeResolver, RateResolver],
43+
});
44+
45+
// create express-based gql endpoint
46+
const app = express();
47+
app.use(
48+
"/graphql",
49+
graphqlHTTP({
50+
schema,
51+
graphiql: true,
52+
}),
53+
);
54+
app.listen(4000, () => {
55+
console.log("Running a GraphQL API server at localhost:4000/graphql");
56+
});
57+
} catch (err) {
58+
console.error(err);
59+
}
60+
})();
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { GraphQLResolver, Query, FieldResolver, Arg, Root, Mutation } from "../../../src/index";
2+
import { Repository } from "typeorm";
3+
import { OrmRepository } from "typeorm-typedi-extensions";
4+
5+
import { Rate } from "../entities/rate";
6+
import { User } from "../entities/user";
7+
8+
@GraphQLResolver(() => Rate)
9+
export class RateResolver {
10+
constructor(
11+
@OrmRepository(User)
12+
private readonly userRepository: Repository<User>,
13+
) {}
14+
15+
@FieldResolver()
16+
async user(@Root() rate: Rate): Promise<User> {
17+
return (await this.userRepository.findOneById(rate.userId, { cache: 1000 }))!;
18+
}
19+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { GraphQLResolver, Query, FieldResolver, Arg, Root, Mutation } from "../../../src/index";
2+
import { Repository } from "typeorm";
3+
import { OrmRepository } from "typeorm-typedi-extensions";
4+
5+
import { Recipe } from "../entities/recipe";
6+
import { Rate } from "../entities/rate";
7+
import { User } from "../entities/user";
8+
import { RecipeInput } from "./types/recipe-input";
9+
10+
@GraphQLResolver(() => Recipe)
11+
export class RecipeResolver {
12+
constructor(
13+
@OrmRepository(Recipe)
14+
private readonly recipeRepository: Repository<Recipe>,
15+
@OrmRepository(Rate)
16+
private readonly ratingsRepository: Repository<Rate>,
17+
@OrmRepository(User)
18+
private readonly userRepository: Repository<User>,
19+
) {}
20+
21+
@Query(returnType => Recipe, { nullable: true })
22+
recipe(@Arg("recipeId") recipeId: number) {
23+
return this.recipeRepository.findOneById(recipeId);
24+
}
25+
26+
@Query(returnType => Recipe, { array: true })
27+
recipes(): Promise<Recipe[]> {
28+
return this.recipeRepository.find();
29+
}
30+
31+
@Mutation(returnType => Recipe)
32+
addRecipe(@Arg("recipe") recipeInput: RecipeInput): Promise<Recipe> {
33+
const recipe = this.recipeRepository.create({
34+
...recipeInput,
35+
authorId: 1,
36+
});
37+
return this.recipeRepository.save(recipe);
38+
}
39+
40+
@FieldResolver()
41+
ratings(@Root() recipe: Recipe) {
42+
return this.ratingsRepository.find({
43+
cache: 1000,
44+
where: { recipeId: recipe.id },
45+
});
46+
}
47+
48+
@FieldResolver()
49+
async author(@Root() recipe: Recipe): Promise<User> {
50+
return (await this.userRepository.findOneById(recipe.authorId, { cache: 1000 }))!;
51+
}
52+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { GraphQLInputType, Field } from "../../../../src";
2+
3+
import { Recipe } from "../../entities/recipe";
4+
5+
@GraphQLInputType()
6+
export class RecipeInput implements Partial<Recipe> {
7+
@Field()
8+
title: string;
9+
10+
@Field({ nullable: true })
11+
description: string;
12+
}

0 commit comments

Comments
 (0)