Skip to main content

SQL definition

Every field of a SQL connector's definition.json, what Owlie adds to each install's configuration, and what it derives from the definition. The machine-readable form is sql.schema.json, a JSON Schema (draft-07).

In the tables, Editable marks a field that accepts an install-editable value: instead of a literal, the bare expression { "$oxl": "config.<name>" } (an object whose only key is $oxl), where <name> is a field declared under config.properties with the same JSON type. Each install then reads its own copy of that field, seeded from the field's default. Only pageSize, sync.table and sync.where are editable; any expression elsewhere is refused.

Top level​

FieldTypeRequiredDefaultEditableWhat it does
engineintegerYesNoAlways 1.
dialectstringYesNopostgres, mysql, mssql or oracle.
descriptionstringNoNoThe catalog description.
iconstringNoNoThe catalog icon: @ plus a domain, or an https:// image URL.
validationQuerystringNoSELECT 1; on Oracle SELECT 1 FROM DUALNoThe connection test's query. Starts with SELECT or WITH.
configobjectNoNoHolds properties.
config.propertiesobjectNoNoThe install fields the definition reads, keyed by name. Each is a JSON Schema object: type, title, description, default (the seed), and for objects additionalProperties. A field without a default, or with any seed other than "" or null, is required at install. The base field names below, user, and password are refused.
pageSizeintegerNo500YesRows per page, 1 to 5000.
entitiesobjectYesNoAt least one entity, keyed by entity key: lowercase letters, digits and _, starting with a letter.
grant_kindsobjectNoNoGrant kinds, keyed by lowercase letters, digits and _, starting with a letter.
custom_opsobjectNoNoPowerShell custom operations, keyed by operation key.
handlersobjectNoNoPowerShell scripts that replace engine handlers, keyed by handler key.

No other top-level field is accepted.

Entity fields​

Each entry of entities:

FieldTypeRequiredDefaultWhat it does
namestringNoThe entity keyWhat Owlie calls the records.
is_accountbooleanNofalseThe account entity. At most one entity has it.
identifierstringYesThe column whose value is the record's external id. One of columns; always kept as text.
columnsobjectYesAt least one column, keyed by column name.
syncobjectYesWhich rows Sync reads.
statementsobjectNoWrite statements, keyed by operation.

A connector with any statement or any Grant kind add needs an account entity.

columns​

Each column name matches ^[A-Za-z_][A-Za-z0-9_$]*$; owlie_src, owlie_rel and owlie_source are refused. Each entry:

FieldTypeRequiredDefaultAllowed valuesWhat it does
typestringNostringstring, number, bigint, int8, boolean, datetimeHow the value is read. bigint and int8 are the same: always text. number stays text past exact integer precision. boolean is true for 1, t, true, y, yes. datetime is ISO 8601; a zoneless timestamp is read as UTC.
titlestringNoThe label Owlie shows.
sensitivebooleanNofalseMark the value as secret or personal data.

sync​

FieldTypeRequiredEditableWhat it does
tablestringOne of table and selectStatementYesA table or view, table or schema.table. An unqualified table resolves in the install's defaultSchema, when set.
selectStatementstringOne of table and selectStatementNoA SELECT or WITH whose rows are the records.
wherestringNoYesWith table only: a condition without the word WHERE.
orderKeystringYesNoA unique, orderable column. Pages are keyset pages on it.
updatedAtstringNoNoA timestamp column. Enables <entity>.fetchAllSince; each run reads rows at or after the last marker.

selectStatement and where contain no ;, no comments and no :name placeholders. An install's where is checked the same way. orderKey and updatedAt are plain identifiers, like column names.

statements​

Each statement is one INSERT, UPDATE, DELETE or MERGE (createdId is a SELECT), with no ; and no comments.

FieldTypeMay bindMust bindWhat it does
createstringAny columnNothingCreates a record. Returns the new identifier with RETURNING or OUTPUT (the column named like the identifier), or relies on createdId or the input.
createdIdstringAny columnNothingWith create only: a SELECT, run in the create's transaction, that returns the new row's identifier, from the column named like it or else the first column.
updatestringAny columnThe identifierUpdates a record. Every column is bound from the current row, with the input on top.
deletestringThe identifierThe identifierDeletes a record. No row changed is an error.
enablestringThe identifierThe identifierEnables an account. No row changed is an error.
disablestringThe identifierThe identifierDisables an account. No row changed is an error.

A column that create or update binds is writable; every other column is read-only. A placeholder must name a declared column. Statements run as written, in the install's defaultSchema when it is set, so a table named without a schema resolves there.

grant_kinds​

Each entry:

FieldTypeRequiredDefaultWhat it does
sourcestringYesThe entity that holds the Grant.
targetstringYesThe entity the Grant is on.
selectstringYesA SELECT or WITH returning one row per Grant; no ;, comments or :name placeholders.
sourceColumnstringYesThe column of select holding the source's identifier.
targetColumnstringYesThe column of select holding the target's identifier.
membershipbooleanNofalseThe source holds what the target holds.
addstringNo, but with removeAdds one Grant. Binds exactly :source and :target. No row changed reads as already present.
removestringNo, but with addRemoves one Grant. Binds exactly :source and :target. No row changed reads as already absent.

The engine does not look up either record before add or remove; the statement's row count is its only evidence (Grant write contract).

custom_ops and handlers​

A custom operation binds a script, scripts/<name>.ps1:

FieldTypeRequiredWhat it does
scriptstringYesThe script's name: letters, digits, _ and -, starting with a letter or digit, up to 64 characters.
entitystringNoThe account entity, the default and the only value: custom operations are actions on a person's account.
title, descriptionstringNoWhat admins and workflows see.
params_schemaobjectNoJSON Schema the parameters are checked against before the script runs.
configlist of stringsNoInstall field names passed to the script as $Params.config.
secretsobjectNoParameter name to gateway secret name. identifiers and config cannot be bound, and params_schema cannot declare a property with either name: Owlie fills both itself.
timeoutMsintegerNo1 to 900000. The default is 60000. The gateway operator's limits cap it: the connector's powershellTimeoutMs and customConnectorLimits.timeoutMs, both 60000 by default.

The operation's handler is <account entity>.op.<key>. Each handlers entry, keyed by a handler key the definition enables, replaces the engine's handler with a script and takes script, config, secrets and timeoutMs. A key the definition does not enable, or a read-only key (connection.validateStatements), is refused: there is no PowerShell broker in a read-only context, so a script bound there would fail every time it ran.

What the script reads as $Params depends on the key. fetchOne, create, fetchAll, fetchAllSince, delete, enable, disable, a Grant kind's add and remove, and connection.testConnection/connection.validateConfig take one value: the script reads it as $Params.payload, beside $Params.identifiers for the entry the operation runs on: null when the operation has none, such as create, fetchAll, fetchAllSince, a Grant write, or either connection operation, which has no entry at all. update takes the entry and the change, so the script reads $Params.identifiers and $Params.input. fetchRelationships takes the external id of the entry whose relationships are read (the group, for a membership grant) and the page request, so the script reads $Params.externalId and $Params.options, with no $Params.identifiers.

A script replacing fetchOne, fetchAll, fetchAllSince or fetchRelationships stands in for a read, so its output is checked before Owlie uses it: a page must be { records, nextCursor, hasMore }, with nextCursor set whenever hasMore is true, and fetchOne must be { record } (the entry, or null when there is none). A script that returns something else fails the operation with a message that says so.

A handlers entry's secrets cannot name a $Params field the key itself fills: config, always, plus payload and identifiers for a one-argument key, identifiers and input for update, or externalId and options for fetchRelationships.

What the engine adds to each install​

FieldTypeRequiredWhat it is
dialectstringYesFixed to the definition's dialect.
hoststringYesThe database server: a plain hostname or IP address.
portintegerNo1 to 65535. The default is 5432 (Postgres), 3306 (MySQL), 1433 (SQL Server) or 1521 (Oracle).
databasestringYesThe database name; for Oracle, the service name. The gateway accepts 1 to 128 letters, digits, _, ., $, # and -.
defaultSchemastringNoPostgres and Oracle only. A plain identifier of up to 63 characters (Postgres) or 128 (Oracle): the schema every statement runs in, Sync reads, writes and Grants alike. The gateway sets it on each connection (on Postgres as the whole search_path, on Oracle as the current schema), so a table named without a schema resolves there. Empty: the connecting user's default schema, or its search_path.
sslboolean or objectNoAbsent or true: verified TLS. false: no TLS. An object: caCert (PEM) and rejectUnauthorized (default true). false, a caCert or rejectUnauthorized: false needs the gateway operator's allowTlsOverrides.

The one authentication option, password ("Username and password"), has user and password, both required. password is a gateway secret: an install gives the secret's name, which the gateway resolves on your network.

What Owlie derives​

PartDerived value
kindsql
provides["sync"], plus provision when the account entity has create or a Grant kind has add and remove
protocols["sql"], plus powershell when a script is bound
execution_targets["gateway"]
EntitiesOne per entity. The schema has exactly the declared columns; identifier_paths is [identifier]; the identifier is a read-only string; a column bound by create or update is writable; bigint columns are strings of digits.
Accountsync_support.supports_incremental follows updatedAt. No sync_profile, so each install's account Sync job starts in Identity mode (Sync creates identities from rows) until an admin switches it to Resource. No Sync active rule, so Sync reads every listed row as active, and a single lookup reports a readable row as active and a missing one as deleted. When the connector provisions, a provisioning profile with the operations its statements offer and no baseline attributes; without create, create_semantics is external.
Grant kindsOne per entry, discovered through its target per entity, with membership as declared, writable with add and remove.
Custom operationsOne per custom_ops entry.

The handlers the engine runs:

HandlersWhen
connection.validateConfig, connection.testConnection, connection.validateStatementsAlways
<entity>.fetchOne, <entity>.fetchAllFor each entity
<entity>.fetchAllSinceWith sync.updatedAt
<entity>.create, <entity>.update, <entity>.delete, <entity>.enable, <entity>.disableFor each statement present
<target>.fetchRelationshipsFor each entity that is a Grant kind's target
grant.<kind>.add, grant.<kind>.removeFor each Grant kind with add and remove
<entity>.op.<key>For each custom operation

connection.validateStatements takes { "keys": [...] } and returns { "statements": { "<key>": { "ok": true } } }, or { "ok": false, "message": "..." } for a statement the database refuses. It executes nothing, and it checks only the statements the definition declares, never the paged, incremental, single-record and relationship reads the engine builds around them. The handler context is in the Handler API.