ent-framework
  • Ent Framework
  • Getting Started
    • Code Structure
    • Connect to a Database
    • Create Ent Classes
    • VC: Viewer Context and Principal
    • Ent API: insert*()
    • Built-in Field Types
    • Ent API: load*() by ID
    • N+1 Selects Solution
    • Automatic Batching Examples
    • Ent API: select() by Expression
    • Ent API: loadBy*() Unique Key
    • Ent API: update*()
    • Ent API: deleteOriginal()
    • Ent API: count() by Expression
    • Ent API: exists() by Expression
    • Ent API: selectBy() Unique Key Prefix
    • Ent API: upsert*()
    • Privacy Rules
    • Validators
    • Triggers
    • Custom Field Types
  • Ent API: Configuration and Types
  • Scalability
    • Replication and Automatic Lag Tracking
    • Sharding and Microsharding
    • Sharding Terminology
    • Locating a Shard and ID Format
    • Sharding Low-Level API
    • Shard Affinity and Ent Colocation
    • Inverses and Cross Shard Foreign Keys
    • Shards Rebalancing and pg-microsharding Tool
    • Connection Pooling
  • Advanced
    • Database Migrations and pg-mig Tool
    • Ephemeral (Symbol) Fields
    • Atomic Updates and CAS
    • Custom Field Refactoring
    • VC Flavors
    • Query Cache and VC Caches
    • Loaders and Custom Batching
    • PostgreSQL Specific Features
    • Query Planner Hints
    • Cluster Maintenance Queries
    • Logging and Diagnostic Tools
    • Composite Primary Keys
    • Passwords Rotation
  • Architecture
    • Abstraction Layers
    • Ent Framework, Meta’s TAO, entgo
    • JIT in SQL Queries Batching
    • To JOIN or not to JOIN
Powered by GitBook
On this page
  • Nullability: allowNull=true
  • Optionality: autoInsert="..."
  • autoUpdate

Was this helpful?

Edit on GitHub
  1. Getting Started

Built-in Field Types

Before we move to the next Ent API calls, let's talk about the Ent field types that are natively supported in Ent Framework:

Field Definition
TypeScript Type
PostgreSQL Type

{ type: String }

string

varchar, text, bigint, numeric, ...

{ type: ID }

string

varchar, text, bigint, ...

{ type: Number }

number

int, bigint, doube, ...

{ type: Date }

Date

timestamptz, timestamp

{ type: Boolean }

boolean

boolean

{ type: EnumType<"a" | "b">() }

"a" | "b"

varchar, text, ...

{ type: EnumType<42 | 101>() }

42 | 101

integer, ...

{ type: EnumType<MyEnum>() }

MyEnum

varchar, text, integer, ...

{ type: YourCustomType }

jsonc, bytea or anything else

You can also define custom field types: Custom Field Types

Fields may be nullable and optional, with the corresponding support from TypeScript side.

Nullability and optionality concepts are often times mixed up. In Ent Framework, they are independent on each other and are used for different use cases.

Nullability: allowNull=true

By default, all fields can't store a null TypeScript value. To allow storing of a null, use the allowNull syntax:

const schema = new PgSchema(
  "topics",
  {
    ...
    // TypeScript type will be: string | null.
    company_id: { type: ID, allowNull: true },
    // TypeScript type will be: string (non-nullable).
    slug: { type: String },
  },
  ["slug"]
);

Notice that if your field is nullable, it doesn't mean that it is optional. Nullability and optionality are independent concepts in both Ent Framework and TypeScript. E.g. you can have a required nullable field which allows saving null in it, but you will still need to explicitly pass this null in your TypeScript code:

await EntTopic.insertReturning(vc, { slug: "abc" });
// ^ TypeScript error: missing required property, company_id.

await EntTopic.insertReturning(vc, { company_id: null, slug: "abc" });
// ^ OK.

By default, each field in the schema is required at insert time. I.e. if you run an insert*() call, then TypeScript won't let you skip a required field.

Optionality: autoInsert="..."

To make a field optional, you can use autoInsert="sql expression" modifier: it makes the field optional at insert time. Ent Framework will use the raw SQL expression provided if you don't mention an explicit field value on an insert (which is convenient when doing refactoring for instance).

Several examples:

const schema = new PgSchema(
  "topics",
  {
    // If not passed in insert*() call, uses nextval('topics_id_seq').
    id: { type: ID, autoInsert: "nextval('topics_id_seq')" },
    // If not passed in insert*() call, uses now().
    created_at: { type: Date, autoInsert: "now()" },
    // If not passed in insert*() call, uses NULL.
    company_id: { type: ID, allowNull: true, autoInsert: "NULL" },
    // Required AND non-nullable at the same time.
    slug: { type: String },
  },
  ["slug"]
);

Notice that now company_id field is both optional and nullable. I.e. you can run this code:

await EntTopic.insertReturning(vc, { slug: "abc" });
// ^ OK: company_id is both optional and nullable.

An example of optional, but non-nullable field is created_at. I.e. you can omit this field when inserting (and thus, Ent Framework will use now() SQL expression for its value), but you can't pass a null TypeScript value there, and your topic.created_at will be of type Date, not Date | null or Date | undefined.

autoUpdate

There is also one more way to mark the field as optional, use autoUpdate modifier. It is very similar to autoInsert, but additionally, if the value is omitted at an update*() call, then it will be automatically set to the result of the provided SQL expression. A classical use case for it is updated_at field:

const schema = new PgSchema(
  "topics",
  {
    // Defaults to now() if not mentioned at insert time.
    created_at: { type: Date, autoInsert: "now()" },
    // Auto-set to now() if not mentioned at update time.
    updated_at: { type: Date, autoUpdate: "now()" },
    ...
  },
  ["slug"]
);
PreviousEnt API: insert*()NextEnt API: load*() by ID

Last updated 12 days ago

Was this helpful?

see

Custom Field Types