Skip to content

Database & DATA Intents

DATA is a revision of an identity. FILE is bytes at a name.

The database-equivalent in D/BASIC is the DATA Intent family. An application asks for semantic database records, immutable views, exact revisions, and durable artifacts. The runner owns the actual store, sessions, authentication, snapshots, and recovery state. A BASIC program receives no host path, store handle, page ID, native pointer, or provider object.

Three similar names have three different jobs:

Thing Job
DATA Intent database-style identities, revisions, snapshots, and artifacts
FILE Intent named byte streams, directories, and manipulation; see Files & File Manipulation
DATA / READ statement a small immutable table compiled into source; see Console I/O & Embedded DATA

This distinction is a gift to future you. A document cannot accidentally become “whatever happens to be at this laptop path,” and a file copy does not pretend to have revision history it never received.

Ask for data, not the storage engine

When semantic data is essential, say so in the application contract. The runner can preflight that promise instead of presenting a window that can never do its job.

APP "IDEA CABINET"
  LABEL "Idea Cabinet"
  NEEDS DATA
END APP

IMPORT dworks.data BAKED

DIM Caps%(0 TO 27)
DworksDataQueryCaps Caps%()
PRINT "DATA PROVIDER ADMITTED"
END

dworks.data is a checked declaration layer. It does not link a database or smuggle in a filesystem. BAKED keeps this sample self-contained; normal imports also allow an exact shared D/Works library. The runner admits and executes the underlying semantic operations through the Intent and Service contract.

Identity, revision, snapshot

A team note is not identified by a filename. It has an opaque identity. A save says, “change this identity only if it is still at this revision.” A browse operation opens a stable view so a person's selected row does not quietly turn into another object after a concurrent edit.

database identity → owner-bound session → immutable snapshot → selected identity rechecked → durable receipt

The host owns live capability state. An adapter may represent it in source, but its slot, generation, root receipt, provider handle, and native connection are not values to place in a TYPE, CLASS, or DOBJ.

The friendly database projection

Most programs should feel like they are working with a small, careful database library—not a packet builder. DataDatabase, DataView, and DataPage are the object-oriented projection. They are bounded adapters over opaque DATA records; they do not expose the host session's slot or generation.

IMPORT dworks.data BAKED

DIM Db AS DataDatabase
DIM View AS DataView
DIM Page AS DataPage

Db.OpenRead ProjectDatabaseId()
View.Open Db, BudgetDocumentsQuery()

DO
  View.FetchPage Page
  ' Paint or inspect Page's stable object/class rows.
LOOP WHILE Page.HasMore

View.Accept SelectedObjects()
View.Close
Db.Close
END

The point of this shape is teaching as much as convenience: Db owns the database session, View owns one immutable query binding, Page is only a bounded observation, and Accept validates the exact selected identities. Your own query/value helpers are application concepts; the host never has to guess whether a string is a path, a SQL fragment, or a native handle.

Queries are semantic, not SQL strings

A snapshot query carries a nonzero query identity and scope, plus one bounded filter:

Filter Meaning
ALL every visible object in the scope
CLASS objects of one semantic class
COLLECTION members of one collection
REFERENCES objects related through one semantic reference
PROPERTY_EQUALS objects whose named property equals one bounded predicate value

An optional UTF-8 search term is bounded to 48 bytes; a property predicate is bounded to 96 bytes. The provider may use SQL, an object store, an index, or a tiny fixed database internally, but the query does not expose that implementation. The returned binding pins schema, content, and index revisions together with the snapshot identity.

Values keep their meaning

GET_VALUE can return unset, Boolean, signed 64-bit integer, decimal, money, percentage, text, bytes, date, time, date-time, duration, enum, quantity, resource, reference, Works link, or a bounded multiple value of up to eight elements. Each result carries the exact database revision that made it true. A typed D/Works adapter turns that semantic value into ordinary D/BASIC values and objects without exposing storage pages or native handles.

Beneath the objects: the typed carrier layer

Under the friendly objects, dworks.data provides a deliberately compact carrier layer: checked encoders over exact rank-one INTEGER arrays. Each element provides two little-endian bytes. Let the wrapper preserve wire sizes and reserved fields; application code should not invent session records.

IMPORT dworks.data BAKED

DIM Session%(0 TO 7)

' Opens the host-selected semantic namespace. Its configured native directory,
' if it has one, remains host configuration rather than program data.
DworksDataOpenMounted Session%()

' ...perform typed DATA work with the owner-bound session...
DworksDataClose Session%()
END

The browser preview's admitted DATA mount

The playground currently admits one browser-local database identity: the exact sixteen UTF-8 bytes D/BASIC-BROWSER1. Its DATA mutations and artifact bodies are stored in the browser's durable local object store. OPEN with any other identity refuses; a random nonzero identity is not an implicit create-database operation. A packaged product supplies its own admitted identity through the typed wrapper rather than copying this developer-preview value.

Wrapper DATA row Meaning
DworksDataQueryCaps QUERY_CAPS supported values, record sizes, and session limits
DworksDataOpen / DworksDataOpenMounted OPEN an owner-bound database session
DworksDataGetValue GET_VALUE one typed value plus exact revision
DworksDataOpenSnapshot OPEN_SNAPSHOT an immutable query binding
DworksDataFetchPage FETCH_PAGE zero to sixteen stable rows
DworksDataResolveRow / DworksDataRevalidateObject RESOLVE_ROW / REVALIDATE_OBJECT check a displayed object precisely
DworksDataAcceptExact ACCEPT_EXACT validate one to sixteen selected IDs in caller order
DworksDataCloseSnapshot / DworksDataClose CLOSE_SNAPSHOT / CLOSE release the view, then its parent session

Close views before their parent database. Process exit is the final host-side revocation path, not a substitute for normal cleanup.

Browse without a race

A list is a promise to a person. Use this flow when the person will act on a selection:

  1. Open a database session.
  2. Open one immutable snapshot for the query.
  3. Fetch pages of at most sixteen stable rows.
  4. Retain stable object IDs, not just screen indices.
  5. Resolve or revalidate the chosen object before a consequential action.
  6. Use ACCEPT_EXACT when the host must validate one to sixteen selected IDs.
  7. Close snapshot, then session.

ACCEPT_EXACT is idempotent: repeating the same binding and object sequence is still the same validation. It is not a database write transaction and not a durable exactly-once ledger.

The carrier contract

Library authors may call generated Intent names directly. Their arrays must be rank-one, non-aliasing, and exactly sized. Output becomes visible only after a matching successful completion and reply decode—never partially on a pending, failed, stale, malformed, or aliased call.

DIM OpenRequest%(0 TO 9)
DIM Session%(0 TO 7)

' A library encoder fills this twenty-byte request. It is shown to expose the
' boundary; ordinary application code should call DworksDataOpen instead.
INTENT DATA.OPEN(OpenRequest%(), Session%())
END
Row Input carrier Output carrier
QUERY_CAPS 56 B / 28 INTEGERs
OPEN 20 B / 10 16 B / 8
GET_VALUE 32 B / 16 864 B / 432
OPEN_SNAPSHOT 192 B / 96 52 B / 26
FETCH_PAGE 60 B / 30 296 B / 148
RESOLVE_ROW 64 B / 32 16 B / 8
REVALIDATE_OBJECT 60 B / 30 16 B / 8
ACCEPT_EXACT 184 B / 92
CLOSE / CLOSE_SNAPSHOT 16 B / 8

Every DATA request is tracked and asynchronous beneath the friendly projection. That lets the runner work or park without corrupting the last honest model.

Mutable records and streamed attachments

Snapshots make reading stable. The write-session family makes a database mutation equally explicit: it is a transaction against known base revisions, not an unguarded “update this row” side effect. It is especially useful when a record owns a large attachment such as an image, sound, or document body.

QUERY_WRITE_CAPS → OPEN_WRITE → BEGIN_WRITE → begin/stream/finish attachments → COMMIT_WRITE → terminal outcome/status → CLOSE_WRITE
DATA row Job
QUERY_WRITE_CAPS discover write sessions, transactions, attachment slots, max attachment size, and 256-byte chunk support
OPEN_WRITE open an owner-bound write database session and receive its current revision binding
BEGIN_WRITE begin one transaction with a nonzero transaction UUID and expected root/schema/content/index revisions
BEGIN_ATTACHMENT name one object/property attachment, operation sequence, byte length, SHA-256, and media type
WRITE_ATTACHMENT_CHUNK write one at-most-256-byte attachment segment at its explicit offset
FINISH_ATTACHMENT prove the attachment's final length and SHA-256
COMMIT_WRITE request the transaction's terminal outcome
WRITE_STATUS recover the outcome for a transaction UUID
ABORT_WRITE deliberately abandon an in-progress transaction
CLOSE_WRITE release the owner-bound write session

The write sequence has two scopes. OPEN_WRITE creates a long-lived owner-bound session. BEGIN_WRITE creates one transaction within it, bound to all four expected revisions. A stale base is therefore a named state conflict, not an opportunity to overwrite somebody else's newer document.

Attachments are staged and verified

BEGIN_ATTACHMENT names a nonzero object and property, a nonzero operation sequence, exact byte length, full SHA-256, and a validated media type. It returns an attachment binding tied to that transaction. Send ordered bounded chunks through WRITE_ATTACHMENT_CHUNK; each reply carries the next expected offset. Finish only with the same total length and digest promised at begin.

This gives the host a useful safety rule: attachment bytes are not a live resource merely because the first chunk arrived. A failed or abandoned stream does not turn into a half-image in a record. For a reusable packaged image or sound, see Resources, Images & Sound; DATA attachments belong to the database object's transaction and revision.

Commit, status, and recovery

COMMIT_WRITE and WRITE_STATUS return an 80-byte outcome. Its state is one of PENDING, COMMITTED, ABORTED, or REOPEN_REQUIRED; it also carries the transaction UUID and the root/schema/content/index revisions. A committed outcome carries exactly one resulting resource ID. REOPEN_REQUIRED tells the application to reopen and ask status, rather than guessing whether its mutation made it through an interruption.

OPEN_WRITE and COMMIT_WRITE are deliberately not idempotent. Retain the transaction UUID, ask WRITE_STATUS when completion is uncertain, then either continue from the terminal fact or begin a new transaction. ABORT_WRITE and CLOSE_WRITE are normal cleanup, not signs that the program did something wrong.

For library authors, the exact carrier shapes are:

Row Request Reply
QUERY_WRITE_CAPS 96 B / 48 INTEGERs
OPEN_WRITE 20 B / 10 48 B / 24
BEGIN_WRITE 64 B / 32 64 B / 32
BEGIN_ATTACHMENT 176 B / 88 40 B / 20
WRITE_ATTACHMENT_CHUNK 304 B / 152 48 B / 24
FINISH_ATTACHMENT 80 B / 40
COMMIT_WRITE 64 B / 32 80 B / 40
WRITE_STATUS 32 B / 16 80 B / 40
ABORT_WRITE 64 B / 32
CLOSE_WRITE 16 B / 8

Like the read family, this is a DATA boundary: no attachment path, native stream handle, or storage-provider pointer crosses into BASIC. A friendly write-session adapter belongs above these records, just as DataDatabase and DataView sit above their read records.

Artifacts: new, save, save as, publish

A D/Write document, D/Calc sheet, or future rich object is a semantic artifact: canonical bytes with an identity and revision. The verbs make their different promises explicit:

Operation Promise
BEGIN_NEW create a new durable identity
BEGIN_SAVE compare-and-save one identity against its expected base revision
BEGIN_SAVE_AS create a new identity without mutating the source
BEGIN_PUBLISH make an immutable publication while preserving source revision
BEGIN_RETIRE withdraw an artifact through the same governed receipt flow

The typed lifecycle is DworksDataQueryArtifactCaps, DworksDataBeginNew, DworksDataBeginSave, DworksDataBeginSaveAs, DworksDataBeginPublish, DworksDataBeginRetire, DworksDataWriteArtifactChunk, DworksDataFinishArtifact, DworksDataCommitArtifact, DworksDataArtifactStatus, DworksDataAbortArtifact, DworksDataCloseArtifact, and DworksDataAckArtifactReceipt.

allocate operation → begin → write 256-byte chunks → finish with SHA-256 → commit → retain receipt → exact acknowledgement

The host issues the operation UUID through DworksDataAllocateArtifactOperation; the application does not invent one. WRITE_ARTIFACT_CHUNK carries at most 256 bytes. FINISH_ARTIFACT proves the declared SHA-256 before commit. A replay of one UUID with different parameters refuses. The resulting 192-byte receipt records operation/kind/state, source/result identities, relevant revisions, publication details, payload digest, and receipt identity/digest.

Keep that exact operation UUID and receipt until recovery is complete. An interrupted operation may yield REOPEN_REQUIRED: call ARTIFACT_STATUS after reopening and recover the byte-identical receipt rather than guessing whether a save happened.

Library-author carrier shapes are exact here too:

Artifact row Request Reply
QUERY_ARTIFACT_CAPS 64 B / 32 INTEGERs
each BEGIN_* 96 B / 48 40 B / 20
WRITE_ARTIFACT_CHUNK 280 B / 140 24 B / 12
FINISH_ARTIFACT 56 B / 28
COMMIT_ARTIFACT / ARTIFACT_STATUS 16 B / 8 192 B / 96
ABORT_ARTIFACT / CLOSE_ARTIFACT 16 B / 8
ACK_ARTIFACT_RECEIPT 64 B / 32
ALLOCATE_ARTIFACT_OPERATION 16 B / 8
LIST_ARTIFACTS / LIST_PUBLICATIONS 16 B / 8 272 B / 136
OPEN_ARTIFACT_READ / OPEN_PUBLICATION_READ 24 B / 12 80 B / 40
READ_ARTIFACT_CHUNK 24 B / 12 280 B / 140
CLOSE_ARTIFACT_READ 16 B / 8

For artifact readback, use DworksDataListArtifacts or DworksDataListPublications (each page is at most eight rows), then open one exact identity/revision through DworksDataOpenArtifactRead or DworksDataOpenPublicationRead. DworksDataReadArtifactChunk returns at most 256 bytes, and DworksDataCloseArtifactRead revokes the owner-bound read session. Host authentication filters lists and exact opens; no path or provider iterator crosses the DATA boundary.

Refusals keep the database honest

Missing providers/rows, unsupported values, malformed shapes, stale bindings, capability mismatches, and capacity pressure are named refusals. An ordinary not-found observation may remain a normal status. Catch a refusal only when an alternative recovery path exists:

IMPORT dworks.data BAKED

DIM Session%(0 TO 7)
ON REFUSAL GOTO DataUnavailable

DworksDataOpenMounted Session%()
PRINT "DATA SESSION OPEN"
DworksDataClose Session%()
END

DataUnavailable:
PRINT "DATA OPERATION REFUSED. RULE "; ERR
END

Keep the last verified document visible until a terminal result says otherwise. Do not paint an artifact prefix, replace an old revision before a receipt, or equate a pressed Save button with durability.

One source, several honest hosts

Host What the runner may do
browser / WebAssembly expose an admitted semantic provider without leaking browser storage internals or ambient files
Windows, Linux, macOS use a durable host provider with atomicity and recovery checks
D/OS with DATA retain sessions/artifacts behind the trusted runtime
no provider refuse the DATA route by name; never offer a pretend empty database

Richer hosts can improve capacity or durability. They cannot turn an identity into a path, publish partial output, or claim an unadmitted operation succeeded.

Import and export cross the boundary deliberately

Exporting a database artifact to a mount is two honest operations: open and read the exact DATA identity/revision, then create, write, and commit a new FILE. Importing is the reverse: read the named FILE, validate and canonicalize it privately, then create a new DATA artifact with BEGIN_NEW.

Both are copies. Export does not give the file a live database link, and import does not grant the application arbitrary filesystem authority. If either half fails, report which side succeeded and keep the previously verified object visible.

Data checklist

  1. Use DATA Intents for identities/revisions and FILE for named bytes.
  2. Keep embedded DATA tables separate from both.
  3. Prefer dworks.data over hand-packed carriers.
  4. Close snapshots before sessions.
  5. Revalidate a selected stable ID before consequential work.
  6. Treat Save, Save As, and Publish as different identity operations.
  7. Retain the operation UUID and receipt through recovery.
  8. Make refusal, cancellation, and close paths first-class.

Next: Windows & Events →