Skip to content

Sequences

A sequence field auto-fills a formatted running number — INV-2025-000042, SKU-07 — on insert. The number is assigned by a per-entity database trigger, set-based over the whole inserted batch, so it stays correct and contention-safe even under bulk inserts and imports.

Add a <Sequence> field to the entity with a Format template. See Entities → Field types.

<Sequence Name="Sku" Format="SKU-#2" />
<Sequence Name="InvoiceNo" Format="INV-{yy}-#6" Scope="Invoice" />

The template mixes literal text, placeholder tokens, and a sequence marker:

  • #N — the running number, zero-padded to width N (e.g. #6000042).
  • A bare # (no digits) defaults to width 2 — this default lives in exactly one place, the shared FormatSequenceNumber function.
  • Date tokens ({yy}, {yyyy}, {MM}, …) and record-field placeholders (e.g. {Region}, {Region:initials}) are “cooked” from the record context before the number is applied.

At submit time the engine cooks the template and produces a pipe-delimited token the trigger consumes:

ResourceName | CookedTemplate | CompanyId | GuidKey
e.g. Invoice | INV-25-#6 | 1 | AB12CD3

The per-entity AFTER-INSERT trigger (installed by SequenceNumberSqlHandlerService from the entity migration) then, set-based for the whole batch:

  1. groups the inserted rows by (Format, ScopeKey) where ScopeKey = "{CompanyId}|{ResourceName}";
  2. reserves one contiguous block per group by advancing a counter in [Genie].[SequenceNumbers];
  3. assigns each row its number with ROW_NUMBER() and formats it via the shared [Genie].[FormatSequenceNumber] (SQL Server) / "Genie".format_sequence_number (PostgreSQL) function.

Those shared helper functions are deployed once at startup by the SequenceSqlContributor; the trigger itself is per-entity because it lives with the entity’s table. Both dialects are supported.

A form can show the user the next value before saving:

Method Route Returns
POST /api/v1/genie/object/sequence-number SuccessDataResult<string> — the previewed number

This calls a read-only preview function (GetSequenceNumberPreview / get_sequence_number_preview) that peeks at the counter + 1 without consuming it. See Object endpoints.

Sequence tokens are also available to the import pipeline through the Sequence(...) expression, so generated values (e.g. an SKU) can be produced during a bulk import while still respecting a hand-entered value:

Sequence('SKU-#2','Product','@SessionCompanyId','@Guid[7]')

See Import → expressions for the full signature.