Skip to content

Commit 7b1b4ac

Browse files
authored
Merge pull request #329 from seattleflu/sample-api-update
Sample API update
2 parents 76a7f7e + c2126ad commit 7b1b4ac

File tree

4 files changed

+35
-10
lines changed

4 files changed

+35
-10
lines changed

lib/id3c/api/datastore.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,8 @@ def store_sample(session: DatabaseSession, sample: dict) -> Any:
468468
collection_barcode = sample.pop("collection_id", None)
469469
collection_identifier = find_identifier(session, collection_barcode) if collection_barcode else None
470470

471+
access_role = sample.pop("access_role", None)
472+
471473
result = {
472474
"sample_barcode": sample_barcode,
473475
"collection_barcode": collection_barcode
@@ -517,7 +519,8 @@ def store_sample(session: DatabaseSession, sample: dict) -> Any:
517519
collection_identifier = collection_identifier.uuid if collection_identifier else None,
518520
collection_date = collected_date,
519521
encounter_id = None,
520-
additional_details = sample)
522+
additional_details = sample,
523+
access_role = access_role)
521524

522525
result["sample"] = sample
523526
result["status"] = status

lib/id3c/api/schemas.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,10 @@
9090
},
9191
"notes": {
9292
"type": "string"
93-
}
93+
},
94+
"access_role": {
95+
"type": "string"
96+
},
9497
},
9598
"anyOf": [
9699
{ "required":

lib/id3c/api/static/index.html

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,14 @@ <h3 class="code">POST /v1/warehouse/sample</h3>
143143
"collection_matrix": "dry"
144144
}
145145
</pre>
146-
146+
<p>An "access_role" value is required for samples from specific projects to enable row-level security:
147+
<pre>
148+
{
149+
...
150+
"access_role": "some_db_role"
151+
...
152+
}
153+
</pre>
147154
<h3 class="code">GET /v1/warehouse/identifier-set-uses</h3>
148155
<p>Retrieve metadata about all identifier set uses.
149156

lib/id3c/db/__init__.py

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,8 @@ def upsert_sample(db: DatabaseSession,
186186
collection_identifier: Optional[str],
187187
collection_date: Optional[str],
188188
encounter_id: Optional[int],
189-
additional_details: dict) -> Tuple[Any, str]:
189+
additional_details: dict,
190+
access_role: Optional[str] = None) -> Tuple[Any, str]:
190191
"""
191192
Upsert sample by its *identifier* and/or *collection_identifier*.
192193
An existing sample has its *identifier*, *collection_identifier*,
@@ -200,13 +201,15 @@ def upsert_sample(db: DatabaseSession,
200201
"collection_date": collection_date,
201202
"encounter_id": encounter_id,
202203
"additional_details": Json(additional_details) if additional_details else None,
204+
"additional_details_without_prov": Json({k: additional_details[k] for k in additional_details if k != '_provenance'}) if additional_details else None,
205+
"access_role": access_role,
203206
}
204207

205208
# Look for existing sample(s)
206209
with db.cursor() as cursor:
207210
cursor.execute("""
208211
select
209-
sample_id as id, identifier, collection_identifier, encounter_id, details,
212+
sample_id as id, identifier, collection_identifier, encounter_id, details, access_role,
210213
row (
211214
identifier,
212215
collection_identifier
@@ -223,8 +226,9 @@ def upsert_sample(db: DatabaseSession,
223226
row(
224227
coalesce(%(collection_date)s, collected)::timestamp,
225228
coalesce(%(encounter_id)s::integer, encounter_id),
226-
coalesce(details, '{}'::jsonb) || coalesce(%(additional_details)s, '{}')::jsonb
227-
)::text as metadata_changed
229+
coalesce(details, '{}'::jsonb) || coalesce(%(additional_details_without_prov)s, '{}')::jsonb
230+
)::text as metadata_changed,
231+
row(access_role)::text != row(coalesce(%(access_role)s, access_role))::text as access_role_changed
228232
from warehouse.sample
229233
where identifier = %(identifier)s
230234
or collection_identifier = %(collection_identifier)s
@@ -239,12 +243,13 @@ def upsert_sample(db: DatabaseSession,
239243
status = 'created'
240244

241245
sample = db.fetch_row("""
242-
insert into warehouse.sample (identifier, collection_identifier, collected, encounter_id, details)
246+
insert into warehouse.sample (identifier, collection_identifier, collected, encounter_id, details, access_role)
243247
values (%(identifier)s,
244248
%(collection_identifier)s,
245249
date_or_null(%(collection_date)s),
246250
%(encounter_id)s,
247-
%(additional_details)s)
251+
%(additional_details)s,
252+
%(access_role)s)
248253
returning sample_id as id, identifier, collection_identifier, encounter_id
249254
""", data)
250255

@@ -256,9 +261,10 @@ def upsert_sample(db: DatabaseSession,
256261
LOG.info(f"Updating existing sample {sample.id}")
257262
LOG.info(f"Sample.identifiers_changed is «{sample.identifiers_changed}» ")
258263
LOG.info(f"Sample.metadata_changed is «{sample.metadata_changed}» ")
264+
LOG.info(f"Sample.access_role_changed is «{sample.access_role_changed}» ")
259265

260266
# can safely skip upsert if metadata is unchanged and not updating identifiers or if all data is unchanged
261-
if sample.metadata_changed == False and (not update_identifiers or sample.identifiers_changed == False):
267+
if sample.metadata_changed == False and sample.access_role_changed == False and (not update_identifiers or sample.identifiers_changed == False):
262268
LOG.info(f"Skipping upsert for sample {sample.id} «{sample.identifier}» (no change).")
263269
return sample, status
264270

@@ -286,16 +292,22 @@ def upsert_sample(db: DatabaseSession,
286292
if overwrite_collection_date else SQL("""
287293
collected = coalesce(collected, date_or_null(%(collection_date)s)), """)
288294

295+
# Update access_role if value changed
296+
access_role_update_composable = SQL("""
297+
access_role = %(access_role)s, """) if sample.access_role_changed else SQL("")
298+
289299
sample = db.fetch_row(SQL("""
290300
update warehouse.sample
291301
set {}
302+
{}
292303
{}
293304
encounter_id = coalesce(%(encounter_id)s, encounter_id),
294305
details = coalesce(details, {}) || %(additional_details)s
295306
where sample_id = %(sample_id)s
296307
returning sample_id as id, identifier, collection_identifier, encounter_id
297308
""").format(identifiers_update_composable,
298309
collected_update_composable,
310+
access_role_update_composable,
299311
Literal(Json({}))),
300312
{ **data, "sample_id": sample.id })
301313

0 commit comments

Comments
 (0)