@nsshunt/stsfhirpg 1.2.13 → 1.2.14

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.
@@ -7127,6 +7127,7 @@ class SearchParameterManager {
7127
7127
  redis;
7128
7128
  alreadyComplete = null;
7129
7129
  options;
7130
+ cache = {};
7130
7131
  constructor(options) {
7131
7132
  this.options = options;
7132
7133
  }
@@ -7234,451 +7235,62 @@ class SearchParameterManager {
7234
7235
  console.log(`SearchParameterManager(): redis closed`);
7235
7236
  }
7236
7237
  };
7237
- /*
7238
- private GetTypeKey(typeName: string) {
7239
- return `stsfhir_type_${typeName}`;
7240
- }
7241
-
7242
- private GetSearchParameterByFullUrlKey(fullUrl: string) {
7243
- return `stsfhir_sp_${fullUrl}`;
7244
- }
7245
-
7246
- private GetResourceKey(resourceType: string) {
7247
- return `stsfhir_resource_${resourceType}`;
7248
- }
7249
-
7250
- private GetSearchParameterByResourceTypeKey(resourceType: string) {
7251
- return `stsfhir_sp_resource_${resourceType}`;
7252
- }
7253
-
7254
- private GetSTSCustomSearchParameterByResourceTypeKey(resourceType: string) {
7255
- return `stsfhir_stscustom_sp_resource_${resourceType}`;
7256
- }
7257
- */
7238
+ #searchParametersByResourceTypeKey = `__stsfhir__searchParametersByResourceType`;
7239
+ #searchParametersByUrlKey = `__stsfhir__searchParametersByUrl`;
7240
+ #resourcesKey = `__stsfhir__resources`;
7241
+ #typesKey = `__stsfhir__types`;
7258
7242
  #LoadDefinitions = async (resources) => {
7259
7243
  console.log("Data Load Starting ...");
7260
7244
  for (const [key, value] of Object.entries(resources.searchParametersByResourceType)) {
7261
- await this.redis.hSet(`__stsfhir__searchParametersByResourceType`, key, JSON.stringify(value));
7245
+ await this.redis.hSet(this.#searchParametersByResourceTypeKey, key, JSON.stringify(value));
7262
7246
  }
7263
7247
  for (const [key, value] of Object.entries(resources.searchParametersByUrl)) {
7264
- await this.redis.hSet(`__stsfhir__searchParametersByUrl`, key, JSON.stringify(value));
7248
+ await this.redis.hSet(this.#searchParametersByUrlKey, key, JSON.stringify(value));
7265
7249
  }
7266
7250
  for (const [key, value] of Object.entries(resources.resources)) {
7267
- await this.redis.hSet(`__stsfhir__resources`, key, JSON.stringify(value));
7251
+ await this.redis.hSet(this.#resourcesKey, key, JSON.stringify(value));
7268
7252
  }
7269
7253
  for (const [key, value] of Object.entries(resources.types)) {
7270
- await this.redis.hSet(`__stsfhir__types`, key, JSON.stringify(value));
7254
+ await this.redis.hSet(this.#typesKey, key, JSON.stringify(value));
7271
7255
  }
7272
7256
  console.log("All Done ***********************************************************************************");
7273
7257
  };
7274
7258
  GetSearchParamFromResourceType = async (resourceType) => {
7275
- const retVal = await this.redis.hGet(`__stsfhir__searchParametersByResourceType`, resourceType);
7276
- return JSON.parse(retVal);
7259
+ const key = `${this.#searchParametersByResourceTypeKey}_${resourceType}`;
7260
+ if (this.cache[key]) {
7261
+ return this.cache[key];
7262
+ }
7263
+ const retVal = await this.redis.hGet(this.#searchParametersByResourceTypeKey, resourceType);
7264
+ this.cache[key] = JSON.parse(retVal);
7265
+ return this.cache[key];
7277
7266
  };
7278
7267
  GetType = async (typeName) => {
7279
- const retVal = await this.redis.hGet(`__stsfhir__types`, typeName);
7280
- return JSON.parse(retVal);
7268
+ const key = `${this.#typesKey}_${typeName}`;
7269
+ if (this.cache[key]) {
7270
+ return this.cache[key];
7271
+ }
7272
+ const retVal = await this.redis.hGet(this.#typesKey, typeName);
7273
+ this.cache[key] = JSON.parse(retVal);
7274
+ return this.cache[key];
7281
7275
  };
7282
7276
  GetResource = async (resourceType) => {
7283
- const retVal = await this.redis.hGet(`__stsfhir__resources`, resourceType);
7284
- return JSON.parse(retVal);
7277
+ const key = `${this.#resourcesKey}_${resourceType}`;
7278
+ if (this.cache[key]) {
7279
+ return this.cache[key];
7280
+ }
7281
+ const retVal = await this.redis.hGet(this.#resourcesKey, resourceType);
7282
+ this.cache[key] = JSON.parse(retVal);
7283
+ return this.cache[key];
7285
7284
  };
7286
7285
  GetSearchParam = async (url) => {
7287
- const retVal = await this.redis.hGet(`__stsfhir__searchParametersByUrl`, url);
7288
- return JSON.parse(retVal);
7286
+ const key = `${this.#searchParametersByUrlKey}_${url}`;
7287
+ if (this.cache[key]) {
7288
+ return this.cache[key];
7289
+ }
7290
+ const retVal = await this.redis.hGet(this.#searchParametersByUrlKey, url);
7291
+ this.cache[key] = JSON.parse(retVal);
7292
+ return this.cache[key];
7289
7293
  };
7290
- /*
7291
- GetSearchParams = async (): Promise<SearchParameter[]> => {
7292
- const retVal = await this.redis!.hGetAll(`__stsfhir__searchParametersByUrl`);
7293
- const searchParameters: SearchParameter[] = [ ];
7294
- for (const [key, value] of Object.entries(retVal)) {
7295
- searchParameters.push(JSON.parse(value));
7296
- }
7297
- return searchParameters;
7298
- }
7299
- */
7300
- /*
7301
- private GetTypeKey(typeName: string) {
7302
- return `stsfhir_type_${typeName}`;
7303
- }
7304
-
7305
- private GetSearchParameterByFullUrlKey(fullUrl: string) {
7306
- return `stsfhir_sp_${fullUrl}`;
7307
- }
7308
-
7309
- private GetResourceKey(resourceType: string) {
7310
- return `stsfhir_resource_${resourceType}`;
7311
- }
7312
-
7313
- private GetSearchParameterByResourceTypeKey(resourceType: string) {
7314
- return `stsfhir_sp_resource_${resourceType}`;
7315
- }
7316
-
7317
- private GetSTSCustomSearchParameterByResourceTypeKey(resourceType: string) {
7318
- return `stsfhir_stscustom_sp_resource_${resourceType}`;
7319
- }
7320
-
7321
- // Remove ( ) when either are present
7322
- private _RemoveOuterParentheses = (input: string): string => {
7323
- return input.replace(/^\(|\)$/g, '');
7324
- }
7325
-
7326
- // Remove ( ) only when both are present
7327
- private _RemoveSurroundingParentheses = (input: string): string => {
7328
- return input.replace(/^\((.*)\)$/, '$1').trim();
7329
- }
7330
- */
7331
- /*
7332
- NamingSystem derived-from reference NamingSystem.relatedArtifact.where(type='derived-from').resource
7333
-
7334
- NamingSystem predecessor reference NamingSystem.relatedArtifact.where(type='predecessor').resource
7335
-
7336
- ClinicalUseDefinition product reference ClinicalUseDefinition.subject.where(resolve() is MedicinalProductDefinition)
7337
-
7338
- OrganizationAffiliation email token OrganizationAffiliation.contact.telecom.where(system='email')
7339
- OrganizationAffiliation phone token OrganizationAffiliation.contact.telecom.where(system='phone')
7340
-
7341
- PackagedProductDefinition biological reference PackagedProductDefinition.packaging.containedItem.item.reference
7342
- PackagedProductDefinition contained-item reference PackagedProductDefinition.packaging.containedItem.item.reference
7343
-
7344
- Patient deceased token Patient.deceased.exists() and Patient.deceased != false
7345
- Practitioner deceased token Practitioner.deceased.exists() and Practitioner.deceased != false
7346
-
7347
- Location contains special Location.extension('http://hl7.org/fhir/StructureDefinition/location-boundary-geojson').value
7348
-
7349
- QuestionnaireResponse item-subject reference QuestionnaireResponse.item.where(extension('http://hl7.org/fhir/StructureDefinition/questionnaireresponse-isSubject').exists()).answer.valueReference
7350
- */
7351
- /*
7352
- private _ProcessExpressions = (resourceName: string, SP_EXPRESSION: string): any => {
7353
- let expressions: any[] = [];
7354
-
7355
- //SP_EXPRESSION = this.#RemoveSurroundingParentheses(val2.expression);
7356
- expressions = SP_EXPRESSION.split('|').map(e => e.trim());
7357
-
7358
- expressions = expressions.map(e => this._RemoveSurroundingParentheses(e).trim());
7359
-
7360
- if (resourceName !== '') {
7361
- expressions = expressions.filter(e => e.split('.')[0].trim().localeCompare(resourceName) === 0);
7362
- }
7363
-
7364
- let original_expressions = [ ...expressions ];
7365
-
7366
- // ofType processing
7367
- expressions = expressions.map((e: string) => {
7368
- let capturedTypeOf = undefined;
7369
- return {
7370
- path: e.replace(
7371
- /\.ofType\(([^)]+)\)/g,
7372
- (_: string, typeName: string) => {
7373
- capturedTypeOf = true;
7374
- return typeName.charAt(0).toUpperCase() + typeName.slice(1)
7375
- }),
7376
- typeOf: capturedTypeOf
7377
- }
7378
- });
7379
-
7380
- //@@ exists processing here is more or less hard coded to the deceased attribute.
7381
- //@@ in future, we need an actual fhir language parser.
7382
- expressions.forEach(expression => {
7383
- try {
7384
- const sp = expression as ISearchParamExpressionRecord;
7385
- if (sp.path.indexOf('exists()') >= 0) {
7386
- // Person.deceased.exists() and Person.deceased != false
7387
- const parts = sp.path.split(' ');
7388
- const i = parts[0].indexOf('exists()');
7389
- if (i >= 0) {
7390
- let fieldExistsEx = parts[0].substring(0, i-1);
7391
- let op = parts[1];
7392
- let fieldTestEx = parts[2];
7393
- let comparator = parts[3];
7394
- let value = parts[4];
7395
-
7396
- const fieldExistsParts = fieldExistsEx.split('.');
7397
- let fieldExists = fieldExistsParts.slice(1).join('.');
7398
-
7399
- const fieldTestParts = fieldTestEx.split('.');
7400
- let fieldTest = fieldTestParts.slice(1).join('.');
7401
-
7402
- sp.exists = {
7403
- fieldExists: [ `${fieldExists}Boolean`, `${fieldExists}DataTime` ], // [x]Boolean or [x]DateTime
7404
- op,
7405
- fieldTest: [ `${fieldTest}Boolean`, `${fieldTest}DataTime` ],
7406
- comparator,
7407
- value: [ value, undefined ]
7408
- }
7409
- }
7410
- }
7411
- } catch (error) {
7412
-
7413
- }
7414
- });
7415
-
7416
- // where(resolve()) processing
7417
- let capturedType: string | undefined;
7418
- expressions = expressions.map((obj: any) => {
7419
- capturedType = undefined;
7420
- const { path, typeOf, exists } = obj;
7421
- return {
7422
- path: path.replace(
7423
- /\.where\(resolve\(\)\s+is\s+([^)]+)\)/,
7424
- (_: string, typeName: string) => {
7425
- capturedType = typeName;
7426
- //return ` // reference = ${capturedType}`; // remove the .where(...) part (you can put ` // ${capturedType}` if you want to keep a comment)
7427
- return '';
7428
- }),
7429
- typeOf,
7430
- reference: capturedType,
7431
- exists
7432
- }
7433
- });
7434
-
7435
- // .where processing
7436
- // The element before the .where will be an array. So this test checks which element(s) from that array are satisifed.
7437
- let capturedWhere: any = undefined;
7438
- expressions = expressions.map((obj: any) => {
7439
- capturedWhere = undefined;
7440
- const { path, reference, typeOf, exists } = obj;
7441
- const retVal: any = {
7442
- path: path.replace(/([^.]+)\.where\(([^=]+)='([^']+)'\)/g, (_: string, field: string, subfield: string, value: string) => {
7443
- capturedWhere = { field, subfield, value }
7444
- return field;
7445
- }),
7446
- typeOf,
7447
- reference,
7448
- exists
7449
- }
7450
- if (capturedWhere) {
7451
- capturedWhere.full = `${capturedWhere.field}[*].${capturedWhere.subfield}=${capturedWhere.value}`;
7452
- retVal.where = capturedWhere;
7453
- }
7454
- return retVal;
7455
- });
7456
-
7457
-
7458
- return {
7459
- expressions,
7460
- original_expressions
7461
- };
7462
- }
7463
-
7464
- #LoadDefinitions = async (): Promise<void> => {
7465
- try {
7466
- let usePath = '';
7467
- if (fs.existsSync(`${specPath1}${resourcesPath}`)) {
7468
- usePath = specPath1;
7469
- } else {
7470
- usePath = specPath2;
7471
- }
7472
- const __resources: any = JSON.parse(fs.readFileSync(`${usePath}${resourcesPath}`, 'utf-8'));
7473
- const __types: any = JSON.parse(fs.readFileSync(`${usePath}${typesPath}`, 'utf-8'));
7474
- const __searchParams: any = JSON.parse(fs.readFileSync(`${usePath}${searchParamsPath}`, 'utf-8'));
7475
-
7476
- for (let i=0; i < (__resources.entry as any[]).length; i++) {
7477
- const entry = __resources.entry[i];
7478
- const resource: any = entry.resource;
7479
- if (resource?.snapshot?.element) {
7480
- const rt = resource.type as string;
7481
- await this.redis!.set(this.GetResourceKey(rt), JSON.stringify(resource.snapshot.element));
7482
- }
7483
- };
7484
-
7485
- for (let i=0; i < (__types.entry as any[]).length; i++) {
7486
- const entry = __types.entry[i];
7487
- const type = entry.resource;
7488
- if (type?.snapshot?.element) {
7489
- await this.redis!.set(this.GetTypeKey(type.type), JSON.stringify(type.snapshot.element));
7490
- }
7491
- };
7492
-
7493
- for (let i=0; i < (__searchParams.entry as any[]).length; i++) {
7494
- const entry = __searchParams.entry[i];
7495
- await this.redis!.set(this.GetSearchParameterByFullUrlKey(entry.fullUrl), JSON.stringify(entry.resource));
7496
- const { code, base } = entry.resource;
7497
- if (base) {
7498
- for (let j=0; j < base.length; j++) {
7499
- const resourceType = base[j];
7500
- await this.redis!.hSet(this.GetSearchParameterByResourceTypeKey(resourceType), code, JSON.stringify(entry.resource));
7501
- }
7502
- }
7503
- };
7504
-
7505
- //await this.#LoadDefinitionsPass2(__searchParams);
7506
-
7507
- console.log(`All completed ...`);
7508
- } catch (error) {
7509
- console.error(error);
7510
- throw error;
7511
- }
7512
- }
7513
- */
7514
- /*
7515
- #LoadDefinitionsPass2 = async (__searchParams: any): Promise<void> => {
7516
- try {
7517
- for (let i=0; i < (__searchParams.entry as any[]).length; i++) {
7518
-
7519
- console.log(`Processing (i) entry: [${i}]`);
7520
-
7521
- if (i === 47 ) {
7522
- console.log(`here...`)
7523
- }
7524
-
7525
- const entry = __searchParams.entry[i];
7526
-
7527
- const { id, url, code, base, type, expression, component, target } = entry.resource;
7528
-
7529
- if (base) {
7530
- for (let j=0; j < base.length; j++) {
7531
- const resourceType = base[j];
7532
- const SP_ID = id;
7533
- const SP_NAME = code; // code is the true SP name (but in the spec, name is usually the same as code)
7534
- const SP_TYPE = type;
7535
- const SP_URL = url;
7536
- const SP_TARGET = target;
7537
- let SP_EXPRESSION: string = expression;
7538
- let expressions: any[] = [];
7539
- let original_expressions: any[] = [];
7540
- if (SP_EXPRESSION) {
7541
- const retVal = this._ProcessExpressions(code, SP_EXPRESSION);
7542
- expressions = retVal.expressions;
7543
- original_expressions = retVal.original_expressions;
7544
- }
7545
-
7546
- const record: ISearchParamRecord = {
7547
- SP_ID,
7548
- SP_NAME,
7549
- SP_TYPE,
7550
- SP_URL,
7551
- SP_TARGET,
7552
- expressions,
7553
- original_expressions,
7554
- SP_DEFINITION: entry.resource // this.resourceHelper.GetSearchParam(SP_URL)
7555
- };
7556
-
7557
- for (let i=0; i < record.expressions.length; i++) {
7558
- //console.log(record.expressions[i]);
7559
- const rf = await this.GetResourceField(resourceType, record.expressions[i].path);
7560
- if (rf) {
7561
- expressions[i].RES_FIELD = rf;
7562
- }
7563
- }
7564
-
7565
- if (component) {
7566
- record.component = [ ...component ];
7567
- for (let k=0; k < record.component.length; k++) {
7568
- const c = record.component[k] as any;
7569
- //c.SP_RAW_PATHS = (c.expression.split('|') as any[]).map(rp => rp.trim());
7570
- //c.SP_PATHS = (c.SP_RAW_PATHS as any[]).map(rawPath => this.ResolveFhirChoiceType(rawPath));
7571
- const retVal = this._ProcessExpressions('', c.expression);
7572
- c.expressions = retVal.expressions;
7573
- c.original_expressions = retVal.original_expressions;
7574
-
7575
- let def = null;
7576
- const foundSearchParameter = await this.redis!.get(this.GetSearchParameterByFullUrlKey(c.definition));
7577
- if (foundSearchParameter) {
7578
- def = JSON.parse(foundSearchParameter);
7579
- }
7580
- //const def = await this.GetSearchParam(c.definition); //@@ fails here ...
7581
-
7582
- if (def && def.type) {
7583
- c.type = def.type
7584
- }
7585
- }
7586
- }
7587
-
7588
- await this.redis!.hSet(this.GetSTSCustomSearchParameterByResourceTypeKey(resourceType),
7589
- code, JSON.stringify(record));
7590
-
7591
- console.log(`Loaded...(j): [${j}]`);
7592
- }
7593
- console.log(`All Loaded...`);
7594
- }
7595
- console.log(`Loaded...(i): [${i}]`);
7596
- };
7597
- console.log(`Loaded...`);
7598
- } catch (error) {
7599
- console.error(error);
7600
- throw error;
7601
- }
7602
- }
7603
- */
7604
- /*
7605
- GetType = async (typeName: string): Promise<any[]> => {
7606
- await this.EnsureSearchParameterDataLoaded();
7607
- const foundType = await this.redis!.get(this.GetTypeKey(typeName));
7608
- if (foundType) {
7609
- return JSON.parse(foundType);
7610
- }
7611
- return [ ];
7612
- }
7613
-
7614
- GetResource = async (resourceType: string): Promise<any[]> => {
7615
- await this.EnsureSearchParameterDataLoaded();
7616
- const foundResourceType = await this.redis!.get(this.GetResourceKey(resourceType));
7617
- if (foundResourceType) {
7618
- return JSON.parse(foundResourceType);
7619
- }
7620
- return [ ];
7621
- }
7622
-
7623
- GetResourceField = async (resourceType: string, fieldPath: string): Promise<any> => {
7624
- const resource: any[] = await this.GetResource(resourceType);
7625
- if (resource) {
7626
- const foundRecord = resource.filter(o => o.id === fieldPath);
7627
- if (foundRecord.length > 0) {
7628
- return foundRecord[0];
7629
- }
7630
- return undefined;
7631
- }
7632
- }
7633
-
7634
- GetSearchParam = async (fullUrl: string): Promise<any> => {
7635
- await this.EnsureSearchParameterDataLoaded();
7636
- const foundSearchParameter = await this.redis!.get(this.GetSearchParameterByFullUrlKey(fullUrl));
7637
- if (foundSearchParameter) {
7638
- return JSON.parse(foundSearchParameter);
7639
- }
7640
- return null;
7641
- }
7642
-
7643
- GetSearchParamsByResourceType = async (resourceType: string): Promise<SearchParameter[]> => {
7644
- await this.EnsureSearchParameterDataLoaded();
7645
- const all = await this.redis!.hGetAll(this.GetSearchParameterByResourceTypeKey(resourceType));
7646
- const parsed = Object.values(all).map(v => JSON.parse(v));
7647
- return parsed;
7648
- }
7649
-
7650
- GetSTSCustomSearchParametersByResourceType = async (resourceType: string): Promise<ISearchParamRecord[]> => {
7651
- await this.EnsureSearchParameterDataLoaded();
7652
- const all = await this.redis!.hGetAll(this.GetSTSCustomSearchParameterByResourceTypeKey(resourceType));
7653
- const parsed = Object.values(all).map(v => JSON.parse(v));
7654
- return parsed;
7655
- }
7656
-
7657
- GetSearchParamFromResourceTypeUrl = async (resourceType: string, url: string): Promise<ISearchParamRecord | undefined> => {
7658
- const customSearchParameters = await this.GetSTSCustomSearchParametersByResourceType(resourceType);
7659
- const filterByNameAndUrl = customSearchParameters.filter(rt => rt.SP_URL.localeCompare(url) === 0);
7660
- if (filterByNameAndUrl.length > 0) {
7661
- return filterByNameAndUrl[0];
7662
- }
7663
- }
7664
-
7665
- GetSearchParamFromResourceType = async (resourceType: string, name: string): Promise<ISearchParamRecord | undefined> => {
7666
- const customSearchParameters = await this.GetSTSCustomSearchParametersByResourceType(resourceType);
7667
- const filterByName = customSearchParameters.filter(rt => rt.SP_NAME.localeCompare(name) === 0);
7668
- if (filterByName.length > 0) {
7669
- return filterByName[0];
7670
- }
7671
- }
7672
-
7673
- GetPathsFromResourceType = async (resourceType: string, name: string): Promise<string[]> => {
7674
- const customSearchParameters = await this.GetSTSCustomSearchParametersByResourceType(resourceType);
7675
- const filterByName = customSearchParameters.filter(rt => rt.SP_NAME.localeCompare(name) === 0);
7676
- if (filterByName.length > 0) {
7677
- return filterByName[0].expressions.map(e => e.path)
7678
- }
7679
- return [ ];
7680
- }
7681
- */
7682
7294
  }
7683
7295
  const specPath1 = "./dist/";
7684
7296
  const specPath2 = "./node_modules/@nsshunt/stsfhirpg/dist/";