[NestJS]TypeORM 에서 trie 릴레이션 표현하기

도도·2021년 8월 1일
0

기술Velog

목록 보기
2/28

typeorm 에서 trie 릴레이션 표현하기

가정된 상황 예시

  • 공유 노트 어플리케이션
  • 사용자는 n개의 노트를 가진다.
  • 사용자는 n개의 노트를 공유 받을 수 있다.
  • 또한 n개의 노트를 공유할 수 있다.

엔터티

  1. User
  2. Note
  3. SharedNote (trie mapping table )

관계 모델링

  1. User-Note 는 1:N 관계이다.
  2. 트라이 관계
  • User-SharedNote 는 1:N관계 (A가 공유한)
  • User-SharedNote 는 1:N관계 (B가 공유받은)
  • Note-SharedNote 는 1:N관계 (C라는 노트를)

user.entity.ts

import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';
import { Note } from './note.entity';
import { SharedNote } from './sharedNote.entity';

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  username: string;

  @OneToMany(() => Note, (note) => note.owner)
  notes: Note;

  @OneToMany(() => SharedNote, (sharedNote) => sharedNote.target)
  notesYouShare: SharedNote[];

  @OneToMany(() => SharedNote, (sharedNote) => sharedNote.sender)
  notesSharedWithYou: SharedNote[];
}

export type UserRelation =
  | keyof Pick<User, 'notes' | 'notesSharedWithYou' | 'notesYouShare'>
  | 'notesSharedWithYou.note'
  | 'notesYouShare.note';

// export type nnn = '1' | '2';
// export type eee = '🚀' | '✔';
// export type nnneee = `${nnn}-${eee}-${UserRelation}`;

note.entity.ts

import {
  Column,
  Entity,
  JoinColumn,
  ManyToOne,
  OneToMany,
  PrimaryGeneratedColumn,
} from 'typeorm';
import { SharedNote } from './sharedNote.entity';
import { User } from './user.entity';

@Entity()
export class Note {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  text: string;

  @Column()
  ownerId: number;

  @ManyToOne(() => User, (user) => user.notes)
  @JoinColumn({ name: 'ownerId' })
  owner: User;

  @OneToMany(() => SharedNote, (sharedNote) => sharedNote.note)
  shares: SharedNote;
}

sharedNote.entity.ts

import { Entity, JoinColumn, ManyToOne, PrimaryColumn } from 'typeorm';
import { Note } from './note.entity';
import { User } from './user.entity';

@Entity()
export class SharedNote {
  @PrimaryColumn()
  senderId: number;

  @ManyToOne(() => User, (user) => user.notesSharedWithYou)
  @JoinColumn({ name: 'senderId' })
  sender: User;

  @PrimaryColumn()
  targetId: number;

  @ManyToOne(() => User, (user) => user.notesYouShare)
  @JoinColumn({ name: 'targetId' })
  target: User;

  @PrimaryColumn()
  noteId: number;

  @ManyToOne(() => Note, (note) => note.shares)
  @JoinColumn({ name: 'noteId' })
  note: Note;
}

CRUD

  • ✔ 단일객체에서 CRUD
  • 1:N 관계를 가지는 사용자와 notes 간에 CRUD
  1. 사용자 id 만으로 매핑이 되어야 한다.
  2. 사용자 객체를 이용해 매핑이 되어야 한다.
  • N:M 관계를 가지는 사용자와 노트 공유자 간에 CURD
  1. 2명의 사용자 id 만으로 매핑이 되어야 한다.
  2. 2명의 사용자 객체를 이용해 매핑이 되어야 한다.
  3. sharedNote 객체 입장에서, 사용자를 1step join해야한다.
  4. 사용자 입장에서, 매핑테이블을 이용해 노트까지 2step join 해야한다.
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Like, Repository } from 'typeorm';
import { Note } from './entities/note.entity';
import { SharedNote } from './entities/sharedNote.entity';
import { User, UserRelation } from './entities/user.entity';

@Injectable()
export class UserService {
  constructor(
    @InjectRepository(User)
    private readonly userRepo: Repository<User>,
    @InjectRepository(Note)
    private readonly noteRepo: Repository<Note>,
    @InjectRepository(SharedNote)
    private readonly sharedNoteRepo: Repository<SharedNote>,
  ) {
    const test = async () => {
      // CRUD user
      // const user = await userRepo.save(userRepo.create({ username: 'user_dodo' }));
      // console.log(user);
      // const user1 = await userRepo.findOne({ where: { id: 1 } });
      // console.log(user1);
      // user1.username = 'user1-1';
      // await userRepo.save(user1);
      // user1.username = 'user1-2';
      // await userRepo.save(user1);
      // user1.username = 'user1-3';
      // await userRepo.save([user1]);
      // user1.username = 'user1-4';
      // await userRepo.save([{ ...user1 }]);
      // await userRepo.save([{ ...user1 }, { ...user1 }]);
      // CRUD user-note
      // const note1 = await noteRepo.save(
      //   noteRepo.create({ text: 'hello world', ownerId: 1 }),
      // );
      // const user = await userRepo.findOne(1);
      // console.log(
      //   await userRepo.findOne({ where: { id: 1 }, relations: ['notes'] }),
      // );
      // const note2 = await noteRepo.save(
      //   noteRepo.create({ text: 'hello world', owner: user }),
      // );
      // const note3 = await noteRepo.find({
      //   where: { ownerId: user.id },
      //   relations: ['owner'],
      // });
      // console.log(note3);
      // CRUD user-shared-note
      const dodo = await userRepo.findOne({
        where: { username: Like('%do%') },
      });
      // console.log(dodo);
      const nana = await userRepo.findOne({
        where: { username: Like('%nana%') },
      });
      // console.log(nana);
      const dodosNote1 = await noteRepo.findOne({
        where: { ownerId: nana.id, text: Like('%1%') },
      });
      // console.log(dodosNote1);

      // nana > dodo  note shared
      // const sharedMap = await sharedNoteRepo.save(
      //   sharedNoteRepo.create({
      //     sender: nana,
      //     target: dodo,
      //     note: dodosNote1,
      //   }),
      // );
      // console.log(sharedMap);

      // read relation mapping table
      const NotesNanaShare = await sharedNoteRepo.find({
        where: { sender: nana },
        relations: ['sender', 'target', 'note'],
      });
      // console.log(NotesNanaShare);

      // read relation user - mapping table - note
      const dodoUser = await userRepo.findOne({
        where: { username: Like('%nana%') },
        relations: [
          'notes',
          'notesSharedWithYou', // 1
          'notesSharedWithYou.note', // 2
          // 'notesYouShare',
          // 'notesYouShare.note',
        ] as UserRelation[],
      });
      console.log(JSON.stringify(dodoUser, null, 4));
    };
    test();
  }
}
profile
프론트 주력의 JS 개발자 입니다.! Node.js, React, NestJS 에 관심이 많습니다.

0개의 댓글