프로젝트 구조
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
+ src + entity Hero.ts Power.ts + resolver hero.resolver.ts index.ts + typeDef hero.graphql index.ts .gitignore ormconfig.json package.json tsconfig.json |
hero find, findOne, skip, take, relations
hero, heroes를 데이터베이스에서 쿼리하도록 수정한다.
먼저 hero.resolve.ts를 수정한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
export default { Query: { hero: async (_, {id}) => { const hero = await getConnection().getRepository(Hero).findOne(id, {relations: ["powers"]}); return hero }, heroes: async (_, args) => { let options = {relations: ["powers"]}; if (args.start_index) { options['skip'] = args.start_index; } if (args.page_size) { options['take'] = args.page_size; } return getConnection().getRepository(Hero).find(options); } } } |
http://localhost:4000 에서 테스트해본다.
1 2 3 4 5 6 7 8 9 10 |
query { hero(id: 1) { id name email powers { name } } } |
1 2 3 4 5 6 7 8 9 10 |
query { heroes(start_index: 3, page_size: 3) { id name email powers { name } } } |
hero create
hero 데이터와 one-to-many 관계인 여러개의 power 데이터가 입력으로 들어오면 먼저 Hero 인스턴스를 만들어서 저장한다. 그러면 저장후에 자동생성된 id 값이 자동으로 저장된다.
그러면 그 후에 power를 저장할때 해당 hero 정보를 넣어주면 power 데이터에 foreign key 정보가 입력되게 된다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
... Mutation: { addHero: async (_, {hero, powers}) => { console.log(hero, powers); const newHero = new Hero(); newHero.name = hero.name; newHero.email = hero.email; newHero.sex = hero.sex; newHero.country = hero.country; newHero.address = hero.address; await getConnection().getRepository(Hero).save(newHero); if (powers && powers.length > 0) { const newPowers = powers.map(power => { let p = new Power(); p.name = power.name; p.hero = newHero; return p; }); await getConnection().createQueryBuilder().insert().into(Power).values(newPowers).execute(); } return await getConnection().getRepository(Hero).findOne(newHero.id, {relations: ["powers"]}); } } |
http://localhost:4000에서 테스트해보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
mutation { addHero(hero: { name: "superman", email: "superman@gmail.com", sex: "male", country: "American" }, powers: [ {name: "flying"}, {name: "strength"} ]) { id name email sex country address created powers { name } } } |
hero update
1 2 3 4 |
type Mutation { addHero(hero: InputHero, powers: [InputPower]): Hero updateHero(id: Int!, hero: InputHero): Hero } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
updateHero: async (_, {id, hero}) => { console.log(id, hero); let saveHero = new Hero(); if (hero.name) saveHero.name = hero.name; if (hero.email) saveHero.email = hero.email; if (hero.sex) saveHero.sex = hero.sex; if (hero.country) saveHero.country = hero.country; if (hero.address) saveHero.address = hero.address; await getConnection().createQueryBuilder() .update(Hero) .set(saveHero) .where("id = :id", {id}) .execute(); return getConnection().getRepository(Hero).findOne(id, {relations: ["powers"]}); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
mutation { updateHero(id: 39, hero: { email: "superman@daum.net" }) { id name email sex country address created updated } } |
hero delete
Hero 테이블 삭제시 one-to-many 관계의 power 테이블도 같이 삭제하기 위해서 cascade 옵션을 추가한다.
1 2 3 |
... @ManyToOne(type => Hero, hero => hero.powers, {cascade: true}) hero: Hero; |
type 추가
1 2 3 4 5 6 |
... type Mutation { addHero(hero: InputHero, powers: [InputPower]): Hero updateHero(id: Int!, hero: InputHero): Hero deleteHero(id: Int!): Response } |
resolver 추가
1 2 3 4 5 6 7 8 9 10 11 12 13 |
deleteHero: async (_, {id}) => { const result = await getConnection().createQueryBuilder() .delete() .from(Hero) .where("id = :id", {id}) .execute(); console.log(result); return { result: 0, message: 'success' } } |
http://localhost:4000에서 테스트한다.
1 2 3 4 5 6 |
mutation { deleteHero(id: 51) { result message } } |