Field Types Reference
Every field in your .apsorc schema requires a type property that determines the database column type, TypeScript type, and auto-applied validation decorators. This page covers all supported field types with their generated TypeORM mappings and examples.
Core Types
text
Variable-length text data. The most common field type.
{ "name": "title", "type": "text" }
{ "name": "email", "type": "text", "length": 255, "is_email": true }
{ "name": "bio", "type": "text", "nullable": true }| Generated Code | |
|---|---|
| TypeORM | @Column({ type: 'text' }) |
| TypeScript | string |
| Validation | @IsString(), @IsNotEmpty() |
Additional options:
| Option | Effect |
|---|---|
"length": 255 | @Column({ type: 'text', length: 255 }) and @MaxLength(255) |
"is_email": true | Adds @IsEmail() validation |
"unique": true | @Column({ unique: true }) |
"nullable": true | @Column({ nullable: true }) and @IsOptional() |
Example with all options:
{
"name": "email",
"type": "text",
"length": 255,
"unique": true,
"is_email": true
}Generates:
@Column({ type: 'text', length: 255, unique: true })
@IsString()
@IsNotEmpty()
@IsEmail()
@MaxLength(255)
email: string;integer
Whole number values.
{ "name": "count", "type": "integer" }
{ "name": "sortOrder", "type": "integer", "default": 0 }| Generated Code | |
|---|---|
| TypeORM | @Column({ type: 'integer' }) |
| TypeScript | number |
| Validation | @IsNumber() |
float
Floating-point number values.
{ "name": "latitude", "type": "float" }
{ "name": "score", "type": "float", "nullable": true }| Generated Code | |
|---|---|
| TypeORM | @Column({ type: 'float' }) |
| TypeScript | number |
| Validation | @IsNumber() |
boolean
True/false values.
{ "name": "isActive", "type": "boolean", "default": true }
{ "name": "isVerified", "type": "boolean", "default": false }| Generated Code | |
|---|---|
| TypeORM | @Column({ type: 'boolean' }) |
| TypeScript | boolean |
| Validation | @IsBoolean() |
decimal
Fixed-precision decimal numbers. Ideal for financial data where floating-point imprecision is unacceptable.
{ "name": "price", "type": "decimal", "precision": 10, "scale": 2, "default": 0 }| Generated Code | |
|---|---|
| TypeORM | @Column({ type: 'decimal', precision: 10, scale: 2 }) |
| TypeScript | number |
| Validation | @IsNumber() |
Options:
| Option | Type | Description |
|---|---|---|
precision | integer (1-131072) | Total number of digits |
scale | integer (0-16383) | Number of digits after the decimal point |
Example:
{
"name": "price",
"type": "decimal",
"precision": 10,
"scale": 2,
"default": 0,
"nullable": false
}Generates:
@Column({ type: 'decimal', precision: 10, scale: 2, default: 0 })
@IsNumber()
price: number;numeric
Functionally identical to decimal. PostgreSQL treats decimal and numeric as the same type. Use whichever name you prefer.
{ "name": "bandwidth_gb", "type": "numeric", "precision": 10, "scale": 3, "default": 0 }| Generated Code | |
|---|---|
| TypeORM | @Column({ type: 'numeric', precision: 10, scale: 3 }) |
| TypeScript | number |
| Validation | @IsNumber() |
date
Date values (without time component).
{ "name": "birthDate", "type": "date" }
{ "name": "expiresOn", "type": "date", "nullable": true }| Generated Code | |
|---|---|
| TypeORM | @Column({ type: 'date' }) |
| TypeScript | Date |
| Validation | None auto-applied |
timestamptz
Timestamp with time zone. Use this for datetime values where you need both date and time, including timezone information.
{ "name": "scheduledAt", "type": "timestamptz" }
{ "name": "expiresAt", "type": "timestamptz", "nullable": true }| Generated Code | |
|---|---|
| TypeORM | @Column({ type: 'timestamptz' }) |
| TypeScript | Date |
| Validation | None auto-applied |
Note: For auto-managed timestamp columns, use
"created_at": trueand"updated_at": trueat the entity level instead of defining fields withtimestamptz. See Entity Definition.
enum
A predefined set of allowed string values. Requires a values array.
{
"name": "status",
"type": "enum",
"values": ["Active", "Inactive", "Deleted"],
"default": "Active"
}| Generated Code | |
|---|---|
| TypeORM | @Column({ type: 'enum', enum: EntityFieldEnum }) |
| TypeScript | Generated enum type (e.g., ProjectStatusEnum) |
| Validation | None (constrained by the enum type itself) |
Apso generates a TypeScript enum in src/autogen/enums.ts with the naming convention {EntityName}{FieldName}Enum:
// For entity "Project", field "status"
export enum ProjectStatusEnum {
Active = "Active",
Inactive = "Inactive",
Deleted = "Deleted",
}The entity column references this enum:
@Column({ type: 'enum', enum: ProjectStatusEnum, default: 'Active' })
status: ProjectStatusEnum;Important: The values array is required when type is "enum". Omitting it will cause a validation error during scaffolding.
json
Arbitrary JSON data, stored as PostgreSQL jsonb for efficient querying and indexing.
{ "name": "metadata", "type": "json" }
{ "name": "settings", "type": "json", "nullable": true }| Generated Code | |
|---|---|
| TypeORM | @Column('jsonb') |
| TypeScript | any (or typed by your extension code) |
| Validation | None auto-applied |
Tip: While the generated type is
any, you can add type safety in your extension service or DTO by defining an interface for the expected JSON structure.
PostGIS Spatial Types
Apso supports the full suite of PostGIS spatial data types for geographic and geometric data. These types are powerful for location-based applications, mapping, geofencing, and spatial analysis.
Prerequisite: PostGIS spatial types require the PostGIS extension to be installed in your PostgreSQL database:
CREATE EXTENSION IF NOT EXISTS postgis; -- Verify installation SELECT PostGIS_Version();Ensure PostGIS is available in all environments (development, staging, production) where your application runs.
point
A single point in 2D space (x, y coordinates).
{ "name": "location", "type": "point", "nullable": true }| Generated Code | |
|---|---|
| TypeORM | @Column({ type: 'point' }) with value transformer |
| TypeScript | { x: number, y: number } |
| Validation | None auto-applied |
The generated code includes a value transformer that converts between the TypeScript object format and PostgreSQL’s point representation:
@Column({
type: 'point',
transformer: {
to: (point: { x: number, y: number } | null) => {
if (!point) return null;
return `(${point.x},${point.y})`;
},
from: (pgPoint: string | null) => {
if (!pgPoint) return null;
const [x, y] = pgPoint.substring(1, pgPoint.length - 1).split(',');
return { x: parseFloat(x), y: parseFloat(y) };
}
},
nullable: true
})
location: { x: number, y: number };linestring
A sequence of points forming a line.
{ "name": "route", "type": "linestring", "nullable": true }| Generated Code | |
|---|---|
| TypeORM | @Column({ type: 'linestring' }) with value transformer |
| TypeScript | Spatial type |
| Validation | None auto-applied |
polygon
A closed shape defined by one or more rings of points. The first ring is the outer boundary; subsequent rings define holes.
{ "name": "boundary", "type": "polygon", "nullable": true }| Generated Code | |
|---|---|
| TypeORM | @Column({ type: 'polygon' }) with value transformer |
| TypeScript | { coordinates: Array<Array<{ x: number, y: number }>> } |
| Validation | None auto-applied |
The generated transformer handles conversion to and from PostgreSQL’s WKT (Well-Known Text) format:
@Column({
type: 'polygon',
transformer: {
to: (polygon) => {
if (!polygon) return null;
const rings = polygon.coordinates.map(ring => {
const coords = ring.map(coord => `${coord.x} ${coord.y}`).join(',');
return `(${coords})`;
});
return `POLYGON(${rings.join(',')})`;
},
from: (pgPolygon) => {
if (!pgPolygon) return null;
// ... parses WKT back to coordinate arrays
}
},
nullable: true
})
boundary: { coordinates: Array<Array<{ x: number, y: number }>> };multipoint
A collection of points.
{ "name": "stops", "type": "multipoint", "nullable": true }| Generated Code | |
|---|---|
| TypeORM | @Column({ type: 'multipoint' }) |
| TypeScript | Spatial type |
| Validation | None auto-applied |
multilinestring
A collection of linestrings.
{ "name": "routes", "type": "multilinestring", "nullable": true }| Generated Code | |
|---|---|
| TypeORM | @Column({ type: 'multilinestring' }) |
| TypeScript | Spatial type |
| Validation | None auto-applied |
multipolygon
A collection of polygons.
{ "name": "territories", "type": "multipolygon", "nullable": true }| Generated Code | |
|---|---|
| TypeORM | @Column({ type: 'multipolygon' }) |
| TypeScript | Spatial type |
| Validation | None auto-applied |
geometry
A generic geometry type that can store any geometry (point, line, polygon, etc.).
{ "name": "shape", "type": "geometry", "nullable": true }| Generated Code | |
|---|---|
| TypeORM | @Column({ type: 'geometry' }) with pass-through transformer |
| TypeScript | any |
| Validation | None auto-applied |
@Column({
type: 'geometry',
transformer: {
to: (geometry: any) => {
if (!geometry) return null;
return geometry;
},
from: (pgGeometry: any) => {
if (!pgGeometry) return null;
return pgGeometry;
}
},
nullable: true
})
shape: any;geography
Similar to geometry but uses geographic coordinates (latitude/longitude) on a spherical model. Calculations account for the Earth’s curvature, making it more accurate for real-world distance and area computations.
{ "name": "position", "type": "geography", "nullable": true }| Generated Code | |
|---|---|
| TypeORM | @Column({ type: 'geography' }) |
| TypeScript | Spatial type |
| Validation | None auto-applied |
geometrycollection
A collection of heterogeneous geometry objects.
{ "name": "features", "type": "geometrycollection", "nullable": true }| Generated Code | |
|---|---|
| TypeORM | @Column({ type: 'geometrycollection' }) |
| TypeScript | Spatial type |
| Validation | None auto-applied |
Complete Type Mapping Reference
| Apso Type | TypeORM Column | PostgreSQL Type | TypeScript Type | Auto-Validation |
|---|---|---|---|---|
text | @Column({ type: 'text' }) | TEXT | string | @IsString(), @IsNotEmpty() |
integer | @Column({ type: 'integer' }) | INTEGER | number | @IsNumber() |
float | @Column({ type: 'float' }) | FLOAT | number | @IsNumber() |
boolean | @Column({ type: 'boolean' }) | BOOLEAN | boolean | @IsBoolean() |
decimal | @Column({ type: 'decimal' }) | DECIMAL(p,s) | number | @IsNumber() |
numeric | @Column({ type: 'numeric' }) | NUMERIC(p,s) | number | @IsNumber() |
date | @Column({ type: 'date' }) | DATE | Date | None |
timestamptz | @Column({ type: 'timestamptz' }) | TIMESTAMPTZ | Date | None |
enum | @Column({ type: 'enum', enum: ... }) | ENUM(...) | Generated enum | None |
json | @Column('jsonb') | JSONB | any | None |
point | @Column({ type: 'point' }) | POINT | { x, y } | None |
linestring | @Column({ type: 'linestring' }) | LINESTRING | Spatial | None |
polygon | @Column({ type: 'polygon' }) | POLYGON | { coordinates } | None |
multipoint | @Column({ type: 'multipoint' }) | MULTIPOINT | Spatial | None |
multilinestring | @Column({ type: 'multilinestring' }) | MULTILINESTRING | Spatial | None |
multipolygon | @Column({ type: 'multipolygon' }) | MULTIPOLYGON | Spatial | None |
geometry | @Column({ type: 'geometry' }) | GEOMETRY | any | None |
geography | @Column({ type: 'geography' }) | GEOGRAPHY | Spatial | None |
geometrycollection | @Column({ type: 'geometrycollection' }) | GEOMETRYCOLLECTION | Spatial | None |
Field Options Reference
These options apply across field types where relevant:
| Option | Type | Applies To | Generated Code |
|---|---|---|---|
nullable | boolean | All types | @Column({ nullable: true }) + @IsOptional() |
unique | boolean | All types | @Column({ unique: true }) |
default | string, number, boolean | All types | @Column({ default: value }) |
length | integer | text | @Column({ length: n }) + @MaxLength(n) |
is_email | boolean | text | @IsEmail() |
values | string[] | enum (required) | @Column({ enum: [...] }) |
precision | integer | decimal, numeric | @Column({ precision: n }) |
scale | integer | decimal, numeric | @Column({ scale: n }) |
Practical Examples
User entity
{
"name": "User",
"created_at": true,
"updated_at": true,
"fields": [
{ "name": "email", "type": "text", "length": 255, "unique": true, "is_email": true },
{ "name": "fullName", "type": "text", "nullable": true },
{ "name": "role", "type": "enum", "values": ["User", "Admin", "SuperAdmin"], "default": "User" },
{ "name": "isActive", "type": "boolean", "default": true },
{ "name": "lastLoginAt", "type": "timestamptz", "nullable": true },
{ "name": "preferences", "type": "json", "nullable": true }
]
}Financial record
{
"name": "Transaction",
"created_at": true,
"fields": [
{ "name": "amount", "type": "decimal", "precision": 12, "scale": 2 },
{ "name": "currency", "type": "text", "length": 3 },
{ "name": "status", "type": "enum", "values": ["Pending", "Completed", "Failed", "Refunded"] },
{ "name": "metadata", "type": "json", "nullable": true }
]
}Location-aware entity
{
"name": "Store",
"created_at": true,
"updated_at": true,
"fields": [
{ "name": "name", "type": "text" },
{ "name": "address", "type": "text" },
{ "name": "location", "type": "point", "nullable": true },
{ "name": "deliveryZone", "type": "polygon", "nullable": true },
{ "name": "isOpen", "type": "boolean", "default": true }
]
}