@openhi/constructs 0.0.122 → 0.0.124

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.
@@ -9587,59 +9587,6 @@ async function getAppointmentByIdRoute(req, res) {
9587
9587
  }
9588
9588
  }
9589
9589
 
9590
- // src/data/operations/data/appointment/appointment-date-search-predicate.ts
9591
- var APPOINTMENT_DATE_SEARCH_PREFIXES = [
9592
- "gt",
9593
- "lt",
9594
- "ge",
9595
- "le",
9596
- "sa",
9597
- "eb"
9598
- ];
9599
- function isAppointmentDateSearchPrefix(s) {
9600
- return APPOINTMENT_DATE_SEARCH_PREFIXES.includes(
9601
- s
9602
- );
9603
- }
9604
- var APPT_START = "resource->>'start'";
9605
- var APPT_END = "resource->>'end'";
9606
- var HAS_ANY_BOUND_GUARD = `(${APPT_START} IS NOT NULL OR ${APPT_END} IS NOT NULL)`;
9607
- function buildSinglePredicateSql(prefix, paramName) {
9608
- switch (prefix) {
9609
- case "gt":
9610
- return `(${APPT_END} IS NULL OR ${APPT_END} > :${paramName})`;
9611
- case "lt":
9612
- return `(${APPT_START} IS NULL OR ${APPT_START} < :${paramName})`;
9613
- case "ge":
9614
- return `(${APPT_END} IS NULL OR ${APPT_END} >= :${paramName})`;
9615
- case "le":
9616
- return `(${APPT_START} IS NULL OR ${APPT_START} <= :${paramName})`;
9617
- case "sa":
9618
- return `(${APPT_START} IS NOT NULL AND ${APPT_START} > :${paramName})`;
9619
- case "eb":
9620
- return `(${APPT_END} IS NOT NULL AND ${APPT_END} < :${paramName})`;
9621
- }
9622
- }
9623
- function appointmentDateConstraintParamName(index) {
9624
- return `apptDateConstraint${index}`;
9625
- }
9626
- function buildAppointmentDateSearchPredicateSql(constraints) {
9627
- if (constraints.length === 0) {
9628
- return [];
9629
- }
9630
- const fragments = constraints.map(
9631
- (c, i) => buildSinglePredicateSql(c.prefix, appointmentDateConstraintParamName(i))
9632
- );
9633
- fragments.push(HAS_ANY_BOUND_GUARD);
9634
- return fragments;
9635
- }
9636
- function buildAppointmentDateSearchPredicateParams(constraints) {
9637
- return constraints.map((c, i) => ({
9638
- name: appointmentDateConstraintParamName(i),
9639
- value: c.value
9640
- }));
9641
- }
9642
-
9643
9590
  // src/data/operations/data/appointment/appointment-list-operation.ts
9644
9591
  async function listAppointmentsOperation(params) {
9645
9592
  const { context, tableName, mode } = params;
@@ -9814,123 +9761,93 @@ function getDefaultPostgresQueryRunner() {
9814
9761
  return cached;
9815
9762
  }
9816
9763
 
9817
- // src/data/operations/data/encounter/encounter-period-search-predicate.ts
9818
- var PERIOD_SEARCH_PREFIXES = [
9819
- "gt",
9820
- "lt",
9821
- "ge",
9822
- "le",
9823
- "sa",
9824
- "eb"
9825
- ];
9826
- function isPeriodSearchPrefix(s) {
9827
- return PERIOD_SEARCH_PREFIXES.includes(s);
9764
+ // src/data/search/engine/date-predicate.ts
9765
+ function flatJsonbExtract(jsonbPath) {
9766
+ const match = /^\$\.([A-Za-z_][A-Za-z0-9_]*)$/.exec(jsonbPath);
9767
+ if (!match) {
9768
+ throw new Error(
9769
+ `Generic date predicate requires a flat top-level JSONPath like "$.fieldName"; received "${jsonbPath}".`
9770
+ );
9771
+ }
9772
+ return `resource->>'${match[1]}'`;
9828
9773
  }
9829
- var PERIOD_START = "resource->'period'->>'start'";
9830
- var PERIOD_END = "resource->'period'->>'end'";
9831
- var HAS_ANY_BOUND_GUARD2 = `(${PERIOD_START} IS NOT NULL OR ${PERIOD_END} IS NOT NULL)`;
9832
- function buildSinglePredicateSql2(prefix, paramName) {
9774
+ var DEFAULT_INTERVAL_PARAM_PREFIX = "intervalDateConstraint";
9775
+ function intervalConstraintParamName(prefix, index) {
9776
+ return `${prefix}${index}`;
9777
+ }
9778
+ function buildIntervalSingleSql(prefix, startExtract, endExtract, paramName) {
9833
9779
  switch (prefix) {
9780
+ case "eq":
9781
+ return `(${startExtract} IS NOT NULL AND ${startExtract} = :${paramName})`;
9834
9782
  case "gt":
9835
- return `(${PERIOD_END} IS NULL OR ${PERIOD_END} > :${paramName})`;
9783
+ return `(${endExtract} IS NULL OR ${endExtract} > :${paramName})`;
9836
9784
  case "lt":
9837
- return `(${PERIOD_START} IS NULL OR ${PERIOD_START} < :${paramName})`;
9785
+ return `(${startExtract} IS NULL OR ${startExtract} < :${paramName})`;
9838
9786
  case "ge":
9839
- return `(${PERIOD_END} IS NULL OR ${PERIOD_END} >= :${paramName})`;
9787
+ return `(${endExtract} IS NULL OR ${endExtract} >= :${paramName})`;
9840
9788
  case "le":
9841
- return `(${PERIOD_START} IS NULL OR ${PERIOD_START} <= :${paramName})`;
9789
+ return `(${startExtract} IS NULL OR ${startExtract} <= :${paramName})`;
9842
9790
  case "sa":
9843
- return `(${PERIOD_START} IS NOT NULL AND ${PERIOD_START} > :${paramName})`;
9791
+ return `(${startExtract} IS NOT NULL AND ${startExtract} > :${paramName})`;
9844
9792
  case "eb":
9845
- return `(${PERIOD_END} IS NOT NULL AND ${PERIOD_END} < :${paramName})`;
9793
+ return `(${endExtract} IS NOT NULL AND ${endExtract} < :${paramName})`;
9846
9794
  }
9847
9795
  }
9848
- function periodConstraintParamName(index) {
9849
- return `periodConstraint${index}`;
9850
- }
9851
- function buildPeriodSearchPredicateSql(constraints) {
9796
+ function buildIntervalDateSearchPredicateSql(constraints, opts) {
9852
9797
  if (constraints.length === 0) {
9853
9798
  return [];
9854
9799
  }
9800
+ const paramPrefix = opts.paramNamePrefix ?? DEFAULT_INTERVAL_PARAM_PREFIX;
9801
+ const startExtract = flatJsonbExtract(opts.startPath);
9802
+ const endExtract = flatJsonbExtract(opts.endPath);
9855
9803
  const fragments = constraints.map(
9856
- (c, i) => buildSinglePredicateSql2(c.prefix, periodConstraintParamName(i))
9804
+ (c, i) => buildIntervalSingleSql(
9805
+ c.prefix,
9806
+ startExtract,
9807
+ endExtract,
9808
+ intervalConstraintParamName(paramPrefix, i)
9809
+ )
9857
9810
  );
9858
- fragments.push(HAS_ANY_BOUND_GUARD2);
9811
+ fragments.push(`(${startExtract} IS NOT NULL OR ${endExtract} IS NOT NULL)`);
9859
9812
  return fragments;
9860
9813
  }
9861
- function buildPeriodSearchPredicateParams(constraints) {
9814
+ function buildIntervalDateSearchPredicateParams(constraints, opts) {
9815
+ const paramPrefix = opts?.paramNamePrefix ?? DEFAULT_INTERVAL_PARAM_PREFIX;
9862
9816
  return constraints.map((c, i) => ({
9863
- name: periodConstraintParamName(i),
9817
+ name: intervalConstraintParamName(paramPrefix, i),
9864
9818
  value: c.value
9865
9819
  }));
9866
9820
  }
9867
-
9868
- // src/data/operations/data/encounter/encounter-search-by-patient-operation.ts
9869
- var DEFAULT_LIMIT = 100;
9870
- function buildOpenHiResourceUrn(opts) {
9871
- return `urn:ohi:${opts.tenantId}:${opts.workspaceId}:${opts.resourceType}:${opts.resourceId}`;
9872
- }
9873
- function buildSearchEncountersByPatientSql(opts) {
9874
- const periodPredicates = buildPeriodSearchPredicateSql(
9875
- opts?.periodConstraints ?? []
9821
+ var APPOINTMENT_DATE_SEARCH_PREFIXES = [
9822
+ "gt",
9823
+ "lt",
9824
+ "ge",
9825
+ "le",
9826
+ "sa",
9827
+ "eb"
9828
+ ];
9829
+ function isAppointmentDateSearchPrefix(s) {
9830
+ return APPOINTMENT_DATE_SEARCH_PREFIXES.includes(
9831
+ s
9876
9832
  );
9877
- const lines = [
9878
- "SELECT resource_id AS id, resource",
9879
- "FROM resources",
9880
- "WHERE tenant_id = :tenantId",
9881
- " AND workspace_id = :workspaceId",
9882
- " AND resource_type = 'Encounter'",
9883
- " AND deleted_at IS NULL",
9884
- " AND (resource @> :containmentRelative::jsonb",
9885
- " OR resource @> :containmentUrn::jsonb)"
9886
- ];
9887
- for (const fragment of periodPredicates) {
9888
- lines.push(` AND ${fragment}`);
9889
- }
9890
- lines.push("ORDER BY last_updated DESC");
9891
- lines.push("LIMIT :limit;");
9892
- return lines.join("\n");
9893
9833
  }
9894
- async function searchEncountersByPatientOperation(params) {
9895
- const { context, patientId } = params;
9896
- const periodConstraints = params.periodConstraints ?? [];
9897
- const { tenantId, workspaceId } = context;
9898
- const runner = params.runner ?? getDefaultPostgresQueryRunner();
9899
- const limit = params.limit ?? DEFAULT_LIMIT;
9900
- const containmentRelative = JSON.stringify({
9901
- subject: { reference: `Patient/${patientId}` }
9834
+ function buildAppointmentDateSearchPredicateSql(constraints) {
9835
+ return buildIntervalDateSearchPredicateSql(constraints, {
9836
+ startPath: "$.start",
9837
+ endPath: "$.end",
9838
+ paramNamePrefix: "apptDateConstraint"
9902
9839
  });
9903
- const containmentUrn = JSON.stringify({
9904
- subject: {
9905
- reference: buildOpenHiResourceUrn({
9906
- tenantId,
9907
- workspaceId,
9908
- resourceType: "Patient",
9909
- resourceId: patientId
9910
- })
9911
- }
9840
+ }
9841
+ function buildAppointmentDateSearchPredicateParams(constraints) {
9842
+ return buildIntervalDateSearchPredicateParams(constraints, {
9843
+ paramNamePrefix: "apptDateConstraint"
9912
9844
  });
9913
- const sql = buildSearchEncountersByPatientSql({ periodConstraints });
9914
- const queryParams = [
9915
- { name: "tenantId", value: tenantId },
9916
- { name: "workspaceId", value: workspaceId },
9917
- { name: "containmentRelative", value: containmentRelative },
9918
- { name: "containmentUrn", value: containmentUrn },
9919
- { name: "limit", value: limit },
9920
- ...buildPeriodSearchPredicateParams(periodConstraints)
9921
- ];
9922
- const rows = await runner.query(sql, queryParams);
9923
- const entries = rows.map((row) => ({
9924
- id: row.id,
9925
- resource: {
9926
- ...row.resource,
9927
- id: row.id
9928
- }
9929
- }));
9930
- return { entries, total: entries.length };
9931
9845
  }
9932
9846
 
9933
- // src/data/operations/data/reference-containment-predicate.ts
9847
+ // src/data/search/engine/reference-predicate.ts
9848
+ function buildOpenHiResourceUrn(opts) {
9849
+ return `urn:ohi:${opts.tenantId}:${opts.workspaceId}:${opts.resourceType}:${opts.resourceId}`;
9850
+ }
9934
9851
  var REFERENCE_CONTAINMENT_SQL_FRAGMENT = "(resource @> :containmentRelative::jsonb OR resource @> :containmentUrn::jsonb)";
9935
9852
  function parseTypedReference(s) {
9936
9853
  const match = /^([A-Za-z][A-Za-z0-9_]*)\/([^\s/]+)$/.exec(s);
@@ -9971,7 +9888,7 @@ function buildReferenceContainmentPayload(params) {
9971
9888
  }
9972
9889
 
9973
9890
  // src/data/operations/data/appointment/appointment-search-by-actor-operation.ts
9974
- var DEFAULT_LIMIT2 = 100;
9891
+ var DEFAULT_LIMIT = 100;
9975
9892
  function buildSearchAppointmentsByActorSql(opts) {
9976
9893
  const datePredicates = buildAppointmentDateSearchPredicateSql(
9977
9894
  opts?.dateConstraints ?? []
@@ -9997,7 +9914,7 @@ async function searchAppointmentsByActorOperation(params) {
9997
9914
  const dateConstraints = params.dateConstraints ?? [];
9998
9915
  const { tenantId, workspaceId } = context;
9999
9916
  const runner = params.runner ?? getDefaultPostgresQueryRunner();
10000
- const limit = params.limit ?? DEFAULT_LIMIT2;
9917
+ const limit = params.limit ?? DEFAULT_LIMIT;
10001
9918
  const { containmentRelative, containmentUrn } = buildReferenceContainmentPayload({
10002
9919
  shape: {
10003
9920
  kind: "array-of-objects",
@@ -10029,7 +9946,7 @@ async function searchAppointmentsByActorOperation(params) {
10029
9946
  }
10030
9947
 
10031
9948
  // src/data/operations/data/appointment/appointment-search-by-date-operation.ts
10032
- var DEFAULT_LIMIT3 = 100;
9949
+ var DEFAULT_LIMIT2 = 100;
10033
9950
  function buildSearchAppointmentsByDateSql(opts) {
10034
9951
  const datePredicates = buildAppointmentDateSearchPredicateSql(
10035
9952
  opts.dateConstraints
@@ -10058,7 +9975,7 @@ async function searchAppointmentsByDateOperation(params) {
10058
9975
  }
10059
9976
  const { tenantId, workspaceId } = context;
10060
9977
  const runner = params.runner ?? getDefaultPostgresQueryRunner();
10061
- const limit = params.limit ?? DEFAULT_LIMIT3;
9978
+ const limit = params.limit ?? DEFAULT_LIMIT2;
10062
9979
  const sql = buildSearchAppointmentsByDateSql({ dateConstraints });
10063
9980
  const queryParams = [
10064
9981
  { name: "tenantId", value: tenantId },
@@ -10078,7 +9995,7 @@ async function searchAppointmentsByDateOperation(params) {
10078
9995
  }
10079
9996
 
10080
9997
  // src/data/operations/data/appointment/appointment-search-by-patient-operation.ts
10081
- var DEFAULT_LIMIT4 = 100;
9998
+ var DEFAULT_LIMIT3 = 100;
10082
9999
  function buildSearchAppointmentsByPatientSql(opts) {
10083
10000
  const datePredicates = buildAppointmentDateSearchPredicateSql(
10084
10001
  opts?.dateConstraints ?? []
@@ -10105,7 +10022,7 @@ async function searchAppointmentsByPatientOperation(params) {
10105
10022
  const dateConstraints = params.dateConstraints ?? [];
10106
10023
  const { tenantId, workspaceId } = context;
10107
10024
  const runner = params.runner ?? getDefaultPostgresQueryRunner();
10108
- const limit = params.limit ?? DEFAULT_LIMIT4;
10025
+ const limit = params.limit ?? DEFAULT_LIMIT3;
10109
10026
  const containmentRelative = JSON.stringify({
10110
10027
  participant: [{ actor: { reference: `Patient/${patientId}` } }]
10111
10028
  });
@@ -17821,8 +17738,59 @@ async function listEncountersOperation(params) {
17821
17738
  );
17822
17739
  }
17823
17740
 
17741
+ // src/data/operations/data/encounter/encounter-period-search-predicate.ts
17742
+ var PERIOD_SEARCH_PREFIXES = [
17743
+ "gt",
17744
+ "lt",
17745
+ "ge",
17746
+ "le",
17747
+ "sa",
17748
+ "eb"
17749
+ ];
17750
+ function isPeriodSearchPrefix(s) {
17751
+ return PERIOD_SEARCH_PREFIXES.includes(s);
17752
+ }
17753
+ var PERIOD_START = "resource->'period'->>'start'";
17754
+ var PERIOD_END = "resource->'period'->>'end'";
17755
+ var HAS_ANY_BOUND_GUARD = `(${PERIOD_START} IS NOT NULL OR ${PERIOD_END} IS NOT NULL)`;
17756
+ function buildSinglePredicateSql(prefix, paramName) {
17757
+ switch (prefix) {
17758
+ case "gt":
17759
+ return `(${PERIOD_END} IS NULL OR ${PERIOD_END} > :${paramName})`;
17760
+ case "lt":
17761
+ return `(${PERIOD_START} IS NULL OR ${PERIOD_START} < :${paramName})`;
17762
+ case "ge":
17763
+ return `(${PERIOD_END} IS NULL OR ${PERIOD_END} >= :${paramName})`;
17764
+ case "le":
17765
+ return `(${PERIOD_START} IS NULL OR ${PERIOD_START} <= :${paramName})`;
17766
+ case "sa":
17767
+ return `(${PERIOD_START} IS NOT NULL AND ${PERIOD_START} > :${paramName})`;
17768
+ case "eb":
17769
+ return `(${PERIOD_END} IS NOT NULL AND ${PERIOD_END} < :${paramName})`;
17770
+ }
17771
+ }
17772
+ function periodConstraintParamName(index) {
17773
+ return `periodConstraint${index}`;
17774
+ }
17775
+ function buildPeriodSearchPredicateSql(constraints) {
17776
+ if (constraints.length === 0) {
17777
+ return [];
17778
+ }
17779
+ const fragments = constraints.map(
17780
+ (c, i) => buildSinglePredicateSql(c.prefix, periodConstraintParamName(i))
17781
+ );
17782
+ fragments.push(HAS_ANY_BOUND_GUARD);
17783
+ return fragments;
17784
+ }
17785
+ function buildPeriodSearchPredicateParams(constraints) {
17786
+ return constraints.map((c, i) => ({
17787
+ name: periodConstraintParamName(i),
17788
+ value: c.value
17789
+ }));
17790
+ }
17791
+
17824
17792
  // src/data/operations/data/encounter/encounter-search-by-date-operation.ts
17825
- var DEFAULT_LIMIT5 = 100;
17793
+ var DEFAULT_LIMIT4 = 100;
17826
17794
  function buildSearchEncountersByDateSql(opts) {
17827
17795
  const periodPredicates = buildPeriodSearchPredicateSql(
17828
17796
  opts.periodConstraints
@@ -17851,7 +17819,7 @@ async function searchEncountersByDateOperation(params) {
17851
17819
  }
17852
17820
  const { tenantId, workspaceId } = context;
17853
17821
  const runner = params.runner ?? getDefaultPostgresQueryRunner();
17854
- const limit = params.limit ?? DEFAULT_LIMIT5;
17822
+ const limit = params.limit ?? DEFAULT_LIMIT4;
17855
17823
  const sql = buildSearchEncountersByDateSql({ periodConstraints });
17856
17824
  const queryParams = [
17857
17825
  { name: "tenantId", value: tenantId },
@@ -17871,7 +17839,7 @@ async function searchEncountersByDateOperation(params) {
17871
17839
  }
17872
17840
 
17873
17841
  // src/data/operations/data/encounter/encounter-search-by-participant-operation.ts
17874
- var DEFAULT_LIMIT6 = 100;
17842
+ var DEFAULT_LIMIT5 = 100;
17875
17843
  function buildSearchEncountersByParticipantSql(opts) {
17876
17844
  const periodPredicates = buildPeriodSearchPredicateSql(
17877
17845
  opts?.periodConstraints ?? []
@@ -17897,7 +17865,7 @@ async function searchEncountersByParticipantOperation(params) {
17897
17865
  const periodConstraints = params.periodConstraints ?? [];
17898
17866
  const { tenantId, workspaceId } = context;
17899
17867
  const runner = params.runner ?? getDefaultPostgresQueryRunner();
17900
- const limit = params.limit ?? DEFAULT_LIMIT6;
17868
+ const limit = params.limit ?? DEFAULT_LIMIT5;
17901
17869
  const { containmentRelative, containmentUrn } = buildReferenceContainmentPayload({
17902
17870
  shape: {
17903
17871
  kind: "array-of-objects",
@@ -17928,6 +17896,68 @@ async function searchEncountersByParticipantOperation(params) {
17928
17896
  return { entries, total: entries.length };
17929
17897
  }
17930
17898
 
17899
+ // src/data/operations/data/encounter/encounter-search-by-patient-operation.ts
17900
+ var DEFAULT_LIMIT6 = 100;
17901
+ function buildSearchEncountersByPatientSql(opts) {
17902
+ const periodPredicates = buildPeriodSearchPredicateSql(
17903
+ opts?.periodConstraints ?? []
17904
+ );
17905
+ const lines = [
17906
+ "SELECT resource_id AS id, resource",
17907
+ "FROM resources",
17908
+ "WHERE tenant_id = :tenantId",
17909
+ " AND workspace_id = :workspaceId",
17910
+ " AND resource_type = 'Encounter'",
17911
+ " AND deleted_at IS NULL",
17912
+ " AND (resource @> :containmentRelative::jsonb",
17913
+ " OR resource @> :containmentUrn::jsonb)"
17914
+ ];
17915
+ for (const fragment of periodPredicates) {
17916
+ lines.push(` AND ${fragment}`);
17917
+ }
17918
+ lines.push("ORDER BY last_updated DESC");
17919
+ lines.push("LIMIT :limit;");
17920
+ return lines.join("\n");
17921
+ }
17922
+ async function searchEncountersByPatientOperation(params) {
17923
+ const { context, patientId } = params;
17924
+ const periodConstraints = params.periodConstraints ?? [];
17925
+ const { tenantId, workspaceId } = context;
17926
+ const runner = params.runner ?? getDefaultPostgresQueryRunner();
17927
+ const limit = params.limit ?? DEFAULT_LIMIT6;
17928
+ const containmentRelative = JSON.stringify({
17929
+ subject: { reference: `Patient/${patientId}` }
17930
+ });
17931
+ const containmentUrn = JSON.stringify({
17932
+ subject: {
17933
+ reference: buildOpenHiResourceUrn({
17934
+ tenantId,
17935
+ workspaceId,
17936
+ resourceType: "Patient",
17937
+ resourceId: patientId
17938
+ })
17939
+ }
17940
+ });
17941
+ const sql = buildSearchEncountersByPatientSql({ periodConstraints });
17942
+ const queryParams = [
17943
+ { name: "tenantId", value: tenantId },
17944
+ { name: "workspaceId", value: workspaceId },
17945
+ { name: "containmentRelative", value: containmentRelative },
17946
+ { name: "containmentUrn", value: containmentUrn },
17947
+ { name: "limit", value: limit },
17948
+ ...buildPeriodSearchPredicateParams(periodConstraints)
17949
+ ];
17950
+ const rows = await runner.query(sql, queryParams);
17951
+ const entries = rows.map((row) => ({
17952
+ id: row.id,
17953
+ resource: {
17954
+ ...row.resource,
17955
+ id: row.id
17956
+ }
17957
+ }));
17958
+ return { entries, total: entries.length };
17959
+ }
17960
+
17931
17961
  // src/data/rest-api/routes/data/encounter/encounter-list-route.ts
17932
17962
  function singleStringQueryParam2(req, name) {
17933
17963
  const v = req.query[name];