@openhi/constructs 0.0.99 → 0.0.101

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.
@@ -4886,55 +4886,6 @@ function getDefaultPostgresQueryRunner() {
4886
4886
  return cached;
4887
4887
  }
4888
4888
 
4889
- // src/data/operations/data/appointment/appointment-search-by-date-operation.ts
4890
- var DEFAULT_LIMIT = 100;
4891
- function buildSearchAppointmentsByDateSql(opts) {
4892
- const datePredicates = buildAppointmentDateSearchPredicateSql(
4893
- opts.dateConstraints
4894
- );
4895
- const lines = [
4896
- "SELECT resource_id AS id, resource",
4897
- "FROM resources",
4898
- "WHERE tenant_id = :tenantId",
4899
- " AND workspace_id = :workspaceId",
4900
- " AND resource_type = 'Appointment'",
4901
- " AND deleted_at IS NULL"
4902
- ];
4903
- for (const fragment of datePredicates) {
4904
- lines.push(` AND ${fragment}`);
4905
- }
4906
- lines.push("ORDER BY last_updated DESC");
4907
- lines.push("LIMIT :limit;");
4908
- return lines.join("\n");
4909
- }
4910
- async function searchAppointmentsByDateOperation(params) {
4911
- const { context, dateConstraints } = params;
4912
- if (dateConstraints.length === 0) {
4913
- throw new Error(
4914
- "searchAppointmentsByDateOperation requires at least one dateConstraint"
4915
- );
4916
- }
4917
- const { tenantId, workspaceId } = context;
4918
- const runner = params.runner ?? getDefaultPostgresQueryRunner();
4919
- const limit = params.limit ?? DEFAULT_LIMIT;
4920
- const sql = buildSearchAppointmentsByDateSql({ dateConstraints });
4921
- const queryParams = [
4922
- { name: "tenantId", value: tenantId },
4923
- { name: "workspaceId", value: workspaceId },
4924
- { name: "limit", value: limit },
4925
- ...buildAppointmentDateSearchPredicateParams(dateConstraints)
4926
- ];
4927
- const rows = await runner.query(sql, queryParams);
4928
- const entries = rows.map((row) => ({
4929
- id: row.id,
4930
- resource: {
4931
- ...row.resource,
4932
- id: row.id
4933
- }
4934
- }));
4935
- return { entries, total: entries.length };
4936
- }
4937
-
4938
4889
  // src/data/operations/data/encounter/encounter-period-search-predicate.ts
4939
4890
  var PERIOD_SEARCH_PREFIXES = [
4940
4891
  "gt",
@@ -4987,7 +4938,7 @@ function buildPeriodSearchPredicateParams(constraints) {
4987
4938
  }
4988
4939
 
4989
4940
  // src/data/operations/data/encounter/encounter-search-by-patient-operation.ts
4990
- var DEFAULT_LIMIT2 = 100;
4941
+ var DEFAULT_LIMIT = 100;
4991
4942
  function buildOpenHiResourceUrn(opts) {
4992
4943
  return `urn:ohi:${opts.tenantId}:${opts.workspaceId}:${opts.resourceType}:${opts.resourceId}`;
4993
4944
  }
@@ -5017,7 +4968,7 @@ async function searchEncountersByPatientOperation(params) {
5017
4968
  const periodConstraints = params.periodConstraints ?? [];
5018
4969
  const { tenantId, workspaceId } = context;
5019
4970
  const runner = params.runner ?? getDefaultPostgresQueryRunner();
5020
- const limit = params.limit ?? DEFAULT_LIMIT2;
4971
+ const limit = params.limit ?? DEFAULT_LIMIT;
5021
4972
  const containmentRelative = JSON.stringify({
5022
4973
  subject: { reference: `Patient/${patientId}` }
5023
4974
  });
@@ -5051,8 +5002,155 @@ async function searchEncountersByPatientOperation(params) {
5051
5002
  return { entries, total: entries.length };
5052
5003
  }
5053
5004
 
5054
- // src/data/operations/data/appointment/appointment-search-by-patient-operation.ts
5005
+ // src/data/operations/data/reference-containment-predicate.ts
5006
+ var REFERENCE_CONTAINMENT_SQL_FRAGMENT = "(resource @> :containmentRelative::jsonb OR resource @> :containmentUrn::jsonb)";
5007
+ function parseTypedReference(s) {
5008
+ const match = /^([A-Za-z][A-Za-z0-9_]*)\/([^\s/]+)$/.exec(s);
5009
+ if (!match) {
5010
+ return void 0;
5011
+ }
5012
+ return { resourceType: match[1], resourceId: match[2] };
5013
+ }
5014
+ function wrapReferenceInShape(shape, reference) {
5015
+ switch (shape.kind) {
5016
+ case "scalar":
5017
+ return { [shape.field]: { reference } };
5018
+ case "array-of-references":
5019
+ return { [shape.field]: [{ reference }] };
5020
+ case "array-of-objects":
5021
+ return { [shape.field]: [{ [shape.subfield]: { reference } }] };
5022
+ }
5023
+ }
5024
+ function buildReferenceContainmentPayload(params) {
5025
+ const parsed = parseTypedReference(params.reference);
5026
+ if (!parsed) {
5027
+ throw new Error(
5028
+ `Reference "${params.reference}" is not a valid typed reference (<ResourceType>/<id>).`
5029
+ );
5030
+ }
5031
+ const urn = buildOpenHiResourceUrn({
5032
+ tenantId: params.tenantId,
5033
+ workspaceId: params.workspaceId,
5034
+ resourceType: parsed.resourceType,
5035
+ resourceId: parsed.resourceId
5036
+ });
5037
+ return {
5038
+ containmentRelative: JSON.stringify(
5039
+ wrapReferenceInShape(params.shape, params.reference)
5040
+ ),
5041
+ containmentUrn: JSON.stringify(wrapReferenceInShape(params.shape, urn))
5042
+ };
5043
+ }
5044
+
5045
+ // src/data/operations/data/appointment/appointment-search-by-actor-operation.ts
5046
+ var DEFAULT_LIMIT2 = 100;
5047
+ function buildSearchAppointmentsByActorSql(opts) {
5048
+ const datePredicates = buildAppointmentDateSearchPredicateSql(
5049
+ opts?.dateConstraints ?? []
5050
+ );
5051
+ const lines = [
5052
+ "SELECT resource_id AS id, resource",
5053
+ "FROM resources",
5054
+ "WHERE tenant_id = :tenantId",
5055
+ " AND workspace_id = :workspaceId",
5056
+ " AND resource_type = 'Appointment'",
5057
+ " AND deleted_at IS NULL",
5058
+ ` AND ${REFERENCE_CONTAINMENT_SQL_FRAGMENT}`
5059
+ ];
5060
+ for (const fragment of datePredicates) {
5061
+ lines.push(` AND ${fragment}`);
5062
+ }
5063
+ lines.push("ORDER BY last_updated DESC");
5064
+ lines.push("LIMIT :limit;");
5065
+ return lines.join("\n");
5066
+ }
5067
+ async function searchAppointmentsByActorOperation(params) {
5068
+ const { context, actorReference } = params;
5069
+ const dateConstraints = params.dateConstraints ?? [];
5070
+ const { tenantId, workspaceId } = context;
5071
+ const runner = params.runner ?? getDefaultPostgresQueryRunner();
5072
+ const limit = params.limit ?? DEFAULT_LIMIT2;
5073
+ const { containmentRelative, containmentUrn } = buildReferenceContainmentPayload({
5074
+ shape: {
5075
+ kind: "array-of-objects",
5076
+ field: "participant",
5077
+ subfield: "actor"
5078
+ },
5079
+ reference: actorReference,
5080
+ tenantId,
5081
+ workspaceId
5082
+ });
5083
+ const sql = buildSearchAppointmentsByActorSql({ dateConstraints });
5084
+ const queryParams = [
5085
+ { name: "tenantId", value: tenantId },
5086
+ { name: "workspaceId", value: workspaceId },
5087
+ { name: "containmentRelative", value: containmentRelative },
5088
+ { name: "containmentUrn", value: containmentUrn },
5089
+ { name: "limit", value: limit },
5090
+ ...buildAppointmentDateSearchPredicateParams(dateConstraints)
5091
+ ];
5092
+ const rows = await runner.query(sql, queryParams);
5093
+ const entries = rows.map((row) => ({
5094
+ id: row.id,
5095
+ resource: {
5096
+ ...row.resource,
5097
+ id: row.id
5098
+ }
5099
+ }));
5100
+ return { entries, total: entries.length };
5101
+ }
5102
+
5103
+ // src/data/operations/data/appointment/appointment-search-by-date-operation.ts
5055
5104
  var DEFAULT_LIMIT3 = 100;
5105
+ function buildSearchAppointmentsByDateSql(opts) {
5106
+ const datePredicates = buildAppointmentDateSearchPredicateSql(
5107
+ opts.dateConstraints
5108
+ );
5109
+ const lines = [
5110
+ "SELECT resource_id AS id, resource",
5111
+ "FROM resources",
5112
+ "WHERE tenant_id = :tenantId",
5113
+ " AND workspace_id = :workspaceId",
5114
+ " AND resource_type = 'Appointment'",
5115
+ " AND deleted_at IS NULL"
5116
+ ];
5117
+ for (const fragment of datePredicates) {
5118
+ lines.push(` AND ${fragment}`);
5119
+ }
5120
+ lines.push("ORDER BY last_updated DESC");
5121
+ lines.push("LIMIT :limit;");
5122
+ return lines.join("\n");
5123
+ }
5124
+ async function searchAppointmentsByDateOperation(params) {
5125
+ const { context, dateConstraints } = params;
5126
+ if (dateConstraints.length === 0) {
5127
+ throw new Error(
5128
+ "searchAppointmentsByDateOperation requires at least one dateConstraint"
5129
+ );
5130
+ }
5131
+ const { tenantId, workspaceId } = context;
5132
+ const runner = params.runner ?? getDefaultPostgresQueryRunner();
5133
+ const limit = params.limit ?? DEFAULT_LIMIT3;
5134
+ const sql = buildSearchAppointmentsByDateSql({ dateConstraints });
5135
+ const queryParams = [
5136
+ { name: "tenantId", value: tenantId },
5137
+ { name: "workspaceId", value: workspaceId },
5138
+ { name: "limit", value: limit },
5139
+ ...buildAppointmentDateSearchPredicateParams(dateConstraints)
5140
+ ];
5141
+ const rows = await runner.query(sql, queryParams);
5142
+ const entries = rows.map((row) => ({
5143
+ id: row.id,
5144
+ resource: {
5145
+ ...row.resource,
5146
+ id: row.id
5147
+ }
5148
+ }));
5149
+ return { entries, total: entries.length };
5150
+ }
5151
+
5152
+ // src/data/operations/data/appointment/appointment-search-by-patient-operation.ts
5153
+ var DEFAULT_LIMIT4 = 100;
5056
5154
  function buildSearchAppointmentsByPatientSql(opts) {
5057
5155
  const datePredicates = buildAppointmentDateSearchPredicateSql(
5058
5156
  opts?.dateConstraints ?? []
@@ -5079,7 +5177,7 @@ async function searchAppointmentsByPatientOperation(params) {
5079
5177
  const dateConstraints = params.dateConstraints ?? [];
5080
5178
  const { tenantId, workspaceId } = context;
5081
5179
  const runner = params.runner ?? getDefaultPostgresQueryRunner();
5082
- const limit = params.limit ?? DEFAULT_LIMIT3;
5180
+ const limit = params.limit ?? DEFAULT_LIMIT4;
5083
5181
  const containmentRelative = JSON.stringify({
5084
5182
  participant: [{ actor: { reference: `Patient/${patientId}` } }]
5085
5183
  });
@@ -5166,11 +5264,45 @@ function sendInvalidSearch400(res, diagnostics) {
5166
5264
  }
5167
5265
  async function listAppointmentsRoute(req, res) {
5168
5266
  const patientId = singleStringQueryParam(req, "patient");
5267
+ const actorRef = singleStringQueryParam(req, "actor");
5169
5268
  const parsed = parseAppointmentDateConstraints(req);
5170
5269
  if (isError(parsed)) {
5171
5270
  return sendInvalidSearch400(res, parsed.error);
5172
5271
  }
5173
5272
  const dateConstraints = parsed;
5273
+ if (patientId !== void 0 && actorRef !== void 0) {
5274
+ return sendInvalidSearch400(
5275
+ res,
5276
+ "?patient= and ?actor= cannot be combined on the same request."
5277
+ );
5278
+ }
5279
+ if (actorRef !== void 0) {
5280
+ if (parseTypedReference(actorRef) === void 0) {
5281
+ return sendInvalidSearch400(
5282
+ res,
5283
+ `?actor must be a typed reference like "Practitioner/<id>"; got "${actorRef}".`
5284
+ );
5285
+ }
5286
+ const ctx = req.openhiContext;
5287
+ try {
5288
+ const result = await searchAppointmentsByActorOperation({
5289
+ context: ctx,
5290
+ actorReference: actorRef,
5291
+ dateConstraints
5292
+ });
5293
+ const bundle = buildSearchsetBundle(
5294
+ BASE_PATH.APPOINTMENT,
5295
+ result.entries
5296
+ );
5297
+ return res.json(bundle);
5298
+ } catch (err) {
5299
+ return sendOperationOutcome500(
5300
+ res,
5301
+ err,
5302
+ "GET /Appointment?actor= search error:"
5303
+ );
5304
+ }
5305
+ }
5174
5306
  if (patientId !== void 0) {
5175
5307
  const ctx = req.openhiContext;
5176
5308
  try {
@@ -12762,7 +12894,7 @@ async function listEncountersOperation(params) {
12762
12894
  }
12763
12895
 
12764
12896
  // src/data/operations/data/encounter/encounter-search-by-date-operation.ts
12765
- var DEFAULT_LIMIT4 = 100;
12897
+ var DEFAULT_LIMIT5 = 100;
12766
12898
  function buildSearchEncountersByDateSql(opts) {
12767
12899
  const periodPredicates = buildPeriodSearchPredicateSql(
12768
12900
  opts.periodConstraints
@@ -12791,7 +12923,7 @@ async function searchEncountersByDateOperation(params) {
12791
12923
  }
12792
12924
  const { tenantId, workspaceId } = context;
12793
12925
  const runner = params.runner ?? getDefaultPostgresQueryRunner();
12794
- const limit = params.limit ?? DEFAULT_LIMIT4;
12926
+ const limit = params.limit ?? DEFAULT_LIMIT5;
12795
12927
  const sql = buildSearchEncountersByDateSql({ periodConstraints });
12796
12928
  const queryParams = [
12797
12929
  { name: "tenantId", value: tenantId },
@@ -12810,6 +12942,64 @@ async function searchEncountersByDateOperation(params) {
12810
12942
  return { entries, total: entries.length };
12811
12943
  }
12812
12944
 
12945
+ // src/data/operations/data/encounter/encounter-search-by-participant-operation.ts
12946
+ var DEFAULT_LIMIT6 = 100;
12947
+ function buildSearchEncountersByParticipantSql(opts) {
12948
+ const periodPredicates = buildPeriodSearchPredicateSql(
12949
+ opts?.periodConstraints ?? []
12950
+ );
12951
+ const lines = [
12952
+ "SELECT resource_id AS id, resource",
12953
+ "FROM resources",
12954
+ "WHERE tenant_id = :tenantId",
12955
+ " AND workspace_id = :workspaceId",
12956
+ " AND resource_type = 'Encounter'",
12957
+ " AND deleted_at IS NULL",
12958
+ ` AND ${REFERENCE_CONTAINMENT_SQL_FRAGMENT}`
12959
+ ];
12960
+ for (const fragment of periodPredicates) {
12961
+ lines.push(` AND ${fragment}`);
12962
+ }
12963
+ lines.push("ORDER BY last_updated DESC");
12964
+ lines.push("LIMIT :limit;");
12965
+ return lines.join("\n");
12966
+ }
12967
+ async function searchEncountersByParticipantOperation(params) {
12968
+ const { context, participantReference } = params;
12969
+ const periodConstraints = params.periodConstraints ?? [];
12970
+ const { tenantId, workspaceId } = context;
12971
+ const runner = params.runner ?? getDefaultPostgresQueryRunner();
12972
+ const limit = params.limit ?? DEFAULT_LIMIT6;
12973
+ const { containmentRelative, containmentUrn } = buildReferenceContainmentPayload({
12974
+ shape: {
12975
+ kind: "array-of-objects",
12976
+ field: "participant",
12977
+ subfield: "individual"
12978
+ },
12979
+ reference: participantReference,
12980
+ tenantId,
12981
+ workspaceId
12982
+ });
12983
+ const sql = buildSearchEncountersByParticipantSql({ periodConstraints });
12984
+ const queryParams = [
12985
+ { name: "tenantId", value: tenantId },
12986
+ { name: "workspaceId", value: workspaceId },
12987
+ { name: "containmentRelative", value: containmentRelative },
12988
+ { name: "containmentUrn", value: containmentUrn },
12989
+ { name: "limit", value: limit },
12990
+ ...buildPeriodSearchPredicateParams(periodConstraints)
12991
+ ];
12992
+ const rows = await runner.query(sql, queryParams);
12993
+ const entries = rows.map((row) => ({
12994
+ id: row.id,
12995
+ resource: {
12996
+ ...row.resource,
12997
+ id: row.id
12998
+ }
12999
+ }));
13000
+ return { entries, total: entries.length };
13001
+ }
13002
+
12813
13003
  // src/data/rest-api/routes/data/encounter/encounter-list-route.ts
12814
13004
  function singleStringQueryParam2(req, name) {
12815
13005
  const v = req.query[name];
@@ -12859,11 +13049,42 @@ function sendInvalidSearch4002(res, diagnostics) {
12859
13049
  }
12860
13050
  async function listEncountersRoute(req, res) {
12861
13051
  const patientId = singleStringQueryParam2(req, "patient");
13052
+ const participantRef = singleStringQueryParam2(req, "participant");
12862
13053
  const parsed = parseEncounterDateConstraints(req);
12863
13054
  if (isError2(parsed)) {
12864
13055
  return sendInvalidSearch4002(res, parsed.error);
12865
13056
  }
12866
13057
  const periodConstraints = parsed;
13058
+ if (patientId !== void 0 && participantRef !== void 0) {
13059
+ return sendInvalidSearch4002(
13060
+ res,
13061
+ "?patient= and ?participant= cannot be combined on the same request."
13062
+ );
13063
+ }
13064
+ if (participantRef !== void 0) {
13065
+ if (parseTypedReference(participantRef) === void 0) {
13066
+ return sendInvalidSearch4002(
13067
+ res,
13068
+ `?participant must be a typed reference like "Practitioner/<id>"; got "${participantRef}".`
13069
+ );
13070
+ }
13071
+ const ctx = req.openhiContext;
13072
+ try {
13073
+ const result = await searchEncountersByParticipantOperation({
13074
+ context: ctx,
13075
+ participantReference: participantRef,
13076
+ periodConstraints
13077
+ });
13078
+ const bundle = buildSearchsetBundle(BASE_PATH.ENCOUNTER, result.entries);
13079
+ return res.json(bundle);
13080
+ } catch (err) {
13081
+ return sendOperationOutcome500(
13082
+ res,
13083
+ err,
13084
+ "GET /Encounter?participant= search error:"
13085
+ );
13086
+ }
13087
+ }
12867
13088
  if (patientId !== void 0) {
12868
13089
  const ctx = req.openhiContext;
12869
13090
  try {
@@ -24664,8 +24885,91 @@ async function listPatientsOperation(params) {
24664
24885
  );
24665
24886
  }
24666
24887
 
24888
+ // src/data/operations/data/patient/patient-search-by-general-practitioner-operation.ts
24889
+ var DEFAULT_LIMIT7 = 100;
24890
+ function buildSearchPatientsByGeneralPractitionerSql() {
24891
+ return [
24892
+ "SELECT resource_id AS id, resource",
24893
+ "FROM resources",
24894
+ "WHERE tenant_id = :tenantId",
24895
+ " AND workspace_id = :workspaceId",
24896
+ " AND resource_type = 'Patient'",
24897
+ " AND deleted_at IS NULL",
24898
+ ` AND ${REFERENCE_CONTAINMENT_SQL_FRAGMENT}`,
24899
+ "ORDER BY last_updated DESC",
24900
+ "LIMIT :limit;"
24901
+ ].join("\n");
24902
+ }
24903
+ async function searchPatientsByGeneralPractitionerOperation(params) {
24904
+ const { context, generalPractitionerReference } = params;
24905
+ const { tenantId, workspaceId } = context;
24906
+ const runner = params.runner ?? getDefaultPostgresQueryRunner();
24907
+ const limit = params.limit ?? DEFAULT_LIMIT7;
24908
+ const { containmentRelative, containmentUrn } = buildReferenceContainmentPayload({
24909
+ shape: { kind: "array-of-references", field: "generalPractitioner" },
24910
+ reference: generalPractitionerReference,
24911
+ tenantId,
24912
+ workspaceId
24913
+ });
24914
+ const sql = buildSearchPatientsByGeneralPractitionerSql();
24915
+ const queryParams = [
24916
+ { name: "tenantId", value: tenantId },
24917
+ { name: "workspaceId", value: workspaceId },
24918
+ { name: "containmentRelative", value: containmentRelative },
24919
+ { name: "containmentUrn", value: containmentUrn },
24920
+ { name: "limit", value: limit }
24921
+ ];
24922
+ const rows = await runner.query(sql, queryParams);
24923
+ const entries = rows.map((row) => ({
24924
+ id: row.id,
24925
+ resource: { ...row.resource, id: row.id }
24926
+ }));
24927
+ return { entries, total: entries.length };
24928
+ }
24929
+
24667
24930
  // src/data/rest-api/routes/data/patient/patient-list-route.ts
24931
+ function singleStringQueryParam3(req, name) {
24932
+ const v = req.query[name];
24933
+ if (typeof v !== "string") {
24934
+ return void 0;
24935
+ }
24936
+ const trimmed = v.trim();
24937
+ return trimmed === "" ? void 0 : trimmed;
24938
+ }
24939
+ function sendInvalidSearch4003(res, diagnostics) {
24940
+ return res.status(400).json({
24941
+ resourceType: "OperationOutcome",
24942
+ issue: [{ severity: "error", code: "invalid", diagnostics }]
24943
+ });
24944
+ }
24668
24945
  async function listPatientsRoute(req, res) {
24946
+ const generalPractitionerRef = singleStringQueryParam3(
24947
+ req,
24948
+ "general-practitioner"
24949
+ );
24950
+ if (generalPractitionerRef !== void 0) {
24951
+ if (parseTypedReference(generalPractitionerRef) === void 0) {
24952
+ return sendInvalidSearch4003(
24953
+ res,
24954
+ `?general-practitioner must be a typed reference like "Practitioner/<id>"; got "${generalPractitionerRef}".`
24955
+ );
24956
+ }
24957
+ const ctx = req.openhiContext;
24958
+ try {
24959
+ const result = await searchPatientsByGeneralPractitionerOperation({
24960
+ context: ctx,
24961
+ generalPractitionerReference: generalPractitionerRef
24962
+ });
24963
+ const bundle = buildSearchsetBundle(BASE_PATH.PATIENT, result.entries);
24964
+ return res.json(bundle);
24965
+ } catch (err) {
24966
+ return sendOperationOutcome500(
24967
+ res,
24968
+ err,
24969
+ "GET /Patient?general-practitioner= search error:"
24970
+ );
24971
+ }
24972
+ }
24669
24973
  return handleListRoute({
24670
24974
  req,
24671
24975
  res,
@@ -28552,8 +28856,90 @@ async function listSchedulesOperation(params) {
28552
28856
  );
28553
28857
  }
28554
28858
 
28859
+ // src/data/operations/data/schedule/schedule-search-by-actor-operation.ts
28860
+ var DEFAULT_LIMIT8 = 100;
28861
+ function buildSearchSchedulesByActorSql() {
28862
+ return [
28863
+ "SELECT resource_id AS id, resource",
28864
+ "FROM resources",
28865
+ "WHERE tenant_id = :tenantId",
28866
+ " AND workspace_id = :workspaceId",
28867
+ " AND resource_type = 'Schedule'",
28868
+ " AND deleted_at IS NULL",
28869
+ ` AND ${REFERENCE_CONTAINMENT_SQL_FRAGMENT}`,
28870
+ "ORDER BY last_updated DESC",
28871
+ "LIMIT :limit;"
28872
+ ].join("\n");
28873
+ }
28874
+ async function searchSchedulesByActorOperation(params) {
28875
+ const { context, actorReference } = params;
28876
+ const { tenantId, workspaceId } = context;
28877
+ const runner = params.runner ?? getDefaultPostgresQueryRunner();
28878
+ const limit = params.limit ?? DEFAULT_LIMIT8;
28879
+ const { containmentRelative, containmentUrn } = buildReferenceContainmentPayload({
28880
+ shape: { kind: "array-of-references", field: "actor" },
28881
+ reference: actorReference,
28882
+ tenantId,
28883
+ workspaceId
28884
+ });
28885
+ const queryParams = [
28886
+ { name: "tenantId", value: tenantId },
28887
+ { name: "workspaceId", value: workspaceId },
28888
+ { name: "containmentRelative", value: containmentRelative },
28889
+ { name: "containmentUrn", value: containmentUrn },
28890
+ { name: "limit", value: limit }
28891
+ ];
28892
+ const rows = await runner.query(
28893
+ buildSearchSchedulesByActorSql(),
28894
+ queryParams
28895
+ );
28896
+ const entries = rows.map((row) => ({
28897
+ id: row.id,
28898
+ resource: { ...row.resource, id: row.id }
28899
+ }));
28900
+ return { entries, total: entries.length };
28901
+ }
28902
+
28555
28903
  // src/data/rest-api/routes/data/schedule/schedule-list-route.ts
28904
+ function singleStringQueryParam4(req, name) {
28905
+ const v = req.query[name];
28906
+ if (typeof v !== "string") {
28907
+ return void 0;
28908
+ }
28909
+ const trimmed = v.trim();
28910
+ return trimmed === "" ? void 0 : trimmed;
28911
+ }
28912
+ function sendInvalidSearch4004(res, diagnostics) {
28913
+ return res.status(400).json({
28914
+ resourceType: "OperationOutcome",
28915
+ issue: [{ severity: "error", code: "invalid", diagnostics }]
28916
+ });
28917
+ }
28556
28918
  async function listSchedulesRoute(req, res) {
28919
+ const actorRef = singleStringQueryParam4(req, "actor");
28920
+ if (actorRef !== void 0) {
28921
+ if (parseTypedReference(actorRef) === void 0) {
28922
+ return sendInvalidSearch4004(
28923
+ res,
28924
+ `?actor must be a typed reference like "Practitioner/<id>"; got "${actorRef}".`
28925
+ );
28926
+ }
28927
+ const ctx = req.openhiContext;
28928
+ try {
28929
+ const result = await searchSchedulesByActorOperation({
28930
+ context: ctx,
28931
+ actorReference: actorRef
28932
+ });
28933
+ const bundle = buildSearchsetBundle(BASE_PATH.SCHEDULE, result.entries);
28934
+ return res.json(bundle);
28935
+ } catch (err) {
28936
+ return sendOperationOutcome500(
28937
+ res,
28938
+ err,
28939
+ "GET /Schedule?actor= search error:"
28940
+ );
28941
+ }
28942
+ }
28557
28943
  return handleListRoute({
28558
28944
  req,
28559
28945
  res,
@@ -32234,8 +32620,164 @@ async function listTasksOperation(params) {
32234
32620
  );
32235
32621
  }
32236
32622
 
32623
+ // src/data/operations/data/task/task-search-by-owner-operation.ts
32624
+ var DEFAULT_LIMIT9 = 100;
32625
+ function buildSearchTasksByOwnerSql() {
32626
+ return [
32627
+ "SELECT resource_id AS id, resource",
32628
+ "FROM resources",
32629
+ "WHERE tenant_id = :tenantId",
32630
+ " AND workspace_id = :workspaceId",
32631
+ " AND resource_type = 'Task'",
32632
+ " AND deleted_at IS NULL",
32633
+ ` AND ${REFERENCE_CONTAINMENT_SQL_FRAGMENT}`,
32634
+ "ORDER BY last_updated DESC",
32635
+ "LIMIT :limit;"
32636
+ ].join("\n");
32637
+ }
32638
+ async function searchTasksByOwnerOperation(params) {
32639
+ const { context, ownerReference } = params;
32640
+ const { tenantId, workspaceId } = context;
32641
+ const runner = params.runner ?? getDefaultPostgresQueryRunner();
32642
+ const limit = params.limit ?? DEFAULT_LIMIT9;
32643
+ const { containmentRelative, containmentUrn } = buildReferenceContainmentPayload({
32644
+ shape: { kind: "scalar", field: "owner" },
32645
+ reference: ownerReference,
32646
+ tenantId,
32647
+ workspaceId
32648
+ });
32649
+ const queryParams = [
32650
+ { name: "tenantId", value: tenantId },
32651
+ { name: "workspaceId", value: workspaceId },
32652
+ { name: "containmentRelative", value: containmentRelative },
32653
+ { name: "containmentUrn", value: containmentUrn },
32654
+ { name: "limit", value: limit }
32655
+ ];
32656
+ const rows = await runner.query(
32657
+ buildSearchTasksByOwnerSql(),
32658
+ queryParams
32659
+ );
32660
+ const entries = rows.map((row) => ({
32661
+ id: row.id,
32662
+ resource: { ...row.resource, id: row.id }
32663
+ }));
32664
+ return { entries, total: entries.length };
32665
+ }
32666
+
32667
+ // src/data/operations/data/task/task-search-by-requester-operation.ts
32668
+ var DEFAULT_LIMIT10 = 100;
32669
+ function buildSearchTasksByRequesterSql() {
32670
+ return [
32671
+ "SELECT resource_id AS id, resource",
32672
+ "FROM resources",
32673
+ "WHERE tenant_id = :tenantId",
32674
+ " AND workspace_id = :workspaceId",
32675
+ " AND resource_type = 'Task'",
32676
+ " AND deleted_at IS NULL",
32677
+ ` AND ${REFERENCE_CONTAINMENT_SQL_FRAGMENT}`,
32678
+ "ORDER BY last_updated DESC",
32679
+ "LIMIT :limit;"
32680
+ ].join("\n");
32681
+ }
32682
+ async function searchTasksByRequesterOperation(params) {
32683
+ const { context, requesterReference } = params;
32684
+ const { tenantId, workspaceId } = context;
32685
+ const runner = params.runner ?? getDefaultPostgresQueryRunner();
32686
+ const limit = params.limit ?? DEFAULT_LIMIT10;
32687
+ const { containmentRelative, containmentUrn } = buildReferenceContainmentPayload({
32688
+ shape: { kind: "scalar", field: "requester" },
32689
+ reference: requesterReference,
32690
+ tenantId,
32691
+ workspaceId
32692
+ });
32693
+ const queryParams = [
32694
+ { name: "tenantId", value: tenantId },
32695
+ { name: "workspaceId", value: workspaceId },
32696
+ { name: "containmentRelative", value: containmentRelative },
32697
+ { name: "containmentUrn", value: containmentUrn },
32698
+ { name: "limit", value: limit }
32699
+ ];
32700
+ const rows = await runner.query(
32701
+ buildSearchTasksByRequesterSql(),
32702
+ queryParams
32703
+ );
32704
+ const entries = rows.map((row) => ({
32705
+ id: row.id,
32706
+ resource: { ...row.resource, id: row.id }
32707
+ }));
32708
+ return { entries, total: entries.length };
32709
+ }
32710
+
32237
32711
  // src/data/rest-api/routes/data/task/task-list-route.ts
32712
+ function singleStringQueryParam5(req, name) {
32713
+ const v = req.query[name];
32714
+ if (typeof v !== "string") {
32715
+ return void 0;
32716
+ }
32717
+ const trimmed = v.trim();
32718
+ return trimmed === "" ? void 0 : trimmed;
32719
+ }
32720
+ function sendInvalidSearch4005(res, diagnostics) {
32721
+ return res.status(400).json({
32722
+ resourceType: "OperationOutcome",
32723
+ issue: [{ severity: "error", code: "invalid", diagnostics }]
32724
+ });
32725
+ }
32238
32726
  async function listTasksRoute(req, res) {
32727
+ const ownerRef = singleStringQueryParam5(req, "owner");
32728
+ const requesterRef = singleStringQueryParam5(req, "requester");
32729
+ if (ownerRef !== void 0 && requesterRef !== void 0) {
32730
+ return sendInvalidSearch4005(
32731
+ res,
32732
+ "?owner= and ?requester= cannot be combined on the same request."
32733
+ );
32734
+ }
32735
+ if (ownerRef !== void 0) {
32736
+ if (parseTypedReference(ownerRef) === void 0) {
32737
+ return sendInvalidSearch4005(
32738
+ res,
32739
+ `?owner must be a typed reference like "Practitioner/<id>"; got "${ownerRef}".`
32740
+ );
32741
+ }
32742
+ const ctx = req.openhiContext;
32743
+ try {
32744
+ const result = await searchTasksByOwnerOperation({
32745
+ context: ctx,
32746
+ ownerReference: ownerRef
32747
+ });
32748
+ const bundle = buildSearchsetBundle(BASE_PATH.TASK, result.entries);
32749
+ return res.json(bundle);
32750
+ } catch (err) {
32751
+ return sendOperationOutcome500(
32752
+ res,
32753
+ err,
32754
+ "GET /Task?owner= search error:"
32755
+ );
32756
+ }
32757
+ }
32758
+ if (requesterRef !== void 0) {
32759
+ if (parseTypedReference(requesterRef) === void 0) {
32760
+ return sendInvalidSearch4005(
32761
+ res,
32762
+ `?requester must be a typed reference like "Practitioner/<id>"; got "${requesterRef}".`
32763
+ );
32764
+ }
32765
+ const ctx = req.openhiContext;
32766
+ try {
32767
+ const result = await searchTasksByRequesterOperation({
32768
+ context: ctx,
32769
+ requesterReference: requesterRef
32770
+ });
32771
+ const bundle = buildSearchsetBundle(BASE_PATH.TASK, result.entries);
32772
+ return res.json(bundle);
32773
+ } catch (err) {
32774
+ return sendOperationOutcome500(
32775
+ res,
32776
+ err,
32777
+ "GET /Task?requester= search error:"
32778
+ );
32779
+ }
32780
+ }
32239
32781
  return handleListRoute({
32240
32782
  req,
32241
32783
  res,