@nsshunt/stsfhirpg 1.1.7 → 1.2.2

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.
@@ -1,9 +1,9 @@
1
1
  import fs from "node:fs";
2
- import { defaultLogger, Sleep } from "@nsshunt/stsutils";
2
+ import { defaultLogger } from "@nsshunt/stsutils";
3
3
  import { isAbsoluteUrl } from "@nsshunt/stsfhirclient";
4
4
  import { goptions } from "@nsshunt/stsconfig";
5
5
  import cluster from "cluster";
6
- import require$$0, { randomUUID as randomUUID$1 } from "crypto";
6
+ import require$$0 from "crypto";
7
7
  import require$$0$3 from "events";
8
8
  import require$$1$1 from "util";
9
9
  import require$$0$2 from "dns";
@@ -13,7 +13,6 @@ import require$$1$2 from "tls";
13
13
  import require$$0$7 from "path";
14
14
  import require$$0$6 from "stream";
15
15
  import require$$0$5 from "buffer";
16
- import { createClient } from "redis";
17
16
  class LuxonError extends Error {
18
17
  }
19
18
  class InvalidDateTimeError extends LuxonError {
@@ -7024,7 +7023,8 @@ class ResourceHelper {
7024
7023
  this.#definitions = {
7025
7024
  resources: {},
7026
7025
  types: {},
7027
- searchParameters: {}
7026
+ searchParametersByUrl: {},
7027
+ searchParametersByResourceType: {}
7028
7028
  };
7029
7029
  }
7030
7030
  __resources.entry.forEach((entry) => {
@@ -7041,25 +7041,22 @@ class ResourceHelper {
7041
7041
  }
7042
7042
  });
7043
7043
  __searchParams.entry.forEach((entry) => {
7044
- this.#definitions.searchParameters[entry.fullUrl] = entry.resource;
7044
+ this.#definitions.searchParametersByUrl[entry.fullUrl] = entry.resource;
7045
7045
  });
7046
+ this._LoadSearchParameters();
7046
7047
  return this.#definitions;
7047
7048
  };
7048
- GetType = (typeName) => {
7049
+ get definitions() {
7049
7050
  if (!this.#definitions) {
7050
7051
  this.#LoadDefinitions();
7051
7052
  }
7052
- if (this.#definitions) {
7053
- const foundType = this.#definitions.types[typeName];
7054
- return foundType;
7055
- }
7056
- return [];
7053
+ return this.#definitions;
7054
+ }
7055
+ GetType = (typeName) => {
7056
+ return this.definitions.types[typeName];
7057
7057
  };
7058
7058
  GetResource = (resourceType) => {
7059
- if (!this.#definitions) {
7060
- this.#LoadDefinitions();
7061
- }
7062
- return this.#definitions.resources[resourceType];
7059
+ return this.definitions.resources[resourceType];
7063
7060
  };
7064
7061
  GetResourceField = (resourceType, fieldPath) => {
7065
7062
  const resource = this.GetResource(resourceType);
@@ -7072,22 +7069,215 @@ class ResourceHelper {
7072
7069
  }
7073
7070
  };
7074
7071
  GetSearchParam = (url) => {
7075
- if (!this.#definitions) {
7076
- this.#LoadDefinitions();
7077
- }
7078
- return this.#definitions.searchParameters[url];
7072
+ return this.definitions.searchParametersByUrl[url];
7079
7073
  };
7080
7074
  GetSearchParams = () => {
7081
- if (!this.#definitions) {
7082
- this.#LoadDefinitions();
7083
- }
7084
- return this.#definitions.searchParameters;
7075
+ return this.definitions.searchParametersByUrl;
7085
7076
  };
7086
7077
  GetSearchParamsByResource = (resource) => {
7087
- if (!this.#definitions) {
7088
- this.#LoadDefinitions();
7078
+ return Object.values(this.definitions.searchParametersByUrl).filter((sp) => sp.base.includes(resource)).map((sp) => sp);
7079
+ };
7080
+ // ------------------------------------------------------------------------------------------------------------------
7081
+ // Remove ( ) when either are present
7082
+ #RemoveOuterParentheses = (input) => {
7083
+ return input.replace(/^\(|\)$/g, "");
7084
+ };
7085
+ // Remove ( ) only when both are present
7086
+ #RemoveSurroundingParentheses = (input) => {
7087
+ return input.replace(/^\((.*)\)$/, "$1").trim();
7088
+ };
7089
+ /*
7090
+
7091
+ NamingSystem derived-from reference NamingSystem.relatedArtifact.where(type='derived-from').resource
7092
+
7093
+ NamingSystem predecessor reference NamingSystem.relatedArtifact.where(type='predecessor').resource
7094
+
7095
+ ClinicalUseDefinition product reference ClinicalUseDefinition.subject.where(resolve() is MedicinalProductDefinition)
7096
+
7097
+ OrganizationAffiliation email token OrganizationAffiliation.contact.telecom.where(system='email')
7098
+ OrganizationAffiliation phone token OrganizationAffiliation.contact.telecom.where(system='phone')
7099
+
7100
+ PackagedProductDefinition biological reference PackagedProductDefinition.packaging.containedItem.item.reference
7101
+ PackagedProductDefinition contained-item reference PackagedProductDefinition.packaging.containedItem.item.reference
7102
+
7103
+ Patient deceased token Patient.deceased.exists() and Patient.deceased != false
7104
+ Practitioner deceased token Practitioner.deceased.exists() and Practitioner.deceased != false
7105
+
7106
+ Location contains special Location.extension('http://hl7.org/fhir/StructureDefinition/location-boundary-geojson').value
7107
+
7108
+ QuestionnaireResponse item-subject reference QuestionnaireResponse.item.where(extension('http://hl7.org/fhir/StructureDefinition/questionnaireresponse-isSubject').exists()).answer.valueReference
7109
+ */
7110
+ ProcessExpressions = (resourceName, SP_EXPRESSION) => {
7111
+ let expressions = [];
7112
+ expressions = SP_EXPRESSION.split("|").map((e) => e.trim());
7113
+ expressions = expressions.map((e) => this.#RemoveSurroundingParentheses(e).trim());
7114
+ if (resourceName !== "") {
7115
+ expressions = expressions.filter((e) => e.split(".")[0].trim().localeCompare(resourceName) === 0);
7089
7116
  }
7090
- return Object.values(this.#definitions.searchParameters).filter((sp) => sp.base.includes(resource)).map((sp) => sp);
7117
+ let original_expressions = [...expressions];
7118
+ expressions = expressions.map((e) => {
7119
+ let capturedTypeOf = void 0;
7120
+ return {
7121
+ path: e.replace(
7122
+ /\.ofType\(([^)]+)\)/g,
7123
+ (_, typeName) => {
7124
+ capturedTypeOf = true;
7125
+ return typeName.charAt(0).toUpperCase() + typeName.slice(1);
7126
+ }
7127
+ ),
7128
+ typeOf: capturedTypeOf
7129
+ };
7130
+ });
7131
+ expressions.forEach((expression) => {
7132
+ try {
7133
+ const sp = expression;
7134
+ if (sp.path.indexOf("exists()") >= 0) {
7135
+ const parts = sp.path.split(" ");
7136
+ const i = parts[0].indexOf("exists()");
7137
+ if (i >= 0) {
7138
+ let fieldExistsEx = parts[0].substring(0, i - 1);
7139
+ let op = parts[1];
7140
+ let fieldTestEx = parts[2];
7141
+ let comparator = parts[3];
7142
+ let value = parts[4];
7143
+ const fieldExistsParts = fieldExistsEx.split(".");
7144
+ let fieldExists = fieldExistsParts.slice(1).join(".");
7145
+ const fieldTestParts = fieldTestEx.split(".");
7146
+ let fieldTest = fieldTestParts.slice(1).join(".");
7147
+ sp.exists = {
7148
+ fieldExists: [`${fieldExists}Boolean`, `${fieldExists}DataTime`],
7149
+ // [x]Boolean or [x]DateTime
7150
+ op,
7151
+ fieldTest: [`${fieldTest}Boolean`, `${fieldTest}DataTime`],
7152
+ comparator,
7153
+ value: [value, void 0]
7154
+ };
7155
+ }
7156
+ }
7157
+ } catch (error) {
7158
+ }
7159
+ });
7160
+ let capturedType;
7161
+ expressions = expressions.map((obj) => {
7162
+ capturedType = void 0;
7163
+ const { path, typeOf, exists } = obj;
7164
+ return {
7165
+ path: path.replace(
7166
+ /\.where\(resolve\(\)\s+is\s+([^)]+)\)/,
7167
+ (_, typeName) => {
7168
+ capturedType = typeName;
7169
+ return "";
7170
+ }
7171
+ ),
7172
+ typeOf,
7173
+ reference: capturedType,
7174
+ exists
7175
+ };
7176
+ });
7177
+ let capturedWhere = void 0;
7178
+ expressions = expressions.map((obj) => {
7179
+ capturedWhere = void 0;
7180
+ const { path, reference, typeOf, exists } = obj;
7181
+ const retVal = {
7182
+ path: path.replace(/([^.]+)\.where\(([^=]+)='([^']+)'\)/g, (_, field, subfield, value) => {
7183
+ capturedWhere = { field, subfield, value };
7184
+ return field;
7185
+ }),
7186
+ typeOf,
7187
+ reference,
7188
+ exists
7189
+ };
7190
+ if (capturedWhere) {
7191
+ capturedWhere.full = `${capturedWhere.field}[*].${capturedWhere.subfield}=${capturedWhere.value}`;
7192
+ retVal.where = capturedWhere;
7193
+ }
7194
+ return retVal;
7195
+ });
7196
+ return {
7197
+ expressions,
7198
+ original_expressions
7199
+ };
7200
+ };
7201
+ _LoadSearchParameters = () => {
7202
+ for (const [key, val] of Object.entries(this.GetSearchParams())) {
7203
+ const { id, url, code, base, type, expression, component, target } = val;
7204
+ for (let i = 0; i < base.length; i++) {
7205
+ const resourceName = base[i];
7206
+ if (!this.#definitions?.searchParametersByResourceType[resourceName]) {
7207
+ this.#definitions.searchParametersByResourceType[resourceName] = {
7208
+ resourceName,
7209
+ params: []
7210
+ };
7211
+ }
7212
+ const SP_ID = id;
7213
+ const SP_NAME = code;
7214
+ const SP_TYPE = type;
7215
+ const SP_URL = url;
7216
+ const SP_TARGET = target;
7217
+ let SP_EXPRESSION = expression;
7218
+ let expressions = [];
7219
+ let original_expressions = [];
7220
+ if (SP_EXPRESSION) {
7221
+ const retVal = this.ProcessExpressions(resourceName, SP_EXPRESSION);
7222
+ expressions = retVal.expressions;
7223
+ original_expressions = retVal.original_expressions;
7224
+ }
7225
+ const record = {
7226
+ SP_ID,
7227
+ SP_NAME,
7228
+ SP_TYPE,
7229
+ SP_URL,
7230
+ SP_TARGET,
7231
+ expressions,
7232
+ original_expressions,
7233
+ SP_DEFINITION: this.GetSearchParam(SP_URL)
7234
+ };
7235
+ for (let i2 = 0; i2 < record.expressions.length; i2++) {
7236
+ const rf = this.GetResourceField(resourceName, record.expressions[i2].path);
7237
+ if (rf) {
7238
+ expressions[i2].RES_FIELD = rf;
7239
+ }
7240
+ }
7241
+ if (component) {
7242
+ record.component = [...component];
7243
+ record.component.forEach((c) => {
7244
+ const retVal = this.ProcessExpressions("", c.expression);
7245
+ c.expressions = retVal.expressions;
7246
+ c.original_expressions = retVal.original_expressions;
7247
+ const def = this.GetSearchParam(c.definition);
7248
+ if (def && def.type) {
7249
+ c.type = def.type;
7250
+ }
7251
+ });
7252
+ }
7253
+ this.#definitions.searchParametersByResourceType[resourceName].params.push(record);
7254
+ }
7255
+ }
7256
+ };
7257
+ GetSearchParamFromResourceTypeUrl = (resourceType, url) => {
7258
+ const filterByNameAndUrl = this.definitions.searchParametersByResourceType[resourceType].params.filter((rt) => rt.SP_URL.localeCompare(url) === 0);
7259
+ if (filterByNameAndUrl.length > 0) {
7260
+ return filterByNameAndUrl[0];
7261
+ }
7262
+ };
7263
+ /*
7264
+ GetSearchParamFromResourceType = (resourceType: string, name: string): ISearchParamRecord | undefined => {
7265
+ const filterByName = this.definitions.searchParametersByResourceType[resourceType].params.filter(rt => rt.SP_NAME.localeCompare(name) === 0);
7266
+ if (filterByName.length > 0) {
7267
+ return filterByName[0];
7268
+ }
7269
+ }
7270
+
7271
+ GetPathsFromResourceType = (resourceType: string, name: string): string[] => {
7272
+ const filterByName = this.definitions.searchParametersByResourceType[resourceType].params.filter(rt => rt.SP_NAME.localeCompare(name) === 0);
7273
+ if (filterByName.length > 0) {
7274
+ return filterByName[0].expressions.map(e => e.path)
7275
+ }
7276
+ return [ ];
7277
+ }
7278
+ */
7279
+ GetSearchParamsFromResourceType = (resourceType) => {
7280
+ return this.definitions.searchParametersByResourceType[resourceType].params;
7091
7281
  };
7092
7282
  }
7093
7283
  var ansiStyles = { exports: {} };
@@ -10565,7 +10755,7 @@ class DBSearchIndexComposite extends DBSearchIndexBase {
10565
10755
  searchFieldRecord.component.forEach((searchParamComponentRecord) => {
10566
10756
  components.push([]);
10567
10757
  const url = searchParamComponentRecord.definition;
10568
- const sp = searchIndex.GetSearchParamFromResourceTypeUrl(resource.resourceType, url);
10758
+ const sp = searchIndex.resourceHelper.GetSearchParamFromResourceTypeUrl(resource.resourceType, url);
10569
10759
  if (this.IsDefined(sp)) {
10570
10760
  const tir2 = {
10571
10761
  PID: v4(),
@@ -11220,27 +11410,13 @@ class DBSearchIndex {
11220
11410
  return [];
11221
11411
  }
11222
11412
  };
11223
- ResolveFhirChoiceType = (path) => {
11224
- const match2 = path.match(/^(.+?)\.ofType\((.+?)\)$/);
11225
- if (!match2) {
11226
- return path;
11227
- }
11228
- const base = match2[1];
11229
- const fhirType = match2[2];
11230
- const capitalizedType = fhirType.charAt(0).toUpperCase() + fhirType.slice(1);
11231
- return `${base}${capitalizedType}`;
11232
- };
11233
11413
  GetSearchIndexData = (resource) => {
11234
11414
  try {
11235
- const st = performance.now();
11236
- if (!this.#searchParams) {
11237
- this.LoadSearchParameters();
11238
- }
11415
+ const searchParamRecords = this.resourceHelper.GetSearchParamsFromResourceType(resource.resourceType);
11239
11416
  const searchIndexData = [];
11240
- for (let i = 0; i < this.#searchParams[resource.resourceType].params.length; i++) {
11241
- const searchRecord = this.#searchParams[resource.resourceType].params[i];
11417
+ for (let i = 0; i < searchParamRecords.length; i++) {
11418
+ const searchRecord = searchParamRecords[i];
11242
11419
  try {
11243
- const st2 = performance.now();
11244
11420
  const retVal = this.UpdateIndex(resource, searchRecord);
11245
11421
  if (retVal && retVal.length > 0) {
11246
11422
  searchIndexData.push(...retVal);
@@ -11255,286 +11431,19 @@ class DBSearchIndex {
11255
11431
  return [];
11256
11432
  }
11257
11433
  };
11258
- GetSearchParamFromResourceTypeUrl = (resourceType, url) => {
11259
- if (!this.#searchParams) {
11260
- this.LoadSearchParameters();
11261
- }
11262
- const filterByNameAndUrl = this.#searchParams[resourceType].params.filter((rt) => rt.SP_URL.localeCompare(url) === 0);
11263
- if (filterByNameAndUrl.length > 0) {
11264
- return filterByNameAndUrl[0];
11265
- }
11266
- };
11267
- GetSearchParamFromResourceType = (resourceType, name) => {
11268
- if (!this.#searchParams) {
11269
- this.LoadSearchParameters();
11270
- }
11271
- const filterByName = this.#searchParams[resourceType].params.filter((rt) => rt.SP_NAME.localeCompare(name) === 0);
11272
- if (filterByName.length > 0) {
11273
- return filterByName[0];
11274
- }
11275
- };
11276
- GetPathsFromResourceType = (resourceType, name) => {
11277
- if (!this.#searchParams) {
11278
- this.LoadSearchParameters();
11279
- }
11280
- const filterByName = this.#searchParams[resourceType].params.filter((rt) => rt.SP_NAME.localeCompare(name) === 0);
11281
- if (filterByName.length > 0) {
11282
- return filterByName[0].expressions.map((e) => e.path);
11283
- }
11284
- return [];
11285
- };
11286
- // Remove ( ) when either are present
11287
- #RemoveOuterParentheses = (input) => {
11288
- return input.replace(/^\(|\)$/g, "");
11289
- };
11290
- // Remove ( ) only when both are present
11291
- #RemoveSurroundingParentheses = (input) => {
11292
- return input.replace(/^\((.*)\)$/, "$1").trim();
11293
- };
11294
11434
  /*
11295
-
11296
- NamingSystem derived-from reference NamingSystem.relatedArtifact.where(type='derived-from').resource
11297
-
11298
- NamingSystem predecessor reference NamingSystem.relatedArtifact.where(type='predecessor').resource
11299
-
11300
- ClinicalUseDefinition product reference ClinicalUseDefinition.subject.where(resolve() is MedicinalProductDefinition)
11301
-
11302
- OrganizationAffiliation email token OrganizationAffiliation.contact.telecom.where(system='email')
11303
- OrganizationAffiliation phone token OrganizationAffiliation.contact.telecom.where(system='phone')
11304
-
11305
- PackagedProductDefinition biological reference PackagedProductDefinition.packaging.containedItem.item.reference
11306
- PackagedProductDefinition contained-item reference PackagedProductDefinition.packaging.containedItem.item.reference
11307
-
11308
- Patient deceased token Patient.deceased.exists() and Patient.deceased != false
11309
- Practitioner deceased token Practitioner.deceased.exists() and Practitioner.deceased != false
11310
-
11311
- Location contains special Location.extension('http://hl7.org/fhir/StructureDefinition/location-boundary-geojson').value
11312
-
11313
- QuestionnaireResponse item-subject reference QuestionnaireResponse.item.where(extension('http://hl7.org/fhir/StructureDefinition/questionnaireresponse-isSubject').exists()).answer.valueReference
11314
- */
11315
- ProcessExpressions = (resourceName, SP_EXPRESSION) => {
11316
- let expressions = [];
11317
- expressions = SP_EXPRESSION.split("|").map((e) => e.trim());
11318
- expressions = expressions.map((e) => this.#RemoveSurroundingParentheses(e).trim());
11319
- if (resourceName !== "") {
11320
- expressions = expressions.filter((e) => e.split(".")[0].trim().localeCompare(resourceName) === 0);
11321
- }
11322
- let original_expressions = [...expressions];
11323
- expressions = expressions.map((e) => {
11324
- let capturedTypeOf = void 0;
11325
- return {
11326
- path: e.replace(
11327
- /\.ofType\(([^)]+)\)/g,
11328
- (_, typeName) => {
11329
- capturedTypeOf = true;
11330
- return typeName.charAt(0).toUpperCase() + typeName.slice(1);
11331
- }
11332
- ),
11333
- typeOf: capturedTypeOf
11334
- };
11335
- });
11336
- expressions.forEach((expression) => {
11337
- try {
11338
- const sp = expression;
11339
- if (sp.path.indexOf("exists()") >= 0) {
11340
- const parts = sp.path.split(" ");
11341
- const i = parts[0].indexOf("exists()");
11342
- if (i >= 0) {
11343
- let fieldExistsEx = parts[0].substring(0, i - 1);
11344
- let op = parts[1];
11345
- let fieldTestEx = parts[2];
11346
- let comparator = parts[3];
11347
- let value = parts[4];
11348
- const fieldExistsParts = fieldExistsEx.split(".");
11349
- let fieldExists = fieldExistsParts.slice(1).join(".");
11350
- const fieldTestParts = fieldTestEx.split(".");
11351
- let fieldTest = fieldTestParts.slice(1).join(".");
11352
- sp.exists = {
11353
- fieldExists: [`${fieldExists}Boolean`, `${fieldExists}DataTime`],
11354
- // [x]Boolean or [x]DateTime
11355
- op,
11356
- fieldTest: [`${fieldTest}Boolean`, `${fieldTest}DataTime`],
11357
- comparator,
11358
- value: [value, void 0]
11359
- };
11360
- }
11361
- }
11362
- } catch (error) {
11435
+ GetSearchParamFromResourceTypeUrl = (resourceType: string, url: string): ISearchParamRecord | undefined => {
11436
+ return this.resourceHelper.GetSearchParamFromResourceTypeUrl(resourceType, url);
11363
11437
  }
11364
- });
11365
- let capturedType;
11366
- expressions = expressions.map((obj) => {
11367
- capturedType = void 0;
11368
- const { path, typeOf, exists } = obj;
11369
- return {
11370
- path: path.replace(
11371
- /\.where\(resolve\(\)\s+is\s+([^)]+)\)/,
11372
- (_, typeName) => {
11373
- capturedType = typeName;
11374
- return "";
11375
- }
11376
- ),
11377
- typeOf,
11378
- reference: capturedType,
11379
- exists
11380
- };
11381
- });
11382
- let capturedWhere = void 0;
11383
- expressions = expressions.map((obj) => {
11384
- capturedWhere = void 0;
11385
- const { path, reference, typeOf, exists } = obj;
11386
- const retVal = {
11387
- path: path.replace(/([^.]+)\.where\(([^=]+)='([^']+)'\)/g, (_, field, subfield, value) => {
11388
- capturedWhere = { field, subfield, value };
11389
- return field;
11390
- }),
11391
- typeOf,
11392
- reference,
11393
- exists
11394
- };
11395
- if (capturedWhere) {
11396
- capturedWhere.full = `${capturedWhere.field}[*].${capturedWhere.subfield}=${capturedWhere.value}`;
11397
- retVal.where = capturedWhere;
11398
- }
11399
- return retVal;
11400
- });
11401
- return {
11402
- expressions,
11403
- original_expressions
11404
- };
11405
- };
11406
- LoadSearchParameters = () => {
11407
- const searchParamData = {};
11408
- for (const [key, val] of Object.entries(this.resourceHelper.GetSearchParams())) {
11409
- const { id, url, code, base, type, expression, component, target } = val;
11410
- for (let i = 0; i < base.length; i++) {
11411
- const resourceName = base[i];
11412
- if (!searchParamData[resourceName]) {
11413
- searchParamData[resourceName] = {
11414
- resourceName,
11415
- params: []
11416
- };
11417
- }
11418
- const SP_ID = id;
11419
- const SP_NAME = code;
11420
- const SP_TYPE = type;
11421
- const SP_URL = url;
11422
- const SP_TARGET = target;
11423
- let SP_EXPRESSION = expression;
11424
- let expressions = [];
11425
- let original_expressions = [];
11426
- if (SP_EXPRESSION) {
11427
- const retVal = this.ProcessExpressions(resourceName, SP_EXPRESSION);
11428
- expressions = retVal.expressions;
11429
- original_expressions = retVal.original_expressions;
11430
- }
11431
- const record = {
11432
- SP_ID,
11433
- SP_NAME,
11434
- SP_TYPE,
11435
- SP_URL,
11436
- SP_TARGET,
11437
- expressions,
11438
- original_expressions,
11439
- SP_DEFINITION: this.resourceHelper.GetSearchParam(SP_URL)
11440
- };
11441
- for (let i2 = 0; i2 < record.expressions.length; i2++) {
11442
- const rf = this.resourceHelper.GetResourceField(resourceName, record.expressions[i2].path);
11443
- if (rf) {
11444
- expressions[i2].RES_FIELD = rf;
11445
- }
11446
- }
11447
- if (component) {
11448
- record.component = [...component];
11449
- record.component.forEach((c) => {
11450
- const retVal = this.ProcessExpressions("", c.expression);
11451
- c.expressions = retVal.expressions;
11452
- c.original_expressions = retVal.original_expressions;
11453
- const def = this.resourceHelper.GetSearchParam(c.definition);
11454
- if (def && def.type) {
11455
- c.type = def.type;
11456
- }
11457
- });
11458
- }
11459
- searchParamData[resourceName].params.push(record);
11460
- }
11461
- }
11462
- this.#searchParams = searchParamData;
11463
- return searchParamData;
11464
- };
11465
- /*
11466
-
11467
-
11468
- for (const [resourceName,val] of Object.entries(searchParams)) {
11469
-
11470
- const patientSearchList: Record<string, any> = (val as any).resourceSpecific;
11471
-
11472
- for (const [key2,val2] of Object.entries(patientSearchList)) {
11473
-
11474
- const SP_ID = val2.id;
11475
- const SP_NAME = key2;
11476
- const SP_TYPE = val2.type;
11477
- const SP_URL = val2.url;
11478
- let SP_EXPRESSION: string = val2.expression;
11479
- let expressions: any[] = [];
11480
- let original_expressions: any[] = [];
11481
- if (SP_EXPRESSION) {
11482
- const retVal = this.ProcessExpressions(resourceName, SP_EXPRESSION);
11483
- expressions = retVal.expressions;
11484
- original_expressions = retVal.original_expressions;
11485
- }
11486
11438
 
11487
- if (!searchParamData[resourceName]) {
11488
- searchParamData[resourceName] = {
11489
- resourceName,
11490
- params: [ ]
11491
- }
11492
- }
11493
-
11494
- // GetResourceField
11495
-
11496
- const record: ISearchParamRecord = {
11497
- SP_ID,
11498
- SP_NAME,
11499
- SP_TYPE,
11500
- SP_URL,
11501
- expressions,
11502
- original_expressions,
11503
- SP_DEFINITION: this.resourceHelper.GetSearchParam(SP_URL)
11504
- };
11505
-
11506
- for (let i=0; i < record.expressions.length; i++) {
11507
- //console.log(record.expressions[i]);
11508
- const rf = this.resourceHelper.GetResourceField(resourceName, record.expressions[i].path);
11509
- if (rf) {
11510
- expressions[i].RES_FIELD = rf;
11511
- }
11512
- }
11513
-
11514
- if (val2.component) {
11515
- record.component = [ ...val2.component ];
11516
- (record.component as any[]).forEach(c => {
11517
- //c.SP_RAW_PATHS = (c.expression.split('|') as any[]).map(rp => rp.trim());
11518
- //c.SP_PATHS = (c.SP_RAW_PATHS as any[]).map(rawPath => this.ResolveFhirChoiceType(rawPath));
11519
- const retVal = this.ProcessExpressions('', c.expression);
11520
- c.expressions = retVal.expressions;
11521
- c.original_expressions = retVal.original_expressions;
11522
- const def = this.resourceHelper.GetSearchParam(c.definition);
11523
- if (def && def.type) {
11524
- c.type = def.type
11525
- }
11526
- })
11527
- }
11528
-
11529
- searchParamData[resourceName].params.push(record);
11530
- }
11531
- }
11532
-
11533
- this.#searchParams = searchParamData;
11439
+ GetSearchParamFromResourceType = (resourceType: string, name: string): ISearchParamRecord | undefined => {
11440
+ return this.resourceHelper.GetSearchParamFromResourceType(resourceType, name);
11441
+ }
11534
11442
 
11535
- return searchParamData;
11443
+ GetPathsFromResourceType = (resourceType: string, name: string): string[] => {
11444
+ return this.resourceHelper.GetPathsFromResourceType(resourceType, name);
11536
11445
  }
11537
- */
11446
+ */
11538
11447
  }
11539
11448
  var lib$1 = { exports: {} };
11540
11449
  var defaults = { exports: {} };
@@ -18943,230 +18852,11 @@ class PGFhirAccessLayer extends tinyEmitterExports.TinyEmitter {
18943
18852
  }
18944
18853
  };
18945
18854
  }
18946
- const RELEASE_SCRIPT = `
18947
- if redis.call("get", KEYS[1]) == ARGV[1] then
18948
- return redis.call("del", KEYS[1])
18949
- else
18950
- return 0
18951
- end
18952
- `;
18953
- const RENEW_SCRIPT = `
18954
- if redis.call("get", KEYS[1]) == ARGV[1] then
18955
- return redis.call("pexpire", KEYS[1], ARGV[2])
18956
- else
18957
- return 0
18958
- end
18959
- `;
18960
- class RedisDistributedLock {
18961
- client;
18962
- ttlMs;
18963
- heartbeatMs;
18964
- keyPrefix;
18965
- constructor(client2, options) {
18966
- this.client = client2;
18967
- this.ttlMs = options?.ttlMs ?? 3e4;
18968
- this.heartbeatMs = options?.heartbeatMs ?? Math.floor(this.ttlMs / 3);
18969
- this.keyPrefix = options?.keyPrefix ?? "lock:";
18970
- if (this.ttlMs <= 0) {
18971
- throw new Error("ttlMs must be > 0");
18972
- }
18973
- if (this.heartbeatMs <= 0) {
18974
- throw new Error("heartbeatMs must be > 0");
18975
- }
18976
- if (this.heartbeatMs >= this.ttlMs) {
18977
- throw new Error("heartbeatMs should be less than ttlMs");
18978
- }
18979
- }
18980
- buildKey(name) {
18981
- return `${this.keyPrefix}${name}`;
18982
- }
18983
- async acquire(name, ttlMs) {
18984
- const key = this.buildKey(name);
18985
- const token = randomUUID$1();
18986
- const effectiveTtlMs = ttlMs ?? this.ttlMs;
18987
- const result2 = await this.client.set(key, token, {
18988
- NX: true,
18989
- PX: effectiveTtlMs
18990
- });
18991
- if (result2 !== "OK") {
18992
- return null;
18993
- }
18994
- return {
18995
- key,
18996
- token,
18997
- ttlMs: effectiveTtlMs
18998
- };
18999
- }
19000
- async release(lock) {
19001
- const result2 = await this.client.eval(RELEASE_SCRIPT, {
19002
- keys: [lock.key],
19003
- arguments: [lock.token]
19004
- });
19005
- return Number(result2) === 1;
19006
- }
19007
- async renew(lock, ttlMs) {
19008
- const effectiveTtlMs = ttlMs ?? lock.ttlMs;
19009
- const result2 = await this.client.eval(RENEW_SCRIPT, {
19010
- keys: [lock.key],
19011
- arguments: [lock.token, String(effectiveTtlMs)]
19012
- });
19013
- return Number(result2) === 1;
19014
- }
19015
- async isOwner(lock) {
19016
- const currentValue = await this.client.get(lock.key);
19017
- return currentValue === lock.token;
19018
- }
19019
- async runExclusive(name, task, options) {
19020
- const lock = await this.acquire(name, options?.ttlMs);
19021
- if (!lock) {
19022
- if (options?.onLockNotAcquired) {
19023
- await options.onLockNotAcquired();
19024
- }
19025
- return { acquired: false };
19026
- }
19027
- let timer = null;
19028
- let stopped = false;
19029
- let renewalError = null;
19030
- const autoRenew = options?.autoRenew ?? false;
19031
- const heartbeatMs = options?.heartbeatMs ?? this.heartbeatMs;
19032
- const stopHeartbeat = () => {
19033
- stopped = true;
19034
- if (timer) {
19035
- clearInterval(timer);
19036
- timer = null;
19037
- }
19038
- };
19039
- if (autoRenew) {
19040
- timer = setInterval(async () => {
19041
- if (stopped) {
19042
- return;
19043
- }
19044
- try {
19045
- const ok = await this.renew(lock, lock.ttlMs);
19046
- if (!ok) {
19047
- renewalError = new Error(
19048
- `Lost lock ownership while renewing "${lock.key}"`
19049
- );
19050
- stopHeartbeat();
19051
- }
19052
- } catch (err) {
19053
- renewalError = err instanceof Error ? err : new Error(String(err));
19054
- stopHeartbeat();
19055
- }
19056
- }, heartbeatMs).unref();
19057
- }
19058
- try {
19059
- const result2 = await task();
19060
- if (renewalError) {
19061
- throw renewalError;
19062
- }
19063
- return { acquired: true, result: result2 };
19064
- } finally {
19065
- stopHeartbeat();
19066
- try {
19067
- await this.release(lock);
19068
- } catch {
19069
- }
19070
- }
19071
- }
19072
- }
19073
- class SearchParameterManager {
19074
- redis;
19075
- EnsureSearchParameterDataLoaded = async (name, loadFn, options) => {
19076
- if (!this.redis) {
19077
- const redisUrl = goptions.imRedisMessageProcessorUrl;
19078
- console.log(`SearchParameterManager(): redis trying to connect ...`);
19079
- this.redis = createClient({
19080
- url: redisUrl
19081
- });
19082
- await this.redis.connect();
19083
- console.log(`SearchParameterManager(): redis connected`);
19084
- }
19085
- try {
19086
- const pollIntervalMs = options?.pollIntervalMs ?? 250;
19087
- const lockTtlMs = options?.lockTtlMs ?? 3e4;
19088
- const autoRenew = options?.autoRenew ?? true;
19089
- const heartbeatMs = options?.heartbeatMs ?? 1e4;
19090
- const completeTtlSeconds = options?.completeTtlSeconds;
19091
- const timeoutMs = options?.timeoutMs;
19092
- const completeKey = `fhir:searchparam:${name}:complete`;
19093
- const startedAt = Date.now();
19094
- const lockManager = new RedisDistributedLock(this.redis, {
19095
- ttlMs: 3e4,
19096
- heartbeatMs: 1e4,
19097
- keyPrefix: "lock:"
19098
- });
19099
- while (true) {
19100
- if (typeof timeoutMs === "number" && timeoutMs > 0) {
19101
- const elapsedMs = Date.now() - startedAt;
19102
- if (elapsedMs >= timeoutMs) {
19103
- throw new Error(
19104
- `Timed out waiting for search param "${name}" to be loaded`
19105
- );
19106
- }
19107
- }
19108
- try {
19109
- const alreadyComplete = await this.redis.get(completeKey);
19110
- if (alreadyComplete) {
19111
- console.log(`ensureSearchParamLoaded():alreadyComplete: PID: [${process.pid}] data loaded: [${alreadyComplete}]`);
19112
- return;
19113
- }
19114
- } catch (error) {
19115
- console.error(error);
19116
- throw error;
19117
- }
19118
- const runResult = await lockManager.runExclusive(
19119
- `fhir:searchparam:${name}`,
19120
- async () => {
19121
- console.log(`ensureSearchParamLoaded(): PID: [${process.pid}] lock acquired`);
19122
- const completeAfterLock = await this.redis.get(completeKey);
19123
- if (completeAfterLock) {
19124
- console.log(`ensureSearchParamLoaded():completeAfterLock: PID: [${process.pid}] data loaded: [${completeAfterLock}]`);
19125
- return;
19126
- }
19127
- await loadFn();
19128
- const completeValue = JSON.stringify({
19129
- loaded: true,
19130
- loadedAt: (/* @__PURE__ */ new Date()).toLocaleString(),
19131
- name,
19132
- workerPid: process.pid
19133
- });
19134
- console.log(`ensureSearchParamLoaded(): PID: [${process.pid}] data loaded: [${completeValue}]`);
19135
- if (typeof completeTtlSeconds === "number" && completeTtlSeconds > 0) {
19136
- await this.redis.set(completeKey, completeValue, {
19137
- EX: completeTtlSeconds
19138
- });
19139
- } else {
19140
- await this.redis.set(completeKey, completeValue);
19141
- }
19142
- },
19143
- {
19144
- ttlMs: lockTtlMs,
19145
- autoRenew,
19146
- heartbeatMs
19147
- }
19148
- );
19149
- if (runResult.acquired) {
19150
- return;
19151
- }
19152
- console.log(`ensureSearchParamLoaded(): PID: [${process.pid}] Did not get lock`);
19153
- await Sleep(pollIntervalMs);
19154
- }
19155
- } finally {
19156
- if (this.redis) {
19157
- this.redis.close();
19158
- console.log(`SearchParameterManager(): redis closed`);
19159
- }
19160
- }
19161
- };
19162
- }
19163
18855
  export {
19164
18856
  DBSearchIndex,
19165
18857
  FHIRDateUtils,
19166
18858
  PGFhirAccessLayer,
19167
- RedisDistributedLock,
19168
18859
  ResourceHelper,
19169
- SearchParameterManager,
19170
18860
  hashReferenceParam,
19171
18861
  hashStringParam,
19172
18862
  hashTokenParam,