Skip to content

Database & DATA Intents

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

This page is about d/BASIC's database. After reading it you will know how a program opens a database, browses records without them changing under the reader, writes changes that cannot overwrite someone else's newer work, attaches images and sounds to records, and saves documents so that a save either happened or did not.

The database in d/BASIC is the DATA intent family. An intent is a named request, such as "open this database" or "fetch the next page", that the machine carries out however it can. Your program asks for records, stable views, exact revisions and durable documents. The d/OS runtime, the program that runs your compiled code, owns the actual store, its sessions, sign-in, snapshots and recovery. A BASIC program never receives a host path, a store handle, a page number, a native pointer or an object from the storage engine.

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 fixed table compiled into source; see Console I/O & Embedded DATA

This separation is a gift to your future self. A document cannot quietly become "whatever happens to be at this path on this laptop", and a copied file cannot pretend to have a revision history it never had.

Ask for data, not the storage engine

When a program cannot work without its data, say so in the application header. The runtime can then check that promise before it opens a window that could 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 from d/Works, the office suite being written in d/BASIC (d/Write, d/Calc, d/Present). It does not link in a database engine and does not sneak in a filesystem. BAKED keeps this sample self-contained; ordinary imports can also bind an exact shared d/Works library. The runtime checks each underlying operation before it runs and carries it out through the same machinery as every other intent and service.

Identity, revision, snapshot

A team note is not identified by a filename. It has an identity: an opaque value the program never takes apart. A save says "change this identity only if it is still at this revision". A browse opens a stable view, so the row a person selected does not silently turn into a different object after someone else edits.

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

The host owns the live state of a session. A library may represent that session in your source, but its slot number, its version number, its root record, the handle the storage side uses and the native connection are not values you may put in a TYPE, a CLASS or a DOBJ (the typed object a program hands to another program when you drag, drop, copy or paste).

The friendly database projection

Most programs should feel as if they are using a small, careful database library, not building packets. DataDatabase, DataView and DataPage are the object-oriented layer. They are bounded wrappers over opaque DATA records; they do not expose the host session's slot or version number.

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 shape teaches as much as it helps: Db owns the database session, View owns one frozen query, Page is only a bounded look at it, and Accept checks the exact identities you selected. Your own query and value helpers are application concepts; the host never has to guess whether a string is a path, a fragment of SQL or a native handle.

Queries are semantic, not SQL strings

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

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

An optional UTF-8 search term is limited to 48 bytes; a property value to 96 bytes. The part of the host that supplies the data may use SQL, an object store, an index or a tiny fixed database internally, but the query never exposes which. The view you get back fixes the 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 wrapper turns that value into ordinary d/BASIC values and objects without exposing storage pages or native handles.

Beneath the objects: the raw record layer

Under the friendly objects, dworks.data provides a deliberately compact lower layer: checked encoders over one-dimensional INTEGER arrays of exact size, which carry the request and reply bytes two little-endian bytes per element. Let the wrapper keep the wire sizes and reserved fields straight; 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 playground's one database

The playground currently accepts one browser-local database identity: the exact sixteen UTF-8 bytes D/BASIC-BROWSER1. Its DATA changes and document bodies are kept in the browser's durable local object store. OPEN with any other identity is declined; a random nonzero identity does not quietly create a database. A packaged product supplies its own accepted 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 a database session owned by your program
DworksDataGetValue GET_VALUE one typed value plus its exact revision
DworksDataOpenSnapshot OPEN_SNAPSHOT a frozen query
DworksDataFetchPage FETCH_PAGE zero to sixteen stable rows
DworksDataResolveRow / DworksDataRevalidateObject RESOLVE_ROW / REVALIDATE_OBJECT check a displayed object precisely
DworksDataAcceptExact ACCEPT_EXACT check one to sixteen selected IDs in the order you give them
DworksDataCloseSnapshot / DworksDataClose CLOSE_SNAPSHOT / CLOSE release the view, then the session that owns it

Close views before the database that owns them. Process exit is the host's last-resort cleanup, not a substitute for closing things yourself.

Browse without a race

A list is a promise to a person. Use this flow whenever the person will act on what they select:

  1. Open a database session.
  2. Open one frozen snapshot for the query.
  3. Fetch pages of at most sixteen stable rows.
  4. Keep the stable object IDs, not just positions on the screen.
  5. Resolve or revalidate the chosen object before doing anything consequential with it.
  6. Use ACCEPT_EXACT when the host must check one to sixteen selected IDs.
  7. Close the snapshot, then the session.

ACCEPT_EXACT is safe to repeat: the same snapshot and the same object sequence give the same check. It is not a write transaction and not a durable exactly-once record.

The raw record contract

Library authors may call the generated intent names directly. Their arrays must be one-dimensional, exactly sized and not overlapping another argument. Output appears only after a matching successful completion and a fully decoded reply, never partially on a call that is pending, failed, out of date, malformed or overlapping.

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 Request Reply
QUERY_CAPS none 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 none
CLOSE / CLOSE_SNAPSHOT 16 B / 8 none

Every DATA request is tracked and runs asynchronously beneath the friendly layer. That lets the runtime work, or pause the program, without corrupting the last state it verified.

Mutable records and streamed attachments

Snapshots make reading stable. The write-session family makes a database change just as explicit: it is a transaction against known base revisions, not an unguarded "update this row". It is especially useful when a record owns a large attachment such as an image, a sound or a 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, the largest attachment, and 256-byte chunk support
OPEN_WRITE open a write session owned by your program and receive its current revision binding
BEGIN_WRITE begin one transaction with a nonzero transaction UUID and the expected root, schema, content and index revisions
BEGIN_ATTACHMENT name one object and property attachment, its operation sequence, byte length, SHA-256 and media type
WRITE_ATTACHMENT_CHUNK write one attachment segment of at most 256 bytes at its explicit offset
FINISH_ATTACHMENT prove the attachment's final length and SHA-256
COMMIT_WRITE ask for the transaction's final outcome
WRITE_STATUS recover the outcome for a transaction UUID
ABORT_WRITE deliberately abandon an in-progress transaction
CLOSE_WRITE release the write session

The write sequence has two scopes. OPEN_WRITE creates a long-lived session owned by your program. BEGIN_WRITE creates one transaction within it, tied to all four expected revisions. A stale base is therefore a named conflict, not a chance to overwrite somebody else's newer document.

Attachments are staged and verified

BEGIN_ATTACHMENT names a nonzero object and property, a nonzero operation sequence, the exact byte length, the 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 you promised at the start.

That gives the host a useful safety rule: attachment bytes are not real just because the first chunk arrived. A failed or abandoned stream never turns into half an image inside 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 and index revisions. A committed outcome carries exactly one resulting resource ID. REOPEN_REQUIRED tells the application to reopen and ask for status, rather than guess whether its change survived an interruption.

OPEN_WRITE and COMMIT_WRITE are deliberately not safe to repeat blindly. Keep the transaction UUID, ask WRITE_STATUS when you are not sure the commit finished, then either carry on from the answer or begin a new transaction. ABORT_WRITE and CLOSE_WRITE are ordinary cleanup, not signs that the program did something wrong.

For library authors, the exact record sizes are:

Row Request Reply
QUERY_WRITE_CAPS none 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 none
COMMIT_WRITE 64 B / 32 80 B / 40
WRITE_STATUS 32 B / 16 80 B / 40
ABORT_WRITE 64 B / 32 none
CLOSE_WRITE 16 B / 8 none

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

Artifacts: new, save, save as, publish

A d/Write document, a d/Calc sheet or a future rich object is an artifact: a document in its exact standard byte form, with an identity and a revision. The verbs make their different promises explicit:

Operation Promise
BEGIN_NEW create a new durable identity
BEGIN_SAVE save one identity only if it is still at the expected base revision
BEGIN_SAVE_AS create a new identity without changing the source
BEGIN_PUBLISH make an unchangeable publication while keeping the source revision
BEGIN_RETIRE withdraw an artifact through the same supervised flow, ending in the same kind of receipt

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 hands out the operation UUID through DworksDataAllocateArtifactOperation; the application never invents one. WRITE_ARTIFACT_CHUNK carries at most 256 bytes. FINISH_ARTIFACT proves the declared SHA-256 before the commit. Replaying one UUID with different parameters is declined. The result is a 192-byte receipt, the host's record of exactly what the operation did: its operation, kind and state, the source and result identities, the relevant revisions, publication details, the payload digest, and the receipt's own identity and digest.

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

Library-author record sizes are exact here too:

Artifact row Request Reply
QUERY_ARTIFACT_CAPS none 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 none
COMMIT_ARTIFACT / ARTIFACT_STATUS 16 B / 8 192 B / 96
ABORT_ARTIFACT / CLOSE_ARTIFACT 16 B / 8 none
ACK_ARTIFACT_RECEIPT 64 B / 32 none
ALLOCATE_ARTIFACT_OPERATION none 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 none

To read artifacts back, use DworksDataListArtifacts or DworksDataListPublications (each page holds at most eight rows), then open one exact identity and revision through DworksDataOpenArtifactRead or DworksDataOpenPublicationRead. DworksDataReadArtifactChunk returns at most 256 bytes, and DworksDataCloseArtifactRead ends the read session your program owns. The host's sign-in rules filter what the lists show and what may be opened; no path and no storage-side iterator crosses the DATA boundary.

Errors keep the database honest

A missing data service or operation, an unsupported value, a malformed request, a stale snapshot, a capability mismatch or a full store each stop with a named error that says what is wrong. An ordinary not-found result can stay an ordinary status. Catch one of these errors only when you have a real alternative:

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 on screen until a final result says otherwise. Do not paint a partly written artifact, replace an old revision before you hold the receipt, or treat a pressed Save button as proof the bytes are safe.

One source, several honest hosts

Host What the runtime may do
browser / WebAssembly offer an approved data service without leaking the browser's storage internals or ambient files
Windows, Linux, macOS use a durable host store with all-or-nothing commits and recovery checks
d/OS with DATA keep sessions and artifacts behind the trusted runtime
no data service decline the DATA route by name; never offer a pretend empty database

Richer hosts can add capacity or durability. They cannot turn an identity into a path, publish partial output, or claim an operation succeeded when it was never approved.

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 and revision, then create, write and commit a new FILE. Importing is the reverse: read the named FILE, check it and put it into standard form in private, then create a new DATA artifact with BEGIN_NEW.

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

Data checklist

  1. Use DATA intents for identities and revisions and FILE for named bytes.
  2. Keep embedded DATA tables separate from both.
  3. Prefer dworks.data over hand-packed records.
  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. Keep the operation UUID and receipt until recovery is complete.
  8. Make the error, cancel and close paths first-class.

Next: Windows & Events →