Sonamu는 다양한 데이터 타입을 지원하며, 각 타입은 PostgreSQL, TypeScript, JSON에서 적절하게 매핑됩니다.
공통 옵션
모든 필드 타입에 공통으로 적용되는 옵션입니다.
옵션 타입 설명 기본값 namestring 필드명 (snake_case) 필수 typestring 데이터 타입 필수 descstring 필드 설명 - nullableboolean NULL 허용 여부 falsetoFilterboolean 검색 필터링 가능 여부 falsedbDefaultstring 데이터베이스 기본값 - generatedGeneratedColumn 계산 컬럼 설정 -
Generated Column
계산된 값을 자동으로 생성하는 컬럼입니다.
{
"name" : "full_name" ,
"type" : "string" ,
"generated" : {
"type" : "STORED" ,
"expression" : "first_name || ' ' || last_name"
}
}
옵션 :
type: STORED | VIRTUAL
STORED: 물리적으로 저장됨 (인덱스 생성 가능)
VIRTUAL: 조회 시에만 계산됨 (메모리 절약)
expression: SQL 표현식
VIRTUAL 타입은 배열 타입, json, vector에서 사용할 수 없습니다 - generated와 dbDefault를
동시에 사용할 수 없습니다
숫자 타입
integer / integer[]
32비트 정수 타입입니다.
{
"name" : "age" ,
"type" : "integer" ,
"desc" : "나이"
}
매핑 :
PostgreSQL: integer
TypeScript: number
JSON: number
범위 : -2,147,483,648 ~ 2,147,483,647{
"name" : "years" ,
"type" : "integer[]" ,
"desc" : "연도 목록"
}
매핑 :
PostgreSQL: integer[]
TypeScript: number[]
JSON: number[]
사용 예시 : ID, 개수, 나이, 순서, 년도
bigInteger / bigInteger[]
64비트 정수 타입입니다.
{
"name" : "transaction_id" ,
"type" : "bigInteger" ,
"desc" : "거래 ID"
}
매핑 :
PostgreSQL: bigint
TypeScript: bigint
JSON: bigint (문자열로 직렬화)
범위 : -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807{
"name" : "large_ids" ,
"type" : "bigInteger[]"
}
매핑 :
PostgreSQL: bigint[]
TypeScript: bigint[]
JSON: bigint[]
JavaScript의 Number.MAX_SAFE_INTEGER (2^53 - 1)를 초과하는 값은 bigint를 사용해야 정확도가
유지됩니다.
number / number[]
부동소수점 또는 고정소수점 숫자 타입입니다.
{
"name" : "price" ,
"type" : "number" ,
"precision" : 10 ,
"scale" : 2 ,
"desc" : "가격"
}
매핑 :
PostgreSQL: numeric(10, 2) (기본값)
TypeScript: number
JSON: number
추가 옵션 :
precision: 전체 자릿수 (기본값: 없음 = 무제한)
scale: 소수점 자릿수 (기본값: 0)
numberType: numeric | real | double precision (기본값: numeric)
{
"name" : "prices" ,
"type" : "number[]" ,
"precision" : 10 ,
"scale" : 2
}
매핑 :
PostgreSQL: numeric(10, 2)[]
TypeScript: number[]
JSON: number[]
numberType 선택 가이드 :
타입 정밀도 메모리 사용 예시 numeric정확함 (권장) 많음 금액, 통화 real근사값 (6자리) 4 bytes 과학적 데이터 double precision근사값 (15자리) 8 bytes 좌표, 측정값
금액 처리 : precision: 10, scale: 2로 설정하면 최대 99,999,999.99까지 저장 가능
numeric / numeric[]
고정밀도 숫자 타입입니다. TypeScript에서 문자열 로 처리됩니다.
{
"name" : "precise_amount" ,
"type" : "numeric" ,
"precision" : 20 ,
"scale" : 10 ,
"desc" : "초정밀 금액"
}
매핑 :
PostgreSQL: numeric(20, 10)
TypeScript: string ⚠️
JSON: string
추가 옵션 :
precision: 전체 자릿수
scale: 소수점 자릿수
{
"name" : "precise_values" ,
"type" : "numeric[]" ,
"precision" : 20 ,
"scale" : 10
}
매핑 :
PostgreSQL: numeric(20, 10)[]
TypeScript: string[]
JSON: string[]
number vs numeric 차이점 :
number: TypeScript에서 number 타입 (정밀도 손실 가능)
numeric: TypeScript에서 string 타입 (정밀도 유지)
큰 숫자나 매우 정확한 소수점 계산이 필요한 경우 numeric을 사용하세요.
문자열 타입
string / string[]
가변 길이 문자열 타입입니다.
{
"name" : "email" ,
"type" : "string" ,
"length" : 255 ,
"zodFormat" : "email" ,
"desc" : "이메일"
}
매핑 :
PostgreSQL: varchar(255) (length 지정 시) 또는 text
TypeScript: string
JSON: string
추가 옵션 :
length: 최대 길이 (생략 시 text 타입 사용)
zodFormat: Zod 4 String Format validation (아래 참조)
{
"name" : "tags" ,
"type" : "string[]" ,
"desc" : "태그 목록"
}
매핑 :
PostgreSQL: text[] 또는 varchar(n)[]
TypeScript: string[]
JSON: string[]
zodFormat 옵션을 사용하면 BaseSchema 생성 시 Zod의 string format validation이 자동으로 적용됩니다.
사용 예시 :
{
"name" : "user_email" ,
"type" : "string" ,
"zodFormat" : "email" ,
"desc" : "사용자 이메일"
}
지원 포맷 :
카테고리 포맷 설명 기본 email이메일 주소 형식 uuidUUID 형식 urlURL 형식 httpUrlHTTP/HTTPS URL 형식 hostname호스트명 형식 emoji이모지 형식 jwtJWT 토큰 형식 인코딩 base64Base64 인코딩 base64urlURL-safe Base64 인코딩 hex16진수 문자열 ID nanoidNanoID 형식 cuidCUID 형식 cuid2CUID2 형식 ulidULID 형식 네트워크 ipv4IPv4 주소 ipv6IPv6 주소 macMAC 주소 cidrv4IPv4 CIDR 표기법 cidrv6IPv6 CIDR 표기법 해시 hashMd5MD5 해시 hashSha1SHA-1 해시 hashSha256SHA-256 해시 hashSha384SHA-384 해시 hashSha512SHA-512 해시 ISO isoDateISO 8601 날짜 (YYYY-MM-DD) isoTimeISO 8601 시간 (HH:MM:SS) isoDatetimeISO 8601 날짜시간 isoDurationISO 8601 기간
length 설정 가이드 : - 짧은 텍스트 (이름, 이메일): 255 - 긴 텍스트 (설명, 내용): 생략 (text
타입) - 고정 길이 (우편번호, 전화번호): 정확한 길이 지정
zodFormat과 uuid 타입의 차이 : - type: "uuid": PostgreSQL의 uuid 컬럼 타입을 사용하며, UUID
전용 인덱스 및 함수 활용 가능 - type: "string" + zodFormat: "uuid": PostgreSQL의
text/varchar 컬럼을 사용하면서 API 레벨에서만 UUID 형식 검증
enum / enum[]
열거형 타입입니다. Entity의 enums에 정의된 값만 허용됩니다.
{
"name" : "role" ,
"type" : "enum" ,
"id" : "UserRole" ,
"desc" : "사용자 역할"
}
매핑 :
PostgreSQL: text
TypeScript: "admin" | "normal" (Enum 키의 Union)
JSON: string
추가 옵션 :
id: Enum 타입 ID (Entity의 enums에 정의 필요)
length: 문자열 최대 길이 (선택 사항)
{
"name" : "roles" ,
"type" : "enum[]" ,
"id" : "UserRole" ,
"desc" : "사용자 역할 목록"
}
매핑 :
PostgreSQL: text[]
TypeScript: ("admin" | "normal")[]
JSON: string[]
Enum 정의 예시 :
{
"props" : [
{
"name" : "role" ,
"type" : "enum" ,
"id" : "UserRole"
}
],
"enums" : {
"UserRole" : {
"admin" : "관리자" ,
"normal" : "일반 사용자"
}
}
}
더 알아보기 -
Enums - Enum 상세 가이드
논리 타입
boolean / boolean[]
참/거짓 값을 저장하는 타입입니다.
{
"name" : "is_active" ,
"type" : "boolean" ,
"dbDefault" : "true" ,
"desc" : "활성화 여부"
}
매핑 :
PostgreSQL: boolean
TypeScript: boolean
JSON: boolean
{
"name" : "flags" ,
"type" : "boolean[]"
}
매핑 :
PostgreSQL: boolean[]
TypeScript: boolean[]
JSON: boolean[]
기본값 설정 : dbDefault: "true" 또는 dbDefault: "false"
날짜/시간 타입
date / date[]
날짜와 시간을 저장하는 타입입니다.
{
"name" : "created_at" ,
"type" : "date" ,
"dbDefault" : "CURRENT_TIMESTAMP" ,
"desc" : "생성일시"
}
매핑 :
PostgreSQL: timestamptz (타임존 포함)
TypeScript: Date
JSON: string (ISO 8601 형식)
{
"name" : "event_dates" ,
"type" : "date[]"
}
매핑 :
PostgreSQL: timestamptz[]
TypeScript: Date[]
JSON: string[]
자주 사용되는 기본값 : - CURRENT_TIMESTAMP: 현재 시각 - CURRENT_DATE: 현재 날짜 (시간
00:00:00)
UUID 타입
uuid / uuid[]
범용 고유 식별자(UUID) 타입입니다.
{
"name" : "session_id" ,
"type" : "uuid" ,
"dbDefault" : "gen_random_uuid()" ,
"desc" : "세션 ID"
}
매핑 :
PostgreSQL: uuid
TypeScript: string
JSON: string
{
"name" : "related_ids" ,
"type" : "uuid[]"
}
매핑 :
PostgreSQL: uuid[]
TypeScript: string[]
JSON: string[]
UUID 생성 : PostgreSQL의 gen_random_uuid() 함수를 dbDefault로 사용하면 자동 생성됩니다.
구조화된 데이터 타입
json
JSON 형식의 구조화된 데이터를 저장하는 타입입니다.
{
"name" : "metadata" ,
"type" : "json" ,
"id" : "ProductMetadata" ,
"nullable" : true ,
"desc" : "상품 메타데이터"
}
매핑 :
PostgreSQL: json
TypeScript: 사용자 정의 타입 (ProductMetadata)
JSON: any
추가 옵션 :
id: TypeScript 타입 ID (.types.ts에서 정의)
타입 정의 예시 :
entity.json
{entity}.types.ts
{
"name" : "metadata" ,
"type" : "json" ,
"id" : "ProductMetadata"
}
JSON 타입은 인덱싱이 어렵고 성능이 낮을 수 있습니다. 자주 검색되는 필드는 별도 컬럼으로 분리하는
것을 권장합니다.
virtual
데이터베이스에 저장되지 않는 가상 필드입니다.
{
"name" : "full_name" ,
"type" : "virtual" ,
"id" : "string" ,
"virtualType" : "code" ,
"desc" : "전체 이름"
}
매핑 :
PostgreSQL: 저장되지 않음
TypeScript: 사용자 정의 타입 (또는 string, number 등)
JSON: 포함됨 (계산 후)
추가 옵션 :
id: TypeScript 타입 ID
virtualType: code | query (기본값: code)
code: TypeScript 코드로 계산
query: SQL appendSelect로 계산
virtualType 비교 :
Model에서 TypeScript 코드로 계산합니다. // {entity}.model.ts
enhanceRow ( row : User ): User {
return {
... row ,
full_name: ` ${ row . first_name } ${ row . last_name } `
};
}
장점 : 복잡한 로직 구현 가능, 외부 API 호출 가능
단점 : 데이터베이스 레벨 필터링/정렬 불가Puri 쿼리의 appendSelect로 SQL 계산합니다. // {entity}.model.ts의 subset 쿼리에서 사용
const { qb } = this . getSubsetQueries ( subset );
qb . appendSelect ({
full_name: Puri . rawString ( "first_name || ' ' || last_name" ),
});
장점 : 데이터베이스 레벨 계산, 필터링/정렬 가능
단점 : SQL로만 표현 가능한 로직으로 제한
virtualType 선택 가이드 : - 단순 문자열 조합, 수식 계산 → query - 복잡한 비즈니스 로직, 외부
API 호출 → code
Vector 타입
vector / vector[]
벡터 임베딩을 저장하는 타입입니다. pgvector 확장이 필요합니다.
{
"name" : "embedding" ,
"type" : "vector" ,
"dimensions" : 1536 ,
"desc" : "텍스트 임베딩"
}
매핑 :
PostgreSQL: vector(1536) (pgvector 확장)
TypeScript: number[]
JSON: number[]
추가 옵션 :
dimensions: 벡터 차원 (필수, 예: 1536)
{
"name" : "embeddings" ,
"type" : "vector[]" ,
"dimensions" : 1536
}
매핑 :
PostgreSQL: vector(1536)[]
TypeScript: number[][]
JSON: number[][]
Vector 검색 예시 :
// 코사인 유사도로 검색
async searchSimilar ( queryEmbedding : number []) {
const results = await this . getPuri ( "r" ). raw ( `
SELECT id, content,
1 - (embedding <=> ?) AS similarity
FROM documents
ORDER BY embedding <=> ?
LIMIT 10
` , [ JSON . stringify ( queryEmbedding ), JSON . stringify ( queryEmbedding )]);
return results . rows ;
}
Vector 인덱스 :
{
"indexes" : [
{
"type" : "hnsw" ,
"name" : "posts_embedding_idx" ,
"columns" : [
{
"name" : "embedding" ,
"vectorOps" : "vector_cosine_ops"
}
],
"m" : 16 ,
"efConstruction" : 64
}
]
}
tsvector
PostgreSQL 전문 검색(Full-Text Search)을 위한 타입입니다.
{
"name" : "search_vector" ,
"type" : "tsvector" ,
"generated" : {
"type" : "STORED" ,
"expression" : "to_tsvector('english', title || ' ' || content)"
}
}
매핑 :
PostgreSQL: tsvector
TypeScript: string
JSON: string
전문 검색 인덱스 :
{
"indexes" : [
{
"type" : "index" ,
"name" : "posts_search_vector_idx" ,
"columns" : [{ "name" : "search_vector" }],
"using" : "gin"
}
]
}
전문 검색 : 자연어 텍스트의 키워드 검색에 최적화된 타입입니다. 형태소 분석, 어간 추출 등을
지원합니다.
Relation 타입
다른 Entity와의 관계를 정의하는 타입입니다.
{
"type" : "relation" ,
"name" : "user" ,
"with" : "User" ,
"relationType" : "BelongsToOne" ,
"desc" : "작성자"
}
Relation 타입 :
BelongsToOne: N:1 관계
OneToOne: 1:1 관계
HasMany: 1:N 관계
ManyToMany: N:M 관계
타입 선택 가이드
숫자 저장
데이터 타입 이유 ID, 나이, 개수 integer일반적인 정수 큰 ID, 타임스탬프 bigInteger큰 범위 필요 금액, 가격 number (precision, scale)정확한 소수점 과학적 측정값 number (numberType: real)근사값 허용 초정밀 계산 numeric정밀도 손실 방지
문자열 저장
데이터 타입 이유 이름, 이메일 string (length: 255)일반적인 텍스트 설명, 본문 string (length 생략)긴 텍스트 상태, 역할 enum제한된 값 목록 UUID, 토큰 uuid고유 식별자
날짜/시간 저장
데이터 타입 설정 생성일시 datedbDefault: "CURRENT_TIMESTAMP"수정일시 date업데이트 트리거 필요 날짜만 date시간은 00:00:00
복잡한 데이터
데이터 타입 이유 설정, 메타데이터 json구조화된 데이터 계산 필드 virtual저장 불필요 텍스트 임베딩 vectorAI 검색 전문 검색 tsvector키워드 검색
다음 단계
Relations Entity 간 관계 정의하기
Vector Search Vector 검색 설정하기