Chapter 4 Registering the dsOMOP resources
The databases exist, but Opal does not yet know about them. This step creates, on
each site, a DataSHIELD resource that tells the dsOMOP server package where the
OMOP data lives and how to open it. It talks to the Opal REST API through R’s
opalr package — no Docker needed here.
That thin wrapper installs opalr if needed and runs the R script that does the
work:
4_resources/create_resources.R.
For each site it ensures a resource-only project omop_demo and (re)creates one
resource named gibleed — the path omop_demo.gibleed the client logs into.
4.1 The resource format
A resource is an ordinary resourcer resource that the dsOMOP resolver matches
by its format, omop.dbi.db. We register it through the dsOMOP provider with
structured connection parameters; Opal stores the resolver-ready definition as a readable
URL — the engine, host, port and database, with any non-default schemas as query
parameters:
omop+dbi:<dbms>://<host>:<port>/<database>?cdm_schema=...&vocabulary_schema=...
For this demo each site’s resource is exactly:
omop+dbi:postgresql://omopdb:5432/omop?cdm_schema=cdm
The schema query parameters are optional and follow a simple rule:
- Neither given → both the CDM and vocabulary tables are read from the engine’s
default schema (PostgreSQL
public, SQL Serverdbo, Oracle the connecting user, …). cdm_schemaonly → the vocabulary tables are assumed to sit alongside the CDM tables, sovocabulary_schemadefaults tocdm_schema. That is the case here: everything lives incdm.- Both given → the CDM and vocabulary tables are read from their respective schemas.
Two consequences worth highlighting:
host/portare Docker-internal. They are the aliasomopdband the in-container port5432from the previous chapter — not a published host port. The same resource definition is therefore valid on every site; each Rock session resolvesomopdbto its own database.- Credentials are not in the URL. The DB user/password (
postgres/postgres) are stored separately as the resource’sidentity/secret. - Bound to the dsOMOP provider. Registering through the provider, rather than as a bare URL, also records which package backs the resource, so no separate package hint is needed.
In R, the script registers the resource through the dsOMOP provider, passing the connection details as structured parameters (site values and credentials are hardcoded to match steps 2–3):
library(opalr)
o <- opal.login("administrator", "password", "http://localhost:48080")
opal.resource_extension_create(
o, "omop_demo", name = "gibleed",
provider = "dsOMOP",
factory = "postgresql",
parameters = list(host = "omopdb", port = 5432L,
database = "omop", cdm_schema = "cdm"),
credentials = list(username = "postgres", password = "postgres"))
opal.logout(o)4.2 A note on disclosure control
No DataSHIELD privacyControlLevel is set here, and it would make no difference if
it were: dsOMOP does not read that option. The
permissive/banana/avocado/… hierarchy is a dsBase mechanism. dsOMOP enforces
its own statistical disclosure control on every response — the standard
nfilter.* thresholds plus a mandatory, non-disableable identifier strip — so
its operations, including extraction, behave the same at every level. The only
prerequisite for extraction is that dsOMOP’s assign methods are published on the
omop profile, which the image and easy-opal already handled in
Chapter 2.
4.3 Verifying
Open any site (e.g. http://localhost:48080), log in as administrator /
password, and under project omop_demo → Resources you should see a gibleed
resource of type omop.dbi.db. With all three sites carrying that resource, we are
ready to connect.