golang ORM entgo로 custom sql 만들기

dasd412·2024년 9월 10일
0

golang

목록 보기
3/5

서론

본론에 앞서 golang ORM인 entgo는 문서화가 생각보다 부실하다. 예제가 부족해서 개발자가 부딪혀가며 배울 수 밖에 없다...


커스텀 sql 만들기

커스텀 sql이 필요한 이유

ORM은 raw sql query를 작성하지 않고도 어플리케이션 개발 언어를 통해서 db 조작을 할 수 있게 하는 기술이다. 근데 가끔씩 ORM이 제공해주지 않는 기능이 있다. 이러한 기능들은 DB 벤더마다 다르다. 내 기억 상으로 Spring JPA는 native query라는 것을 활용하는 걸로 알고 있다. 이 기능은 DB 벤더가 바뀌면 작동하지 않는다는 문제가 있다. (ORM 추상화를 포기하는 거라 보면 된다)

뭐 어쨋든, 나는 LENGTH라는 db function이 golang ORM인 entgo에도 있는 줄 알았다. 근데 없어.... 그래서 커스텀 Sql로 진행했다.

출처

먼저 공식 문서 출처부터 제공한다.
https://entgo.io/docs/feature-flags#custom-sql-modifiers

예제

사용자 user와 애완동물 pet이 있다고 하자. 일대다 관계를 맺고 있다고 하자. 만약 애완동물 이름인 뽀삐인 애완동물들의 주인 중에서 이름이 가장 짧은 주인의 정보를 얻고 싶다고 해보자. (예시가 억지스러운 건 양해바란다. 좀 급조했다.)

sql

			SELECT u.id, LENGTH(u.name)as name_len ,u.name
				FROM pets p
				INNER JOIN users u ON p.user_pets = u.id
				where p.name = '뽀삐'
				GROUP BY LENGTH(u.name), p.id
				ORDER BY name_len
				LIMIT 1;

entgo ORM

elem, err := client.User.Query().
		Modify(
			func(s *sql.Selector) {
				t1 := sql.Table(user.Table).As("u")
				t2 := sql.Table(pet.Table).As("p")

				s.Select(
					t1.C(user.FieldID),
					sql.As("LENGTH(u.name)", "name_len"), 
					t1.C(user.FieldName),
				).
					From(t1).
					Join(t2).
					On(t1.C(user.FieldID), t2.C(pet.UserColumn)).
					Where(sql.EQ(t2.C(pet.FieldName), "뽀삐")).
					GroupBy("name_len", pet.FieldID).
					OrderBy("name_len").
					Limit(1)
			},
		).
		Only(ctx)

해설
1. Modify : custom Sql을 만드는 데 쓰이는 코드다.
2. t1.C(user.FieldID) : 여기서 C는 칼럼의 약자다. 즉, t1 테이블의 id 칼럼이라는 뜻이다. 이 때 t1은 user 테이블이다.
3. sql.As("LENGTH(u.name)", "name_len") : db의 as 구문을 사용할 수 있다. 이 때, 첫 번째 인자는 raw query인 string을 넣으면 된다. 잘 보면 알겠지만, t1 := sql.Table(user.Table).As("u")에서 지정된 별칭 u를 쓰고 있다. sql ambiguous error가 발생하면 이를 통해 해결해보자.
4. 다음 결과는 User 엔티티에 저장된다. 즉, Id와 name은 User 엔티티에 저장된다. 다른 필드는 nil로 처리된다.

				s.Select(
					t1.C(user.FieldID),
					sql.As("LENGTH(u.name)", "name_len"), 
					t1.C(user.FieldName),
				).

profile
시스템 아키텍쳐 설계에 관심이 많은 백엔드 개발자입니다. (Go/Python/MSA/graphql/Spring)

0개의 댓글