Sonamu supports various data types, and each type is appropriately mapped to PostgreSQL, TypeScript, and JSON.
Common Options
Options that apply to all field types.
| Option | Type | Description | Default |
|---|
name | string | Field name (snake_case) | required |
type | string | Data type | required |
desc | string | Field description | - |
nullable | boolean | Allow NULL | false |
toFilter | boolean | Enable search filtering | false |
dbDefault | string | Database default value | - |
generated | GeneratedColumn | Computed column setting | - |
Generated Column
A column that automatically generates computed values.
{
"name": "full_name",
"type": "string",
"generated": {
"type": "STORED",
"expression": "first_name || ' ' || last_name"
}
}
Options:
type: STORED | VIRTUAL
STORED: Physically stored (can create indexes)
VIRTUAL: Calculated only on query (saves memory)
expression: SQL expression
VIRTUAL type cannot be used with array types, json, or vector
generated and dbDefault cannot be used together
Numeric Types
integer / integer[]
32-bit integer type.
{
"name": "age",
"type": "integer",
"desc": "Age"
}
Mapping:
- PostgreSQL:
integer
- TypeScript:
number
- JSON:
number
Range: -2,147,483,648 ~ 2,147,483,647{
"name": "years",
"type": "integer[]",
"desc": "Year list"
}
Mapping:
- PostgreSQL:
integer[]
- TypeScript:
number[]
- JSON:
number[]
Use cases: ID, count, age, order, year
bigInteger / bigInteger[]
64-bit integer type.
{
"name": "transaction_id",
"type": "bigInteger",
"desc": "Transaction ID"
}
Mapping:
- PostgreSQL:
bigint
- TypeScript:
bigint
- JSON:
bigint (serialized as string)
Range: -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807{
"name": "large_ids",
"type": "bigInteger[]"
}
Mapping:
- PostgreSQL:
bigint[]
- TypeScript:
bigint[]
- JSON:
bigint[]
Values exceeding JavaScript’s Number.MAX_SAFE_INTEGER (2^53 - 1) must use bigint to maintain accuracy.
number / number[]
Floating-point or fixed-point numeric type.
{
"name": "price",
"type": "number",
"precision": 10,
"scale": 2,
"desc": "Price"
}
Mapping:
- PostgreSQL:
numeric(10, 2) (default)
- TypeScript:
number
- JSON:
number
Additional Options:
precision: Total digits (default: none = unlimited)
scale: Decimal places (default: 0)
numberType: numeric | real | double precision (default: numeric)
{
"name": "prices",
"type": "number[]",
"precision": 10,
"scale": 2
}
Mapping:
- PostgreSQL:
numeric(10, 2)[]
- TypeScript:
number[]
- JSON:
number[]
numberType Selection Guide:
| Type | Precision | Memory | Use Cases |
|---|
numeric | Exact (recommended) | High | Money, currency |
real | Approximate (6 digits) | 4 bytes | Scientific data |
double precision | Approximate (15 digits) | 8 bytes | Coordinates, measurements |
Money handling: Setting precision: 10, scale: 2 allows storing up to 99,999,999.99
numeric / numeric[]
High-precision numeric type. Processed as string in TypeScript.
{
"name": "precise_amount",
"type": "numeric",
"precision": 20,
"scale": 10,
"desc": "High-precision amount"
}
Mapping:
- PostgreSQL:
numeric(20, 10)
- TypeScript:
string ⚠️
- JSON:
string
Additional Options:
precision: Total digits
scale: Decimal places
{
"name": "precise_values",
"type": "numeric[]",
"precision": 20,
"scale": 10
}
Mapping:
- PostgreSQL:
numeric(20, 10)[]
- TypeScript:
string[]
- JSON:
string[]
Difference between number and numeric:
number: number type in TypeScript (possible precision loss)
numeric: string type in TypeScript (maintains precision)
Use numeric when you need large numbers or very precise decimal calculations.
String Types
string / string[]
Variable-length string type.
{
"name": "email",
"type": "string",
"length": 255,
"zodFormat": "email",
"desc": "Email"
}
Mapping:
- PostgreSQL:
varchar(255) (when length specified) or text
- TypeScript:
string
- JSON:
string
Additional Options:
length: Maximum length (uses text type when omitted)
zodFormat: Zod 4 String Format validation (see below)
{
"name": "tags",
"type": "string[]",
"desc": "Tag list"
}
Mapping:
- PostgreSQL:
text[] or varchar(n)[]
- TypeScript:
string[]
- JSON:
string[]
The zodFormat option automatically applies Zod’s string format validation when generating BaseSchema.
Usage Example:
{
"name": "user_email",
"type": "string",
"zodFormat": "email",
"desc": "User email"
}
Supported Formats:
| Category | Format | Description |
|---|
| Basic | email | Email address format |
| uuid | UUID format |
| url | URL format |
| httpUrl | HTTP/HTTPS URL format |
| hostname | Hostname format |
| emoji | Emoji format |
| jwt | JWT token format |
| Encoding | base64 | Base64 encoding |
| base64url | URL-safe Base64 encoding |
| hex | Hexadecimal string |
| ID | nanoid | NanoID format |
| cuid | CUID format |
| cuid2 | CUID2 format |
| ulid | ULID format |
| Network | ipv4 | IPv4 address |
| ipv6 | IPv6 address |
| mac | MAC address |
| cidrv4 | IPv4 CIDR notation |
| cidrv6 | IPv6 CIDR notation |
| Hash | hashMd5 | MD5 hash |
| hashSha1 | SHA-1 hash |
| hashSha256 | SHA-256 hash |
| hashSha384 | SHA-384 hash |
| hashSha512 | SHA-512 hash |
| ISO | isoDate | ISO 8601 date (YYYY-MM-DD) |
| isoTime | ISO 8601 time (HH:MM:SS) |
| isoDatetime | ISO 8601 datetime |
| isoDuration | ISO 8601 duration |
length Setting Guide:
- Short text (name, email):
255
- Long text (description, content): omit (text type)
- Fixed length (zip code, phone number): specify exact length
Difference between zodFormat and uuid type:
type: "uuid": Uses PostgreSQL’s native uuid column type, enabling UUID-specific indexes and functions
type: "string" + zodFormat: "uuid": Uses PostgreSQL’s text/varchar column while validating UUID format only at the API level
enum / enum[]
Enumeration type. Only values defined in the Entity’s enums are allowed.
{
"name": "role",
"type": "enum",
"id": "UserRole",
"desc": "User role"
}
Mapping:
- PostgreSQL:
text
- TypeScript:
"admin" | "normal" (Union of Enum keys)
- JSON:
string
Additional Options:
id: Enum type ID (must be defined in Entity’s enums)
length: String max length (optional)
{
"name": "roles",
"type": "enum[]",
"id": "UserRole",
"desc": "User role list"
}
Mapping:
- PostgreSQL:
text[]
- TypeScript:
("admin" | "normal")[]
- JSON:
string[]
Enum Definition Example:
{
"props": [
{
"name": "role",
"type": "enum",
"id": "UserRole"
}
],
"enums": {
"UserRole": {
"admin": "Administrator",
"normal": "Normal User"
}
}
}
Learn More
- Enums - Detailed Enum guide
Boolean Type
boolean / boolean[]
Type for storing true/false values.
{
"name": "is_active",
"type": "boolean",
"dbDefault": "true",
"desc": "Active status"
}
Mapping:
- PostgreSQL:
boolean
- TypeScript:
boolean
- JSON:
boolean
{
"name": "flags",
"type": "boolean[]"
}
Mapping:
- PostgreSQL:
boolean[]
- TypeScript:
boolean[]
- JSON:
boolean[]
Default value setting: dbDefault: "true" or dbDefault: "false"
Date/Time Types
date / date[]
Type for storing date and time.
{
"name": "created_at",
"type": "date",
"dbDefault": "CURRENT_TIMESTAMP",
"desc": "Created at"
}
Mapping:
- PostgreSQL:
timestamptz (with timezone)
- TypeScript:
Date
- JSON:
string (ISO 8601 format)
{
"name": "event_dates",
"type": "date[]"
}
Mapping:
- PostgreSQL:
timestamptz[]
- TypeScript:
Date[]
- JSON:
string[]
Commonly used default values:
CURRENT_TIMESTAMP: Current time
CURRENT_DATE: Current date (time 00:00:00)
UUID Type
uuid / uuid[]
Universally Unique Identifier (UUID) type.
{
"name": "session_id",
"type": "uuid",
"dbDefault": "gen_random_uuid()",
"desc": "Session ID"
}
Mapping:
- PostgreSQL:
uuid
- TypeScript:
string
- JSON:
string
{
"name": "related_ids",
"type": "uuid[]"
}
Mapping:
- PostgreSQL:
uuid[]
- TypeScript:
string[]
- JSON:
string[]
UUID Generation: Using PostgreSQL’s gen_random_uuid() function as dbDefault enables auto-generation.
Structured Data Types
json
Type for storing structured data in JSON format.
{
"name": "metadata",
"type": "json",
"id": "ProductMetadata",
"nullable": true,
"desc": "Product metadata"
}
Mapping:
- PostgreSQL:
json
- TypeScript: User-defined type (
ProductMetadata)
- JSON:
any
Additional Options:
id: TypeScript type ID (defined in .types.ts)
Type Definition Example:
{
"name": "metadata",
"type": "json",
"id": "ProductMetadata"
}
JSON types can be difficult to index and may have lower performance. It’s recommended to separate frequently searched fields into separate columns.
virtual
Virtual fields not stored in the database.
{
"name": "full_name",
"type": "virtual",
"id": "string",
"virtualType": "code",
"desc": "Full name"
}
Mapping:
- PostgreSQL: Not stored
- TypeScript: User-defined type (or
string, number, etc.)
- JSON: Included (after calculation)
Additional Options:
id: TypeScript type ID
virtualType: code | query (default: code)
code: Calculated with TypeScript code
query: Calculated with SQL appendSelect
virtualType Comparison:
Calculated with TypeScript code in Model.// {entity}.model.ts
enhanceRow(row: User): User {
return {
...row,
full_name: `${row.first_name} ${row.last_name}`
};
}
Pros: Can implement complex logic, can call external APIs
Cons: Cannot filter/sort at database level Calculated with SQL using Puri query’s appendSelect.// {entity}.model.ts
async findAll() {
return this.puri()
.appendSelect({
full_name: this.puri().knex.raw("first_name || ' ' || last_name")
})
.many();
}
Pros: Database-level calculation, can filter/sort
Cons: Limited to logic expressible in SQL
virtualType Selection Guide:
- Simple string concatenation, arithmetic calculations →
query
- Complex business logic, external API calls →
code
Vector Types
vector / vector[]
Type for storing vector embeddings. Requires pgvector extension.
{
"name": "embedding",
"type": "vector",
"dimensions": 1536,
"desc": "Text embedding"
}
Mapping:
- PostgreSQL:
vector(1536) (pgvector extension)
- TypeScript:
number[]
- JSON:
number[]
Additional Options:
dimensions: Vector dimensions (required, e.g., 1536)
{
"name": "embeddings",
"type": "vector[]",
"dimensions": 1536
}
Mapping:
- PostgreSQL:
vector(1536)[]
- TypeScript:
number[][]
- JSON:
number[][]
Vector Search Example:
// Search by cosine similarity
async searchSimilar(queryEmbedding: number[]) {
return this.puri()
.whereRaw("embedding <=> ?", [JSON.stringify(queryEmbedding)])
.orderByRaw("embedding <=> ?", [JSON.stringify(queryEmbedding)])
.limit(10)
.many();
}
Vector Index:
{
"indexes": [
{
"type": "hnsw",
"name": "posts_embedding_idx",
"columns": [
{
"name": "embedding",
"vectorOps": "vector_cosine_ops"
}
],
"m": 16,
"efConstruction": 64
}
]
}
tsvector
Type for PostgreSQL Full-Text Search.
{
"name": "search_vector",
"type": "tsvector",
"generated": {
"type": "STORED",
"expression": "to_tsvector('english', title || ' ' || content)"
}
}
Mapping:
- PostgreSQL:
tsvector
- TypeScript:
string
- JSON:
string
Full-Text Search Index:
{
"indexes": [
{
"type": "index",
"name": "posts_search_vector_idx",
"columns": [{ "name": "search_vector" }],
"using": "gin"
}
]
}
Full-Text Search: A type optimized for keyword searching in natural language text. Supports morphological analysis, stemming, etc.
Relation Type
Type for defining relationships with other Entities.
{
"type": "relation",
"name": "user",
"with": "User",
"relationType": "BelongsToOne",
"desc": "Author"
}
Relation Types:
BelongsToOne: N:1 relationship
OneToOne: 1:1 relationship
HasMany: 1:N relationship
ManyToMany: N:M relationship
Type Selection Guide
Storing Numbers
| Data | Type | Reason |
|---|
| ID, age, count | integer | Common integers |
| Large ID, timestamp | bigInteger | Large range needed |
| Money, price | number (precision, scale) | Precise decimals |
| Scientific measurements | number (numberType: real) | Approximate values allowed |
| High-precision calculations | numeric | Prevent precision loss |
Storing Strings
| Data | Type | Reason |
|---|
| Name, email | string (length: 255) | Common text |
| Description, content | string (omit length) | Long text |
| Status, role | enum | Limited value list |
| UUID, token | uuid | Unique identifier |
Storing Date/Time
| Data | Type | Setting |
|---|
| Created at | date | dbDefault: "CURRENT_TIMESTAMP" |
| Updated at | date | Update trigger needed |
| Date only | date | Time is 00:00:00 |
Complex Data
| Data | Type | Reason |
|---|
| Settings, metadata | json | Structured data |
| Computed fields | virtual | No storage needed |
| Text embeddings | vector | AI search |
| Full-text search | tsvector | Keyword search |
Next Steps