Address a Provider table
{connector} is the technical connector slug exposed by the Provider Plugin,
such as google, github, or linear. {table} is the projected stream name.
Examples include:
providers.google.usersproviders.github.pull_requestsproviders.linear.issues
USE statement or search_path.
A table appears only when its Provider is configured for the Workspace and
its stream has registered. It can be present before the first sync produces
rows. Use catalog discovery
instead of assuming that an example table exists.
parable.warning.not_connected_providers metadata, so
a reader can show “not connected” rather than zero. Each such table also
carries parable.provider.connection = not_connected and the health state
not_connected (see Types and metadata).
Catalog discovery still lists only connected Providers.
A Provider counts as connected once the Workspace has added it, even before
any of its streams serves a table. A connected Provider serves only its own
tables: a misspelled table, a stream it has not enabled, or any name of a
Provider whose streams are all disabled, still fails as an unknown table.
Only providers resolves a Provider the Workspace has not connected. In
providers_quarantine and providers_quality, a table of such a Provider
fails as an unknown table. Those pools hold the records a connected Provider’s
syncs set aside and the quality history of its tables, so SQL meant to run in
every Workspace reads them only for Providers that catalog discovery lists.
A sync that produces no new records is still a valid result, and the table
stays queryable. An empty first run returns zero rows. An empty incremental run
keeps rows from earlier runs. Rows are removed only when the stream reports a
deletion or an exhaustive result proves that the rows are absent. An empty
result does not mean that the sync failed.
Query one Provider
Active Google Workspace directory users:Understand projected names
A Provider stream can project one or more tables:- Field names are lowercased:
primaryEmailbecomesprimaryemail. - Flattened object paths use
__:assignee.emailbecomesassignee__email. - Arrays can become child tables named
{table}__{path}.
providers.github.issues__labels. The parent ID repeats across child rows, and
the child table has its own logical key. Do not use SELECT DISTINCT on the
parent ID to remove expected child records.
A child row’s parent_pk column holds its parent’s key as text. A string key
is copied as it is. A number or boolean key is the text CAST(key AS VARCHAR)
returns. A date key is its day count since 1970-01-01, a time key its
microseconds since midnight, and a timestamp key its microseconds since the
Unix epoch, which CAST(CAST(key AS BIGINT) AS VARCHAR) returns. The
convenience views below compare keys this way. A join you write yourself must
do the same:
providers.github.issues__labels_with_parent, and a
{table}_nested view that re-nests each child table into its parent row as an
array. A _with_parent view returns one row for each child row whose parent is
stored.
Most tables keep one row per record, and these views join on the parent ID.
Some event streams store an event again each time a load reads it, for example
when two loads’ time windows overlap. Such a stream keeps one parent row and one
set of child rows per load. Its views pair each child row with the parent row
written by the same load, matched on dt and _parable_seal_id as well as the
parent ID, so an event read by three loads returns three pairs, not nine. To
read one row per event from such a table, keep one load’s rows per parent ID:
QL-PL-002): a view whose own definition cannot be planned returns
QL-TB-003 with a message naming the view, and other causes keep their own
codes. The next query retries without a catalog refresh. GetTables, the
semantic catalog, and information_schema leave out a view whose latest
initialization failed and keep listing every other table. GetTables and the
semantic catalog try every view on each request; information_schema lists the
view again after one of those, or a query that names it, succeeds. After a
catalog update or service restart, the first information_schema.columns or
information_schema.views query can fail on a view that nothing has tried yet.
Run it again.
The Provider Plugin owns this projection. See the
Provider Plugins primer for how a custom Plugin
defines streams, schemas, and projection behavior.
Read row state
Every Provider table carries state columns beside the Provider’s own fields. The catalog marks them as system columns and lists them under Show system columns:
A table that holds the current state of each record, such as
providers.google.users, writes a row only when a load changes it: the load
contains the record, the record goes missing for the first time, or it is
first marked deleted. A record missing from later loads keeps the dt and
_parable_seal_id of the day it went missing. WHERE dt = '<latest day>'
therefore returns the rows that changed that day, not the whole table. Read
current state from the whole table and filter on the state columns:
Join people by semantic email
Columns marked with theContact.Email semantic scalar represent compatible
email values. They can be joined across Providers and to
workspace.users.email.
id columns and expect a person match.
Resolve accounts when emails differ
Directory streams can contribute to theproviders.identity schema. It
appears after at least one identity directory stream has synced. In a
Workspace that has added no Provider with an identity directory stream, a
query that names one of these tables reads it as an empty table, and the result
schema names identity in parable.warning.not_connected_providers. Once the
Workspace adds such a Provider, the identity tables count as connected: while
its directory stream is disabled, a query that names one fails as an unknown
table, as it does for any stream that Provider has not enabled.
Associations preserve the Provider-native account ID, its type, the match
method, match confidence, and the account’s
email, name, and
photo_url. Identity
resolution is best-effort; service accounts and shared mailboxes can receive
identities too.
email and name are the values the matcher compared, trimmed and
lowercased. email is a Contact.Email column: it is null when the account
has no email or its email is not valid, and an equality literal compares in
canonical form. name is null when the account has no name. Read an
identity’s emails and names here instead of joining back to each directory
table.
For a fuzzy match, the value it matched is on another association of the
same identity.
providers.identity.account.photo_url is a Network.Url column holding the
person’s profile photo as the Provider reported it. It comes from a stream
field that declares x-transformPersonPhoto (Slack profile.image_512,
Google Workspace thumbnailPhotoUrl). An identity takes its photo the way it
takes its name: from the canonical person source first, then from the
earliest-connected stream that has one. It is null when no linked account has
a photo. Provider photo URLs can expire, so copy the image rather than linking
to it.
providers.identity.account_associations.photo_url holds each linked
account’s own photo, by the same rules. To rank sources another way, or to
fall back when a photo cannot be fetched (a default avatar, a directory photo
that needs sign-in), read every association’s photo_url instead of the
identity’s.