Go Order Tutorial
Build understanding around one draft Order: load its complete item list, change Notebook quantity from 2 to 3, save the Order and line totals together, then read the result in a new process. Follow the recorded native SQLite application and learn why each query, expression and transaction boundary is needed. The version and publication boundaries below apply to this specific example.
The generator/runtime contract repair and pagination observations use the retained workspace: WORKSPACE PASS — RELEASE PENDING. Keep the selected Go workspace/module resolution; a newly published version needs its own qualification.
1. Prepare the example
You need the Go toolchain, the site checkout, and the retained built
golang-app-console workspace from the core Order receipt.
Read its build.toolchain, build.runtimeSource, build.runtimePackage and
verification.qualification entries for go before selecting dependencies.
The commands below assume that recorded workspace and its dependencies already
exist; they are not a clean-machine bootstrap or a claim that every published
runtime passes. For build/replay preparation use the retained workspace instructions.
Start a new model with the Go Quick Start, then use Order-scoped Assist for its generated Q/E/mutation methods. This page reuses the evaluated Order v1.0 model and the three-order fixture. Do not substitute the isolation/stock fixture: those are separately evaluated model revisions.
The complete application
contains imports, helpers, startup and all phase handlers. The excerpts below
are function-body excerpts from that application, not standalone files.
The source imports the generated lib facade plus the customer_order and order_item expression packages. required, nullable, check and report are application helpers, not new generated APIs. For new models obtain the package paths and method names through Assist.
2. Understand startup and run the first edit
ServiceRuntimeFromEnv() constructs the native provider and *runtime.UserContext. Check its returned error, then explicitly call EnsureSchema(context) before normal phases. Set ORDER_WORKFLOW_SERVICE_CORE_DATABASE_URL to the absolute database path as well as ORDER_DATABASE.
Module installation registers metadata and behavior. Schema reconciliation is an explicit database operation. Keep startup/admin schema work separate from request execution, and obtain tenant/actor/policy from trusted server context.
From the site root, run this sequence with a new disposable database:
export ORDER_WORKSPACE="$PWD/artifacts/order/2026-10-27/golang/golang-app-console"
export ORDER_FIXTURE="$PWD/static/examples/order/fixture.json"
export ORDER_DATABASE="$(mktemp -d)/orders.sqlite"
export ORDER_WORKFLOW_SERVICE_CORE_DATABASE_URL="$ORDER_DATABASE"
cd "$ORDER_WORKSPACE"
for phase in bootstrap seed draft-graph note-value note-null note-empty note-not-loaded invalid-quantity draft-edit restart-readback; do
../order "$phase"
done
Run seed once on the fresh database; the fixture program is not an import/upsert
service. Each phase starts a fresh process against the same absolute database
path. The two NotLoaded probes are intentional negative examples; their handler
reports the native error and finishes successfully.
| Stop and inspect | Expected result |
|---|---|
bootstrap | Explicit schema setup and ORDER_OK phase=bootstrap. |
seed and draft-graph | Three Orders, six items; ORD-2026-1001 is DRAFT with total 3850 USD cents. |
| Note phases | Value, SQL NULL, empty text and NotLoaded remain distinct. |
invalid-quantity | 0, -1, 1.5 and 101 rejected before save. |
draft-edit | Notebook quantity 3, Notebook line total 3750, Order total 5100. |
restart-readback | The same totals in a new process; Order and changed item version 2, untouched item version 1. |
The handlers print ORDER_CASE JSON and an ORDER_OK completion line. Find the
Order by business number and the line by SKU; generated numeric IDs are not
portable fixture keys. Compare the returned graph with these expected values
before adapting the operation to your own model.
3. Load the full Order before editing
rows, err := Q.CustomerOrders().WithOrderNumberIs("ORD-2026-1001").
SelectOrderItemListWith(Q.OrderItems().OrderBySkuCodeAsc().OrderByIdAsc().Limit(101)).Limit(2).
Comment("Load full draft and bounded full items").Purpose("Validate and edit one draft order").ExecuteForList(context)
The outer bound of 2 lets the application reject a duplicate business identity. The child bound of 101 is an overflow sentinel for a supported maximum of 100 items. Require exactly one Order, DRAFT status and at most 100 loaded items before continuing. A one-item preview is useful for a list screen, but cannot supply the complete total for an edit. The full source performs these checks after the query; keep them when adapting the excerpt.
comment describes the operation and purpose records the business reason.
Both travel with execution through the trusted context. A buyer filter in this
v1.0 fixture is a business predicate; it does not authenticate or authorize a
buyer. Use the separate buyer/tenant isolation contract
when implementing protected access.
4. Validate money and save one atomic edit
The application validates integral quantity in [1, 100], USD currency, each stored
line amount and the complete new Order total. Prices and totals are integer cents.
It finds exactly one SKU-NOTEBOOK, computes 3 × 1250 + 3 × 450 = 5100, then
changes the selected item and Order together. The following write excerpt assumes
those validated, fully loaded variables; it is not a replacement for validation.
The audit reason is Edit draft Order quantity and totals atomically, named
EDIT in most examples and editReason/EditReason in Go, Swift and .NET.
selected.UpdateQuantity(int64(quantity))
selected.UpdateLineTotalMinor(int64(quantity) * required(order_item.NewOrderItemExpression(selected).UnitPriceMinor().Eval()))
order.UpdateTotalMinor(total)
fmt.Println("ORDER_GRAPH_ATTEMPT")
_, err = order.AuditAs(editReason).Save(context)
return err
Validate signed bounds before converting them to uint64. Check every returned error. Expressions return (value, present); use the checked required helper for non-null money and the nullable helper for notes. Keep Go’s chain continuation dot at the end of the previous line, as in the excerpt.
A successful audited save returns the persisted typed entity. The core example reads again after mutation, rather than treating a pre-save object as independent evidence of committed state. A rejected stale write requires reloading authoritative state and a business decision before retrying; it is not permission to overwrite the winner or retry every provider error.
5. Use projections, nulls and pages deliberately
| Task | Go API in this example | Result / responsibility |
|---|---|---|
| Execute a bounded query | ExecuteForList(context) → result and error | Typed SmartList; preserve native errors and check cardinality. |
| Read selected money | customer_order.NewCustomerOrderExpression(order).TotalMinor().Eval() | Loaded integer cents; not a formatting or currency conversion API. |
| Access selected items | order.OrderItemList().Items() | Only the relation that was explicitly loaded. |
| Default a selected SQL NULL note | OrderNote().OrElse(&fallback) | Null-only fallback; an empty string stays empty and NotLoaded still reports a missing field. |
| Save an audited mutation | order.AuditAs(editReason).Save(context) | Persisted typed entity; the required transaction includes all changed entities. |
| Request an exact page total | Offset(uint64(offset)).Limit(uint64(limit)).Count() → page.TotalCount (pointer) | Total of the filtered set, independent of page length. |
The note accessors in the table are called on the corresponding E expression.
required, report, pageRows, load, edit and prepare_edit are application
helpers where present; they are not additional generated terminal methods.
| Note state | Expected behavior |
|---|---|
| Selected value | Leave at reception stays that value. |
| Selected SQL NULL | A null-only default produces No note. |
| Selected empty text | Remains the empty string. |
| Omitted field | Native NotLoaded diagnostic, including when a null-only default is attempted. |
For a read-only list screen, the existing bounded-page handler validates
offset >= 0 and 1 <= limit <= 3, sets a stable total/ID order and explicitly
selects one item preview per Order. With validated offset, limit and
buyer, its native query is:
page, err := Q.CustomerOrders().WithBuyerReferenceIs(buyer).OrderByTotalMinorAsc().OrderByIdAsc().
SelectOrderItemListWith(Q.OrderItems().OrderBySkuCodeAsc().OrderByIdAsc().Limit(1)).Offset(uint64(offset)).Limit(uint64(limit)).Count().
Comment("Read bounded Order pages").Purpose("Compare filtered totals and per-order item previews").ExecuteForList(context)
This query only reads. Do not save its one-item preview as if it were a full
Order edit or infer deletion of omitted items. The pagination fixture has eight
matching BUYER-EXPORT Orders, whereas the first-edit fixture above has three
Orders overall. See the page API decision guide
for fixture selection, continuous export, retained-ID jumps and aggregate results.
6. Diagnose a failure before changing code
For a field error preserve a recovered NotLoaded panic and its path. In cancellation cleanup, database/sql may return native sql.ErrTxDone after auto-rollback; the lifecycle/soak receipt checks actual lock and connection release rather than treating that message alone as a leak.
| Symptom | First action |
|---|---|
| Workspace or package missing | Confirm the retained artifact prerequisite; follow the Quick Start for fresh generation instead of assuming this checkout ships compiled outputs. |
| Empty Order or duplicate row | Confirm absolute DB path, fixture and business number; preserve the cardinality check. |
| Wrong total after edit | Check complete item loading and integer validation before the audited save. |
| Missing field error | Reload the field/relation explicitly; do not substitute a null default. |
| Version conflict | Reload authoritative state and decide whether the requested edit is still valid. |
| Busy/locked, commit or cancellation failure | Inspect native provider error and transaction boundary; follow the Go Order troubleshooting table. |
Continue with the Order API usage guide, Go advanced data operations, version and qualification table and documentation coverage matrix. The School regression baseline and all prior Order receipts remain unchanged.
Continue with advanced Order writes
Follow Go Advanced Order Mutations for explicit line deletion, legal state transitions and stale-version recovery. Each recipe explains its starting state, transaction boundary, native errors and independent readback using the existing qualified example. Start a fresh recipe database; do not reuse the quantity-edited database above.
Continue with Order queries
Use Go Order Queries for continuous export, retained-ID page jumps and provider summaries. The query recipes use separate nine-/ten-order datasets; keep the fixture and context/store lifetime with the operation you are learning.
Continue with buyer and tenant isolation
Use Go Order Isolation to upgrade the model to v1.1 and build root/buyer scope from an application-owned trusted session.