@toxplanet/pegasus-sdk 1.1.7 → 1.1.8

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.
@@ -20,7 +20,7 @@ module.exports = {
20
20
  }
21
21
  },
22
22
  indexRoutes: {
23
- chemicals: ['*'],
23
+ chemicals: ['chemicals*'],
24
24
  documents: ['documents*'],
25
25
  search: [/^(chemicals|substances|search)/]
26
26
  }
@@ -19,9 +19,9 @@ module.exports = {
19
19
  rejectUnauthorized: false
20
20
  }
21
21
  },
22
- indexRoutes: {
23
- chemicals: ['chemical_index*', 'synonym_lookup_index'],
24
- documents: ['document_nones_index*'],
25
- search: [/^(chemical_index|document_nones_index|search)/]
26
- }
22
+ indexRoutes: {
23
+ chemicals: ['chemicals*'],
24
+ documents: ['documents*'],
25
+ search: [/^(chemicals|substances|search)/]
26
+ }
27
27
  };
@@ -20,7 +20,7 @@ module.exports = {
20
20
  }
21
21
  },
22
22
  indexRoutes: {
23
- chemicals: ['*'],
23
+ chemicals: ['chemicals*'],
24
24
  documents: ['documents*'],
25
25
  search: [/^(chemicals|substances|search)/]
26
26
  }
package/lib/chemicals.js CHANGED
@@ -628,121 +628,171 @@ class ChemicalsService {
628
628
  }
629
629
  }
630
630
 
631
- registerElasticsearchHandlers(elasticsearchService) {
632
- const indexPatterns = this.connection.config.indexRoutes?.chemicals || ['chemicals*'];
633
-
634
- indexPatterns.forEach(pattern => {
635
- elasticsearchService.registerIndexRoute(pattern, {
636
- index: async (params) => {
637
- const chemical = params.body;
638
- const result = await this.createChemical(chemical);
639
-
640
- return {
641
- _index: params.index,
642
- _id: result.chemicalId,
643
- _version: 1,
644
- result: 'created',
645
- _source: result
646
- };
647
- },
631
+ _buildEsHandlers() {
632
+ return {
633
+ index: async (params) => {
634
+ const chemical = params.body;
635
+ const result = await this.createChemical(chemical);
648
636
 
649
- bulk: async (params) => {
650
- const operations = params.body || params.operations;
651
- const documents = [];
652
-
653
- for (let i = 0; i < operations.length; i += 2) {
654
- const action = operations[i];
655
- const document = operations[i + 1];
656
-
657
- if (action.index || action.create) {
658
- documents.push(document);
637
+ return {
638
+ _index: params.index,
639
+ _id: result.chemicalId,
640
+ _version: 1,
641
+ result: 'created',
642
+ _source: result
643
+ };
644
+ },
645
+
646
+ bulk: async (params) => {
647
+ const operations = params.body || params.operations;
648
+ const cdiDocuments = [];
649
+
650
+ for (let i = 0; i < operations.length; i++) {
651
+ const op = operations[i];
652
+ if ((op.index || op.create) &&
653
+ (op.index?._index === 'chemical_data_index' || op.create?._index === 'chemical_data_index')) {
654
+ const doc = operations[i + 1];
655
+ const sourceId = op.index?._id || op.create?._id;
656
+ if (doc && sourceId) {
657
+ cdiDocuments.push({
658
+ source_id: sourceId,
659
+ chemical_name: doc.chemical_primary_name || (doc.chemical_names && doc.chemical_names[0]) || null,
660
+ chemical_meta: doc.chemical_meta || {},
661
+ chemical_identifiers: doc.chemical_identifiers || {},
662
+ chemical_synonyms: doc.chemical_synonyms || [],
663
+ chemical_categories: doc.chemical_categories || [],
664
+ created_at: doc.chemical_created_at,
665
+ updated_at: doc.chemical_updated_at
666
+ });
667
+ i++;
659
668
  }
660
669
  }
661
-
662
- const result = await this.bulkIndexFielded(documents);
663
-
664
- const items = result.results.map((res, idx) => {
665
- if (res.success) {
666
- return {
667
- index: {
668
- _index: params.index || 'chemicals',
669
- _id: documents[idx].source_id || documents[idx]._id,
670
- status: 201,
671
- result: 'created'
672
- }
673
- };
674
- } else {
675
- return {
676
- index: {
677
- _index: params.index || 'chemicals',
678
- _id: documents[idx].source_id || documents[idx]._id,
679
- status: 400,
680
- error: {
681
- type: 'mapper_parsing_exception',
682
- reason: res.error
683
- }
684
- }
685
- };
670
+ }
671
+
672
+ if (cdiDocuments.length === 0) {
673
+ return { took: 0, errors: false, items: [] };
674
+ }
675
+
676
+ const result = await this.bulkIndexFielded(cdiDocuments);
677
+
678
+ return {
679
+ took: 1,
680
+ errors: result.errors.length > 0,
681
+ items: result.results.map((res, idx) => ({
682
+ index: {
683
+ _index: 'chemical_data_index',
684
+ _id: cdiDocuments[idx].source_id,
685
+ status: res.success ? 200 : 400,
686
+ result: res.success ? 'created' : 'error',
687
+ ...(res.success ? {} : { error: { type: 'mapper_parsing_exception', reason: res.error } })
686
688
  }
687
- });
688
-
689
- return {
690
- took: 1,
691
- errors: result.errors.length > 0,
692
- items
693
- };
694
- },
695
-
696
- get: async (params) => {
697
- const result = await this.getChemicalById(params.id);
698
-
699
- if (!result) {
700
- return {
701
- _index: params.index,
702
- _id: params.id,
703
- found: false
704
- };
705
- }
706
-
707
- return {
708
- _index: params.index,
709
- _id: result.chemicalId,
710
- _version: 1,
711
- found: true,
712
- _source: result
713
- };
714
- },
689
+ }))
690
+ };
691
+ },
692
+
693
+ get: async (params) => {
694
+ const result = await this.getChemicalBySourceId(params.id);
715
695
 
716
- update: async (params) => {
717
- const result = await this.updateChemical(params.id, params.body);
718
-
696
+ if (!result) {
719
697
  return {
720
698
  _index: params.index,
721
699
  _id: params.id,
722
- _version: 2,
723
- result: result ? 'updated' : 'noop',
724
- _source: result
700
+ found: false
725
701
  };
726
- },
702
+ }
703
+
704
+ return {
705
+ _index: params.index,
706
+ _id: params.id,
707
+ _version: 1,
708
+ found: true,
709
+ _source: result
710
+ };
711
+ },
712
+
713
+ update: async (params) => {
714
+ const result = await this.updateChemical(params.id, params.body);
715
+
716
+ return {
717
+ _index: params.index,
718
+ _id: params.id,
719
+ _version: 2,
720
+ result: result ? 'updated' : 'noop',
721
+ _source: result
722
+ };
723
+ },
724
+
725
+ delete: async (params) => {
726
+ if (params.index === 'synonym_lookup_index') {
727
+ return { _index: params.index, _id: params.id, result: 'not_found' };
728
+ }
729
+ const result = await this.deleteBySourceId(params.id);
730
+
731
+ return {
732
+ _index: params.index,
733
+ _id: params.id,
734
+ result: result ? 'deleted' : 'not_found'
735
+ };
736
+ },
737
+
738
+ deleteByQuery: async (params) => {
739
+ const sourceId = params.body?.query?.term?.chemical_set_identifier
740
+ || params.body?.query?.term?.source_id;
741
+ if (!sourceId) {
742
+ return { deleted: 0, failures: [] };
743
+ }
744
+ const result = await this.deleteBySourceId(sourceId);
745
+ return {
746
+ deleted: result ? 1 : 0,
747
+ failures: []
748
+ };
749
+ },
750
+
751
+ search: async (params) => {
752
+ let searchTerm = '';
753
+ let limit = params.body?.size || 10;
727
754
 
728
- delete: async (params) => {
729
- const result = await this.deleteChemical(params.id);
755
+ if (params.index === 'synonym_lookup_index') {
756
+ const query = params.body?.query;
757
+ searchTerm = query?.match?.chemical_name ||
758
+ query?.term?.chemical_name ||
759
+ query?.query_string?.query || '';
760
+ const searchResults = await this.searchBySynonym(searchTerm, limit);
730
761
 
731
762
  return {
732
- _index: params.index,
733
- _id: params.id,
734
- _version: 1,
735
- result: result ? 'deleted' : 'not_found'
763
+ took: 1,
764
+ timed_out: false,
765
+ _shards: {
766
+ total: 1,
767
+ successful: 1,
768
+ skipped: 0,
769
+ failed: 0
770
+ },
771
+ hits: {
772
+ total: {
773
+ value: searchResults.results.length,
774
+ relation: 'eq'
775
+ },
776
+ max_score: searchResults.results[0]?.score || 0,
777
+ hits: searchResults.results.map(result => ({
778
+ _index: params.index,
779
+ _id: result.id,
780
+ _score: result.score,
781
+ _source: {
782
+ postgres_id: result.id,
783
+ chemical_name: result.name,
784
+ cas_numbers: result.cas,
785
+ identifier_values: result.identifiers,
786
+ synonyms: result.synonyms
787
+ }
788
+ }))
789
+ }
736
790
  };
737
- },
738
-
739
- search: async (params) => {
791
+ } else {
740
792
  const query = params.body?.query;
741
- const searchTerm = query?.match?.chemical_name ||
742
- query?.term?.chemical_name ||
743
- query?.query_string?.query || '';
744
- const limit = params.body?.size || 10;
745
-
793
+ searchTerm = query?.match?.chemical_name ||
794
+ query?.term?.chemical_name ||
795
+ query?.query_string?.query || '';
746
796
  const searchResults = await this.searchByName(searchTerm, limit);
747
797
 
748
798
  return {
@@ -774,12 +824,25 @@ class ChemicalsService {
774
824
  }))
775
825
  }
776
826
  };
777
- },
778
-
779
- count: async (params) => {
780
- return await this.countAll();
781
827
  }
782
- });
828
+ },
829
+
830
+ count: async (params) => {
831
+ if (params.index === 'synonym_lookup_index') {
832
+ return await this.getTotalSynonymCount();
833
+ }
834
+ return await this.countAll();
835
+ }
836
+ };
837
+ }
838
+
839
+ registerElasticsearchHandlers(elasticsearchService) {
840
+ const configurablePatterns = this.connection.config.indexRoutes?.chemicals || ['chemicals*'];
841
+ const legacyPatterns = ['synonym_lookup_index', 'chemical_data_index', 'chemical_converter_index'];
842
+ const allPatterns = [...new Set([...configurablePatterns, ...legacyPatterns])];
843
+ const handlers = this._buildEsHandlers();
844
+ allPatterns.forEach(pattern => {
845
+ elasticsearchService.registerIndexRoute(pattern, handlers);
783
846
  });
784
847
  }
785
848
  }
package/lib/db/index.js CHANGED
@@ -1,18 +1,18 @@
1
- const { drizzle } = require('drizzle-orm/node-postgres');
2
- const { logInfo } = require('@toxplanet/tphelper/logging');
3
- const schema = require('./schema');
4
-
5
- const logger = {
6
- logQuery(query, params) {
7
- logInfo('pegasus-sdk', `[SQL] ${query}${params?.length ? ` -- params: ${JSON.stringify(params)}` : ''}`);
8
- }
9
- };
10
-
11
- function getDrizzle(pgPool) {
12
- return drizzle(pgPool, { schema, logger });
13
- }
14
-
15
- module.exports = {
16
- getDrizzle,
17
- schema
18
- };
1
+ const { drizzle } = require('drizzle-orm/node-postgres');
2
+ const { logInfo } = require('@toxplanet/tphelper/logging');
3
+ const schema = require('./schema');
4
+
5
+ const logger = {
6
+ logQuery(query, params) {
7
+ logInfo('pegasus-sdk', `[SQL] ${query}${params?.length ? ` -- params: ${JSON.stringify(params)}` : ''}`);
8
+ }
9
+ };
10
+
11
+ function getDrizzle(pgPool) {
12
+ return drizzle(pgPool, { schema, logger });
13
+ }
14
+
15
+ module.exports = {
16
+ getDrizzle,
17
+ schema
18
+ };
@@ -69,17 +69,22 @@ class ElasticsearchService {
69
69
  throw new Error('Bulk operations must be a non-empty array');
70
70
  }
71
71
 
72
- const firstOp = operations[0];
73
- const indexName = firstOp?.index?._index || firstOp?.index?.index || firstOp?.create?._index || firstOp?.create?.index || params.index;
74
-
75
- if (!indexName) {
76
- throw new Error('Could not determine index from bulk operations');
72
+ let indexName = params.index;
73
+ let cdiIndexName = null;
74
+ for (const op of operations) {
75
+ const name = op?.index?._index || op?.index?.index ||
76
+ op?.create?._index || op?.create?.index ||
77
+ op?.delete?._index || op?.delete?.index ||
78
+ op?.update?._index || op?.update?.index;
79
+ if (!name) continue;
80
+ if (name === 'chemical_data_index') { cdiIndexName = name; break; }
81
+ if (!indexName) indexName = name;
77
82
  }
83
+ indexName = cdiIndexName || indexName;
84
+ if (!indexName) throw new Error('Could not determine index from bulk operations');
78
85
 
79
86
  const handler = this.getRouteHandler(indexName);
80
- if (handler && handler.bulk) {
81
- return await handler.bulk(params);
82
- }
87
+ if (handler && handler.bulk) return await handler.bulk(params);
83
88
  throw new Error(`No handler registered for index: ${indexName}`);
84
89
  }
85
90
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toxplanet/pegasus-sdk",
3
- "version": "1.1.7",
3
+ "version": "1.1.8",
4
4
  "description": "SDK for migrating chemical data to Pegasus PostgreSQL + OpenSearch architecture with Elasticsearch client compatibility",
5
5
  "main": "index.js",
6
6
  "type": "commonjs",