@openhi/constructs 0.0.122 → 0.0.123

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5394,59 +5394,6 @@ async function getAppointmentByIdRoute(req, res) {
5394
5394
  }
5395
5395
  }
5396
5396
 
5397
- // src/data/operations/data/appointment/appointment-date-search-predicate.ts
5398
- var APPOINTMENT_DATE_SEARCH_PREFIXES = [
5399
- "gt",
5400
- "lt",
5401
- "ge",
5402
- "le",
5403
- "sa",
5404
- "eb"
5405
- ];
5406
- function isAppointmentDateSearchPrefix(s) {
5407
- return APPOINTMENT_DATE_SEARCH_PREFIXES.includes(
5408
- s
5409
- );
5410
- }
5411
- var APPT_START = "resource->>'start'";
5412
- var APPT_END = "resource->>'end'";
5413
- var HAS_ANY_BOUND_GUARD = `(${APPT_START} IS NOT NULL OR ${APPT_END} IS NOT NULL)`;
5414
- function buildSinglePredicateSql(prefix, paramName) {
5415
- switch (prefix) {
5416
- case "gt":
5417
- return `(${APPT_END} IS NULL OR ${APPT_END} > :${paramName})`;
5418
- case "lt":
5419
- return `(${APPT_START} IS NULL OR ${APPT_START} < :${paramName})`;
5420
- case "ge":
5421
- return `(${APPT_END} IS NULL OR ${APPT_END} >= :${paramName})`;
5422
- case "le":
5423
- return `(${APPT_START} IS NULL OR ${APPT_START} <= :${paramName})`;
5424
- case "sa":
5425
- return `(${APPT_START} IS NOT NULL AND ${APPT_START} > :${paramName})`;
5426
- case "eb":
5427
- return `(${APPT_END} IS NOT NULL AND ${APPT_END} < :${paramName})`;
5428
- }
5429
- }
5430
- function appointmentDateConstraintParamName(index) {
5431
- return `apptDateConstraint${index}`;
5432
- }
5433
- function buildAppointmentDateSearchPredicateSql(constraints) {
5434
- if (constraints.length === 0) {
5435
- return [];
5436
- }
5437
- const fragments = constraints.map(
5438
- (c, i) => buildSinglePredicateSql(c.prefix, appointmentDateConstraintParamName(i))
5439
- );
5440
- fragments.push(HAS_ANY_BOUND_GUARD);
5441
- return fragments;
5442
- }
5443
- function buildAppointmentDateSearchPredicateParams(constraints) {
5444
- return constraints.map((c, i) => ({
5445
- name: appointmentDateConstraintParamName(i),
5446
- value: c.value
5447
- }));
5448
- }
5449
-
5450
5397
  // src/data/operations/data/appointment/appointment-list-operation.ts
5451
5398
  async function listAppointmentsOperation(params) {
5452
5399
  const { context, tableName, mode } = params;
@@ -5584,123 +5531,93 @@ function getDefaultPostgresQueryRunner() {
5584
5531
  return cached;
5585
5532
  }
5586
5533
 
5587
- // src/data/operations/data/encounter/encounter-period-search-predicate.ts
5588
- var PERIOD_SEARCH_PREFIXES = [
5589
- "gt",
5590
- "lt",
5591
- "ge",
5592
- "le",
5593
- "sa",
5594
- "eb"
5595
- ];
5596
- function isPeriodSearchPrefix(s) {
5597
- return PERIOD_SEARCH_PREFIXES.includes(s);
5534
+ // src/data/search/engine/date-predicate.ts
5535
+ function flatJsonbExtract(jsonbPath) {
5536
+ const match = /^\$\.([A-Za-z_][A-Za-z0-9_]*)$/.exec(jsonbPath);
5537
+ if (!match) {
5538
+ throw new Error(
5539
+ `Generic date predicate requires a flat top-level JSONPath like "$.fieldName"; received "${jsonbPath}".`
5540
+ );
5541
+ }
5542
+ return `resource->>'${match[1]}'`;
5598
5543
  }
5599
- var PERIOD_START = "resource->'period'->>'start'";
5600
- var PERIOD_END = "resource->'period'->>'end'";
5601
- var HAS_ANY_BOUND_GUARD2 = `(${PERIOD_START} IS NOT NULL OR ${PERIOD_END} IS NOT NULL)`;
5602
- function buildSinglePredicateSql2(prefix, paramName) {
5544
+ var DEFAULT_INTERVAL_PARAM_PREFIX = "intervalDateConstraint";
5545
+ function intervalConstraintParamName(prefix, index) {
5546
+ return `${prefix}${index}`;
5547
+ }
5548
+ function buildIntervalSingleSql(prefix, startExtract, endExtract, paramName) {
5603
5549
  switch (prefix) {
5550
+ case "eq":
5551
+ return `(${startExtract} IS NOT NULL AND ${startExtract} = :${paramName})`;
5604
5552
  case "gt":
5605
- return `(${PERIOD_END} IS NULL OR ${PERIOD_END} > :${paramName})`;
5553
+ return `(${endExtract} IS NULL OR ${endExtract} > :${paramName})`;
5606
5554
  case "lt":
5607
- return `(${PERIOD_START} IS NULL OR ${PERIOD_START} < :${paramName})`;
5555
+ return `(${startExtract} IS NULL OR ${startExtract} < :${paramName})`;
5608
5556
  case "ge":
5609
- return `(${PERIOD_END} IS NULL OR ${PERIOD_END} >= :${paramName})`;
5557
+ return `(${endExtract} IS NULL OR ${endExtract} >= :${paramName})`;
5610
5558
  case "le":
5611
- return `(${PERIOD_START} IS NULL OR ${PERIOD_START} <= :${paramName})`;
5559
+ return `(${startExtract} IS NULL OR ${startExtract} <= :${paramName})`;
5612
5560
  case "sa":
5613
- return `(${PERIOD_START} IS NOT NULL AND ${PERIOD_START} > :${paramName})`;
5561
+ return `(${startExtract} IS NOT NULL AND ${startExtract} > :${paramName})`;
5614
5562
  case "eb":
5615
- return `(${PERIOD_END} IS NOT NULL AND ${PERIOD_END} < :${paramName})`;
5563
+ return `(${endExtract} IS NOT NULL AND ${endExtract} < :${paramName})`;
5616
5564
  }
5617
5565
  }
5618
- function periodConstraintParamName(index) {
5619
- return `periodConstraint${index}`;
5620
- }
5621
- function buildPeriodSearchPredicateSql(constraints) {
5566
+ function buildIntervalDateSearchPredicateSql(constraints, opts) {
5622
5567
  if (constraints.length === 0) {
5623
5568
  return [];
5624
5569
  }
5570
+ const paramPrefix = opts.paramNamePrefix ?? DEFAULT_INTERVAL_PARAM_PREFIX;
5571
+ const startExtract = flatJsonbExtract(opts.startPath);
5572
+ const endExtract = flatJsonbExtract(opts.endPath);
5625
5573
  const fragments = constraints.map(
5626
- (c, i) => buildSinglePredicateSql2(c.prefix, periodConstraintParamName(i))
5574
+ (c, i) => buildIntervalSingleSql(
5575
+ c.prefix,
5576
+ startExtract,
5577
+ endExtract,
5578
+ intervalConstraintParamName(paramPrefix, i)
5579
+ )
5627
5580
  );
5628
- fragments.push(HAS_ANY_BOUND_GUARD2);
5581
+ fragments.push(`(${startExtract} IS NOT NULL OR ${endExtract} IS NOT NULL)`);
5629
5582
  return fragments;
5630
5583
  }
5631
- function buildPeriodSearchPredicateParams(constraints) {
5584
+ function buildIntervalDateSearchPredicateParams(constraints, opts) {
5585
+ const paramPrefix = opts?.paramNamePrefix ?? DEFAULT_INTERVAL_PARAM_PREFIX;
5632
5586
  return constraints.map((c, i) => ({
5633
- name: periodConstraintParamName(i),
5587
+ name: intervalConstraintParamName(paramPrefix, i),
5634
5588
  value: c.value
5635
5589
  }));
5636
5590
  }
5637
-
5638
- // src/data/operations/data/encounter/encounter-search-by-patient-operation.ts
5639
- var DEFAULT_LIMIT = 100;
5640
- function buildOpenHiResourceUrn(opts) {
5641
- return `urn:ohi:${opts.tenantId}:${opts.workspaceId}:${opts.resourceType}:${opts.resourceId}`;
5642
- }
5643
- function buildSearchEncountersByPatientSql(opts) {
5644
- const periodPredicates = buildPeriodSearchPredicateSql(
5645
- opts?.periodConstraints ?? []
5591
+ var APPOINTMENT_DATE_SEARCH_PREFIXES = [
5592
+ "gt",
5593
+ "lt",
5594
+ "ge",
5595
+ "le",
5596
+ "sa",
5597
+ "eb"
5598
+ ];
5599
+ function isAppointmentDateSearchPrefix(s) {
5600
+ return APPOINTMENT_DATE_SEARCH_PREFIXES.includes(
5601
+ s
5646
5602
  );
5647
- const lines = [
5648
- "SELECT resource_id AS id, resource",
5649
- "FROM resources",
5650
- "WHERE tenant_id = :tenantId",
5651
- " AND workspace_id = :workspaceId",
5652
- " AND resource_type = 'Encounter'",
5653
- " AND deleted_at IS NULL",
5654
- " AND (resource @> :containmentRelative::jsonb",
5655
- " OR resource @> :containmentUrn::jsonb)"
5656
- ];
5657
- for (const fragment of periodPredicates) {
5658
- lines.push(` AND ${fragment}`);
5659
- }
5660
- lines.push("ORDER BY last_updated DESC");
5661
- lines.push("LIMIT :limit;");
5662
- return lines.join("\n");
5663
5603
  }
5664
- async function searchEncountersByPatientOperation(params) {
5665
- const { context, patientId } = params;
5666
- const periodConstraints = params.periodConstraints ?? [];
5667
- const { tenantId, workspaceId } = context;
5668
- const runner = params.runner ?? getDefaultPostgresQueryRunner();
5669
- const limit = params.limit ?? DEFAULT_LIMIT;
5670
- const containmentRelative = JSON.stringify({
5671
- subject: { reference: `Patient/${patientId}` }
5604
+ function buildAppointmentDateSearchPredicateSql(constraints) {
5605
+ return buildIntervalDateSearchPredicateSql(constraints, {
5606
+ startPath: "$.start",
5607
+ endPath: "$.end",
5608
+ paramNamePrefix: "apptDateConstraint"
5672
5609
  });
5673
- const containmentUrn = JSON.stringify({
5674
- subject: {
5675
- reference: buildOpenHiResourceUrn({
5676
- tenantId,
5677
- workspaceId,
5678
- resourceType: "Patient",
5679
- resourceId: patientId
5680
- })
5681
- }
5610
+ }
5611
+ function buildAppointmentDateSearchPredicateParams(constraints) {
5612
+ return buildIntervalDateSearchPredicateParams(constraints, {
5613
+ paramNamePrefix: "apptDateConstraint"
5682
5614
  });
5683
- const sql = buildSearchEncountersByPatientSql({ periodConstraints });
5684
- const queryParams = [
5685
- { name: "tenantId", value: tenantId },
5686
- { name: "workspaceId", value: workspaceId },
5687
- { name: "containmentRelative", value: containmentRelative },
5688
- { name: "containmentUrn", value: containmentUrn },
5689
- { name: "limit", value: limit },
5690
- ...buildPeriodSearchPredicateParams(periodConstraints)
5691
- ];
5692
- const rows = await runner.query(sql, queryParams);
5693
- const entries = rows.map((row) => ({
5694
- id: row.id,
5695
- resource: {
5696
- ...row.resource,
5697
- id: row.id
5698
- }
5699
- }));
5700
- return { entries, total: entries.length };
5701
5615
  }
5702
5616
 
5703
- // src/data/operations/data/reference-containment-predicate.ts
5617
+ // src/data/search/engine/reference-predicate.ts
5618
+ function buildOpenHiResourceUrn(opts) {
5619
+ return `urn:ohi:${opts.tenantId}:${opts.workspaceId}:${opts.resourceType}:${opts.resourceId}`;
5620
+ }
5704
5621
  var REFERENCE_CONTAINMENT_SQL_FRAGMENT = "(resource @> :containmentRelative::jsonb OR resource @> :containmentUrn::jsonb)";
5705
5622
  function parseTypedReference(s) {
5706
5623
  const match = /^([A-Za-z][A-Za-z0-9_]*)\/([^\s/]+)$/.exec(s);
@@ -5741,7 +5658,7 @@ function buildReferenceContainmentPayload(params) {
5741
5658
  }
5742
5659
 
5743
5660
  // src/data/operations/data/appointment/appointment-search-by-actor-operation.ts
5744
- var DEFAULT_LIMIT2 = 100;
5661
+ var DEFAULT_LIMIT = 100;
5745
5662
  function buildSearchAppointmentsByActorSql(opts) {
5746
5663
  const datePredicates = buildAppointmentDateSearchPredicateSql(
5747
5664
  opts?.dateConstraints ?? []
@@ -5767,7 +5684,7 @@ async function searchAppointmentsByActorOperation(params) {
5767
5684
  const dateConstraints = params.dateConstraints ?? [];
5768
5685
  const { tenantId, workspaceId } = context;
5769
5686
  const runner = params.runner ?? getDefaultPostgresQueryRunner();
5770
- const limit = params.limit ?? DEFAULT_LIMIT2;
5687
+ const limit = params.limit ?? DEFAULT_LIMIT;
5771
5688
  const { containmentRelative, containmentUrn } = buildReferenceContainmentPayload({
5772
5689
  shape: {
5773
5690
  kind: "array-of-objects",
@@ -5799,7 +5716,7 @@ async function searchAppointmentsByActorOperation(params) {
5799
5716
  }
5800
5717
 
5801
5718
  // src/data/operations/data/appointment/appointment-search-by-date-operation.ts
5802
- var DEFAULT_LIMIT3 = 100;
5719
+ var DEFAULT_LIMIT2 = 100;
5803
5720
  function buildSearchAppointmentsByDateSql(opts) {
5804
5721
  const datePredicates = buildAppointmentDateSearchPredicateSql(
5805
5722
  opts.dateConstraints
@@ -5828,7 +5745,7 @@ async function searchAppointmentsByDateOperation(params) {
5828
5745
  }
5829
5746
  const { tenantId, workspaceId } = context;
5830
5747
  const runner = params.runner ?? getDefaultPostgresQueryRunner();
5831
- const limit = params.limit ?? DEFAULT_LIMIT3;
5748
+ const limit = params.limit ?? DEFAULT_LIMIT2;
5832
5749
  const sql = buildSearchAppointmentsByDateSql({ dateConstraints });
5833
5750
  const queryParams = [
5834
5751
  { name: "tenantId", value: tenantId },
@@ -5848,7 +5765,7 @@ async function searchAppointmentsByDateOperation(params) {
5848
5765
  }
5849
5766
 
5850
5767
  // src/data/operations/data/appointment/appointment-search-by-patient-operation.ts
5851
- var DEFAULT_LIMIT4 = 100;
5768
+ var DEFAULT_LIMIT3 = 100;
5852
5769
  function buildSearchAppointmentsByPatientSql(opts) {
5853
5770
  const datePredicates = buildAppointmentDateSearchPredicateSql(
5854
5771
  opts?.dateConstraints ?? []
@@ -5875,7 +5792,7 @@ async function searchAppointmentsByPatientOperation(params) {
5875
5792
  const dateConstraints = params.dateConstraints ?? [];
5876
5793
  const { tenantId, workspaceId } = context;
5877
5794
  const runner = params.runner ?? getDefaultPostgresQueryRunner();
5878
- const limit = params.limit ?? DEFAULT_LIMIT4;
5795
+ const limit = params.limit ?? DEFAULT_LIMIT3;
5879
5796
  const containmentRelative = JSON.stringify({
5880
5797
  participant: [{ actor: { reference: `Patient/${patientId}` } }]
5881
5798
  });
@@ -13556,8 +13473,59 @@ async function listEncountersOperation(params) {
13556
13473
  );
13557
13474
  }
13558
13475
 
13476
+ // src/data/operations/data/encounter/encounter-period-search-predicate.ts
13477
+ var PERIOD_SEARCH_PREFIXES = [
13478
+ "gt",
13479
+ "lt",
13480
+ "ge",
13481
+ "le",
13482
+ "sa",
13483
+ "eb"
13484
+ ];
13485
+ function isPeriodSearchPrefix(s) {
13486
+ return PERIOD_SEARCH_PREFIXES.includes(s);
13487
+ }
13488
+ var PERIOD_START = "resource->'period'->>'start'";
13489
+ var PERIOD_END = "resource->'period'->>'end'";
13490
+ var HAS_ANY_BOUND_GUARD = `(${PERIOD_START} IS NOT NULL OR ${PERIOD_END} IS NOT NULL)`;
13491
+ function buildSinglePredicateSql(prefix, paramName) {
13492
+ switch (prefix) {
13493
+ case "gt":
13494
+ return `(${PERIOD_END} IS NULL OR ${PERIOD_END} > :${paramName})`;
13495
+ case "lt":
13496
+ return `(${PERIOD_START} IS NULL OR ${PERIOD_START} < :${paramName})`;
13497
+ case "ge":
13498
+ return `(${PERIOD_END} IS NULL OR ${PERIOD_END} >= :${paramName})`;
13499
+ case "le":
13500
+ return `(${PERIOD_START} IS NULL OR ${PERIOD_START} <= :${paramName})`;
13501
+ case "sa":
13502
+ return `(${PERIOD_START} IS NOT NULL AND ${PERIOD_START} > :${paramName})`;
13503
+ case "eb":
13504
+ return `(${PERIOD_END} IS NOT NULL AND ${PERIOD_END} < :${paramName})`;
13505
+ }
13506
+ }
13507
+ function periodConstraintParamName(index) {
13508
+ return `periodConstraint${index}`;
13509
+ }
13510
+ function buildPeriodSearchPredicateSql(constraints) {
13511
+ if (constraints.length === 0) {
13512
+ return [];
13513
+ }
13514
+ const fragments = constraints.map(
13515
+ (c, i) => buildSinglePredicateSql(c.prefix, periodConstraintParamName(i))
13516
+ );
13517
+ fragments.push(HAS_ANY_BOUND_GUARD);
13518
+ return fragments;
13519
+ }
13520
+ function buildPeriodSearchPredicateParams(constraints) {
13521
+ return constraints.map((c, i) => ({
13522
+ name: periodConstraintParamName(i),
13523
+ value: c.value
13524
+ }));
13525
+ }
13526
+
13559
13527
  // src/data/operations/data/encounter/encounter-search-by-date-operation.ts
13560
- var DEFAULT_LIMIT5 = 100;
13528
+ var DEFAULT_LIMIT4 = 100;
13561
13529
  function buildSearchEncountersByDateSql(opts) {
13562
13530
  const periodPredicates = buildPeriodSearchPredicateSql(
13563
13531
  opts.periodConstraints
@@ -13586,7 +13554,7 @@ async function searchEncountersByDateOperation(params) {
13586
13554
  }
13587
13555
  const { tenantId, workspaceId } = context;
13588
13556
  const runner = params.runner ?? getDefaultPostgresQueryRunner();
13589
- const limit = params.limit ?? DEFAULT_LIMIT5;
13557
+ const limit = params.limit ?? DEFAULT_LIMIT4;
13590
13558
  const sql = buildSearchEncountersByDateSql({ periodConstraints });
13591
13559
  const queryParams = [
13592
13560
  { name: "tenantId", value: tenantId },
@@ -13606,7 +13574,7 @@ async function searchEncountersByDateOperation(params) {
13606
13574
  }
13607
13575
 
13608
13576
  // src/data/operations/data/encounter/encounter-search-by-participant-operation.ts
13609
- var DEFAULT_LIMIT6 = 100;
13577
+ var DEFAULT_LIMIT5 = 100;
13610
13578
  function buildSearchEncountersByParticipantSql(opts) {
13611
13579
  const periodPredicates = buildPeriodSearchPredicateSql(
13612
13580
  opts?.periodConstraints ?? []
@@ -13632,7 +13600,7 @@ async function searchEncountersByParticipantOperation(params) {
13632
13600
  const periodConstraints = params.periodConstraints ?? [];
13633
13601
  const { tenantId, workspaceId } = context;
13634
13602
  const runner = params.runner ?? getDefaultPostgresQueryRunner();
13635
- const limit = params.limit ?? DEFAULT_LIMIT6;
13603
+ const limit = params.limit ?? DEFAULT_LIMIT5;
13636
13604
  const { containmentRelative, containmentUrn } = buildReferenceContainmentPayload({
13637
13605
  shape: {
13638
13606
  kind: "array-of-objects",
@@ -13663,6 +13631,68 @@ async function searchEncountersByParticipantOperation(params) {
13663
13631
  return { entries, total: entries.length };
13664
13632
  }
13665
13633
 
13634
+ // src/data/operations/data/encounter/encounter-search-by-patient-operation.ts
13635
+ var DEFAULT_LIMIT6 = 100;
13636
+ function buildSearchEncountersByPatientSql(opts) {
13637
+ const periodPredicates = buildPeriodSearchPredicateSql(
13638
+ opts?.periodConstraints ?? []
13639
+ );
13640
+ const lines = [
13641
+ "SELECT resource_id AS id, resource",
13642
+ "FROM resources",
13643
+ "WHERE tenant_id = :tenantId",
13644
+ " AND workspace_id = :workspaceId",
13645
+ " AND resource_type = 'Encounter'",
13646
+ " AND deleted_at IS NULL",
13647
+ " AND (resource @> :containmentRelative::jsonb",
13648
+ " OR resource @> :containmentUrn::jsonb)"
13649
+ ];
13650
+ for (const fragment of periodPredicates) {
13651
+ lines.push(` AND ${fragment}`);
13652
+ }
13653
+ lines.push("ORDER BY last_updated DESC");
13654
+ lines.push("LIMIT :limit;");
13655
+ return lines.join("\n");
13656
+ }
13657
+ async function searchEncountersByPatientOperation(params) {
13658
+ const { context, patientId } = params;
13659
+ const periodConstraints = params.periodConstraints ?? [];
13660
+ const { tenantId, workspaceId } = context;
13661
+ const runner = params.runner ?? getDefaultPostgresQueryRunner();
13662
+ const limit = params.limit ?? DEFAULT_LIMIT6;
13663
+ const containmentRelative = JSON.stringify({
13664
+ subject: { reference: `Patient/${patientId}` }
13665
+ });
13666
+ const containmentUrn = JSON.stringify({
13667
+ subject: {
13668
+ reference: buildOpenHiResourceUrn({
13669
+ tenantId,
13670
+ workspaceId,
13671
+ resourceType: "Patient",
13672
+ resourceId: patientId
13673
+ })
13674
+ }
13675
+ });
13676
+ const sql = buildSearchEncountersByPatientSql({ periodConstraints });
13677
+ const queryParams = [
13678
+ { name: "tenantId", value: tenantId },
13679
+ { name: "workspaceId", value: workspaceId },
13680
+ { name: "containmentRelative", value: containmentRelative },
13681
+ { name: "containmentUrn", value: containmentUrn },
13682
+ { name: "limit", value: limit },
13683
+ ...buildPeriodSearchPredicateParams(periodConstraints)
13684
+ ];
13685
+ const rows = await runner.query(sql, queryParams);
13686
+ const entries = rows.map((row) => ({
13687
+ id: row.id,
13688
+ resource: {
13689
+ ...row.resource,
13690
+ id: row.id
13691
+ }
13692
+ }));
13693
+ return { entries, total: entries.length };
13694
+ }
13695
+
13666
13696
  // src/data/rest-api/routes/data/encounter/encounter-list-route.ts
13667
13697
  function singleStringQueryParam2(req, name) {
13668
13698
  const v = req.query[name];