@toxplanet/pegasus-sdk 1.0.1 → 1.1.0
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.
- package/config/environment.acc.js +27 -0
- package/config/environment.dev.js +6 -1
- package/config/environment.prod.js +6 -1
- package/config/environment.qa.js +5 -0
- package/config/index.js +1 -1
- package/index.js +44 -37
- package/lib/chemicals.js +293 -229
- package/lib/connection.js +223 -223
- package/lib/documents.js +94 -47
- package/lib/elasticsearch.js +404 -0
- package/lib/search.js +336 -307
- package/lib/sync.js +43 -41
- package/lib/utils.js +49 -47
- package/package.json +48 -25
- package/env.example +0 -21
- package/index.d.ts +0 -252
- package/tests/chemicals.js +0 -165
- package/tests/search.js +0 -138
package/tests/chemicals.js
DELETED
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
const PegasusSDK = require('../index');
|
|
2
|
-
const { logInfo, logError } = require('@toxplanet/tphelper/logging');
|
|
3
|
-
|
|
4
|
-
const ICONS = {
|
|
5
|
-
PASS: '[OK]',
|
|
6
|
-
FAIL: '[!!]',
|
|
7
|
-
WARN: '[?]'
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
async function runChemicalTests() {
|
|
11
|
-
const sdk = new PegasusSDK();
|
|
12
|
-
let testsPassed = 0;
|
|
13
|
-
let testsFailed = 0;
|
|
14
|
-
|
|
15
|
-
const log = (test, status, details = '') => {
|
|
16
|
-
logInfo('pegasus-sdk-tests', `${test}: ${status} ${details}`);
|
|
17
|
-
if (status === ICONS.PASS) testsPassed++;
|
|
18
|
-
else if (status === ICONS.FAIL) testsFailed++;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
const print = (message) => {
|
|
22
|
-
logInfo('pegasus-sdk-tests', message);
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
let createdChemicalId = null;
|
|
26
|
-
|
|
27
|
-
try {
|
|
28
|
-
await sdk.connect();
|
|
29
|
-
log('Connection', ICONS.PASS);
|
|
30
|
-
|
|
31
|
-
const testChemical = {
|
|
32
|
-
source_id: `test-chemical-${Date.now()}`,
|
|
33
|
-
chemical_name: 'Test Chemical (Benzene)',
|
|
34
|
-
chemical_meta: {
|
|
35
|
-
test: true,
|
|
36
|
-
description: 'This is a test chemical record'
|
|
37
|
-
},
|
|
38
|
-
chemical_identifiers: [
|
|
39
|
-
{ type: 'cas', value: '71-43-2' },
|
|
40
|
-
{ type: 'pubchem_cid', value: 'CID241' }
|
|
41
|
-
],
|
|
42
|
-
chemical_synonyms: ['Test Synonym 1', 'Test Synonym 2'],
|
|
43
|
-
chemical_categories: ['test', 'aromatic'],
|
|
44
|
-
created_at: new Date(),
|
|
45
|
-
updated_at: new Date()
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
print('\n' + '='.repeat(60));
|
|
49
|
-
print('TEST 1: Create Chemical');
|
|
50
|
-
print('='.repeat(60));
|
|
51
|
-
|
|
52
|
-
const created = await sdk.chemicals.createChemical(testChemical);
|
|
53
|
-
createdChemicalId = created.chemicalId;
|
|
54
|
-
|
|
55
|
-
if (created && created.chemicalId) {
|
|
56
|
-
log('Create Chemical', ICONS.PASS, `(ID: ${created.chemicalId.substring(0, 8)}...)`);
|
|
57
|
-
print(` Source ID: ${created.sourceId}`);
|
|
58
|
-
print(` Name: ${created.chemicalName}`);
|
|
59
|
-
print(` Identifiers: ${created.chemicalIdentifiers.length} found`);
|
|
60
|
-
print(` Synonyms: ${created.chemicalSynonyms.length} found`);
|
|
61
|
-
} else {
|
|
62
|
-
log('Create Chemical', ICONS.FAIL, 'No ID returned');
|
|
63
|
-
testsFailed++;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
print('\n' + '='.repeat(60));
|
|
67
|
-
print('TEST 2: Get Chemical By ID');
|
|
68
|
-
print('='.repeat(60));
|
|
69
|
-
|
|
70
|
-
const retrieved = await sdk.chemicals.getChemicalById(createdChemicalId);
|
|
71
|
-
|
|
72
|
-
if (retrieved && retrieved.chemicalId === createdChemicalId) {
|
|
73
|
-
log('Get Chemical By ID', ICONS.PASS);
|
|
74
|
-
print(` Retrieved Name: ${retrieved.chemicalName}`);
|
|
75
|
-
print(` Source ID: ${retrieved.sourceId}`);
|
|
76
|
-
|
|
77
|
-
if (retrieved.chemicalName === testChemical.chemical_name) {
|
|
78
|
-
log('Name Match', ICONS.PASS);
|
|
79
|
-
} else {
|
|
80
|
-
log('Name Match', ICONS.FAIL, `Expected: ${testChemical.chemical_name}, Got: ${retrieved.chemicalName}`);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if (retrieved.sourceId === testChemical.source_id) {
|
|
84
|
-
log('Source ID Match', ICONS.PASS);
|
|
85
|
-
} else {
|
|
86
|
-
log('Source ID Match', ICONS.FAIL);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (Array.isArray(retrieved.chemicalIdentifiers) && retrieved.chemicalIdentifiers.length === 2) {
|
|
90
|
-
log('Identifiers Match', ICONS.PASS, `(${retrieved.chemicalIdentifiers.length} identifiers)`);
|
|
91
|
-
} else {
|
|
92
|
-
log('Identifiers Match', ICONS.FAIL);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (Array.isArray(retrieved.chemicalSynonyms) && retrieved.chemicalSynonyms.length === 2) {
|
|
96
|
-
log('Synonyms Match', ICONS.PASS, `(${retrieved.chemicalSynonyms.length} synonyms)`);
|
|
97
|
-
} else {
|
|
98
|
-
log('Synonyms Match', ICONS.FAIL);
|
|
99
|
-
}
|
|
100
|
-
} else {
|
|
101
|
-
log('Get Chemical By ID', ICONS.FAIL, 'Chemical not found or ID mismatch');
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
print('\n' + '='.repeat(60));
|
|
105
|
-
print('TEST 3: Get Non-Existent Chemical');
|
|
106
|
-
print('='.repeat(60));
|
|
107
|
-
|
|
108
|
-
const nonExistent = await sdk.chemicals.getChemicalById('00000000-0000-0000-0000-000000000000');
|
|
109
|
-
|
|
110
|
-
if (nonExistent === null) {
|
|
111
|
-
log('Get Non-Existent', ICONS.PASS, '(Correctly returned null)');
|
|
112
|
-
} else {
|
|
113
|
-
log('Get Non-Existent', ICONS.FAIL, 'Should return null for non-existent ID');
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
print('\n' + '='.repeat(60));
|
|
117
|
-
print('TEST 4: Delete Chemical');
|
|
118
|
-
print('='.repeat(60));
|
|
119
|
-
|
|
120
|
-
const deleted = await sdk.chemicals.deleteChemical(createdChemicalId);
|
|
121
|
-
|
|
122
|
-
if (deleted && deleted.chemicalId === createdChemicalId) {
|
|
123
|
-
log('Delete Chemical', ICONS.PASS, `(Deleted ID: ${deleted.chemicalId.substring(0, 8)}...)`);
|
|
124
|
-
} else {
|
|
125
|
-
log('Delete Chemical', ICONS.FAIL, 'Delete did not return expected result');
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
print('\n' + '='.repeat(60));
|
|
129
|
-
print('TEST 5: Verify Deletion');
|
|
130
|
-
print('='.repeat(60));
|
|
131
|
-
|
|
132
|
-
const shouldBeGone = await sdk.chemicals.getChemicalById(createdChemicalId);
|
|
133
|
-
|
|
134
|
-
if (shouldBeGone === null) {
|
|
135
|
-
log('Verify Deletion', ICONS.PASS, '(Chemical no longer exists)');
|
|
136
|
-
} else {
|
|
137
|
-
log('Verify Deletion', ICONS.FAIL, 'Chemical still exists after deletion');
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
print('\n' + '='.repeat(60));
|
|
141
|
-
print(`${ICONS.PASS} Tests Passed: ${testsPassed}`);
|
|
142
|
-
if (testsFailed > 0) print(`${ICONS.FAIL} Tests Failed: ${testsFailed}`);
|
|
143
|
-
print('='.repeat(60));
|
|
144
|
-
|
|
145
|
-
} catch (error) {
|
|
146
|
-
logError('pegasus-sdk-tests', 'chemicals-tests', 'runChemicalTests', error);
|
|
147
|
-
print(`\n${ICONS.FAIL} Test Failed: ${error.message}`);
|
|
148
|
-
|
|
149
|
-
if (createdChemicalId) {
|
|
150
|
-
print('\nCleaning up test chemical...');
|
|
151
|
-
try {
|
|
152
|
-
await sdk.chemicals.deleteChemical(createdChemicalId);
|
|
153
|
-
print('Cleanup successful');
|
|
154
|
-
} catch (cleanupError) {
|
|
155
|
-
print('Cleanup failed (chemical may need manual deletion)');
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
process.exit(1);
|
|
160
|
-
} finally {
|
|
161
|
-
await sdk.disconnect();
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
runChemicalTests();
|
package/tests/search.js
DELETED
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
const PegasusSDK = require('../index');
|
|
2
|
-
const { logInfo, logError } = require('@toxplanet/tphelper/logging');
|
|
3
|
-
|
|
4
|
-
const ICONS = {
|
|
5
|
-
PASS: '[OK]',
|
|
6
|
-
FAIL: '[!!]',
|
|
7
|
-
WARN: '[?]'
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
async function runTests() {
|
|
11
|
-
const sdk = new PegasusSDK();
|
|
12
|
-
let testsPassed = 0;
|
|
13
|
-
let testsFailed = 0;
|
|
14
|
-
|
|
15
|
-
const log = (test, status, details = '') => {
|
|
16
|
-
logInfo('pegasus-sdk-tests', `${test}: ${status} ${details}`);
|
|
17
|
-
if (status === ICONS.PASS) testsPassed++;
|
|
18
|
-
else if (status === ICONS.FAIL) testsFailed++;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
const print = (message) => {
|
|
22
|
-
logInfo('pegasus-sdk-tests', message);
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
try {
|
|
26
|
-
await sdk.connect();
|
|
27
|
-
log('Connection', ICONS.PASS);
|
|
28
|
-
|
|
29
|
-
const health = await sdk.healthCheck();
|
|
30
|
-
const pgStatus = health.postgres.connected ? ICONS.PASS : ICONS.FAIL;
|
|
31
|
-
const osStatus = health.opensearch?.connected ? ICONS.PASS : ICONS.WARN;
|
|
32
|
-
log('Health Check', health.postgres.connected && health.opensearch?.connected ? ICONS.PASS : ICONS.WARN, `(PG:${pgStatus} OS:${osStatus})`);
|
|
33
|
-
|
|
34
|
-
if (!sdk.search?.searchChemicals) throw new Error('Search service not found');
|
|
35
|
-
log('Search Service', ICONS.PASS);
|
|
36
|
-
|
|
37
|
-
const emptyResult = await sdk.search.searchChemicals('');
|
|
38
|
-
if (emptyResult.results.length !== 0) throw new Error('Empty query should return no results');
|
|
39
|
-
log('Empty Query', ICONS.PASS);
|
|
40
|
-
|
|
41
|
-
const basicResult = await sdk.search.searchChemicals('test', { limit: 5 });
|
|
42
|
-
if (!Array.isArray(basicResult.results)) throw new Error('Invalid result structure');
|
|
43
|
-
log('Basic Search', ICONS.PASS, `(${basicResult.results.length} results)`);
|
|
44
|
-
|
|
45
|
-
const customResult = await sdk.search.searchChemicals('carbon', {
|
|
46
|
-
limit: 3,
|
|
47
|
-
casExact: 100,
|
|
48
|
-
nameExact: 50,
|
|
49
|
-
synonymExact: 75
|
|
50
|
-
});
|
|
51
|
-
log('Custom Boost', ICONS.PASS, `(${customResult.results.length} results)`);
|
|
52
|
-
|
|
53
|
-
const casResult = await sdk.search.searchChemicals('7440-06-4', { limit: 3 });
|
|
54
|
-
log('CAS Search', ICONS.PASS, `(${casResult.results.length} results)`);
|
|
55
|
-
|
|
56
|
-
const reversedCasResult = await sdk.search.searchChemicals('06/4/7440', { limit: 3 });
|
|
57
|
-
log('CAS Reversed Format', ICONS.PASS, `(${reversedCasResult.results.length} results)`);
|
|
58
|
-
|
|
59
|
-
if (basicResult.results.length > 0) {
|
|
60
|
-
const result = basicResult.results[0];
|
|
61
|
-
const requiredFields = ['id', 'name', 'cas', 'identifiers', 'synonyms', 'score'];
|
|
62
|
-
const missingFields = requiredFields.filter(field => !(field in result));
|
|
63
|
-
if (missingFields.length > 0) throw new Error(`Missing fields: ${missingFields.join(', ')}`);
|
|
64
|
-
if (!Array.isArray(result.cas) || !Array.isArray(result.identifiers) || !Array.isArray(result.synonyms)) {
|
|
65
|
-
throw new Error('Array fields invalid');
|
|
66
|
-
}
|
|
67
|
-
if (typeof result.score !== 'number') throw new Error('Score not a number');
|
|
68
|
-
log('Result Structure', ICONS.PASS);
|
|
69
|
-
} else {
|
|
70
|
-
log('Result Structure', ICONS.WARN, '(no results to validate)');
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const startsWithResult = await sdk.search.searchStartsWith('test', 3);
|
|
74
|
-
const containsResult = await sdk.search.searchContains('test', 3);
|
|
75
|
-
const exactResult = await sdk.search.searchExact('test', 3);
|
|
76
|
-
if (!startsWithResult.results || !containsResult.results || !exactResult.results) {
|
|
77
|
-
throw new Error('Forwarding methods failed');
|
|
78
|
-
}
|
|
79
|
-
log('SearchService Methods', ICONS.PASS, `(starts:${startsWithResult.results.length} contains:${containsResult.results.length} exact:${exactResult.results.length})`);
|
|
80
|
-
|
|
81
|
-
const casExactResult = await sdk.search.searchByCAS('7440-06-4', 'exact');
|
|
82
|
-
const casPrefixResult = await sdk.search.searchByCAS('7440', 'prefix');
|
|
83
|
-
log('CAS Methods', ICONS.PASS, `(exact:${casExactResult.results.length} prefix:${casPrefixResult.results.length})`);
|
|
84
|
-
|
|
85
|
-
const identifierResult = await sdk.search.searchByIdentifier('CCCO', 'exact');
|
|
86
|
-
log('Identifier Method', ICONS.PASS, `(${identifierResult.results.length} results)`);
|
|
87
|
-
|
|
88
|
-
const synonymExactResult = await sdk.search.searchBySynonym('grain alcohol', 'exact');
|
|
89
|
-
const synonymPrefixResult = await sdk.search.searchBySynonym('alco', 'prefix');
|
|
90
|
-
log('Synonym Methods', ICONS.PASS, `(exact:${synonymExactResult.results.length} prefix:${synonymPrefixResult.results.length})`);
|
|
91
|
-
|
|
92
|
-
const nameSearchResult = await sdk.chemicals.searchByName('platinum', 3);
|
|
93
|
-
const synonymSearchResult = await sdk.chemicals.searchBySynonym('alcohol', 3);
|
|
94
|
-
if (!nameSearchResult.results || !synonymSearchResult.results) {
|
|
95
|
-
throw new Error('ChemicalsService methods failed');
|
|
96
|
-
}
|
|
97
|
-
log('ChemicalsService Methods', ICONS.PASS, `(name:${nameSearchResult.results.length} synonym:${synonymSearchResult.results.length})`);
|
|
98
|
-
|
|
99
|
-
const highLimitResult = await sdk.search.searchChemicals('carbon', { limit: 20 });
|
|
100
|
-
log('High Limit Search', ICONS.PASS, `(${highLimitResult.results.length} results)`);
|
|
101
|
-
|
|
102
|
-
print(`\n${'='.repeat(60)}`);
|
|
103
|
-
print('FINAL TEST: Benzene Search Results');
|
|
104
|
-
print('='.repeat(60));
|
|
105
|
-
const benzeneResults = await sdk.search.searchChemicals('benzene', { limit: 3 });
|
|
106
|
-
print(`Found ${benzeneResults.results.length} results for "benzene":\n`);
|
|
107
|
-
benzeneResults.results.forEach((result, i) => {
|
|
108
|
-
print(`${i + 1}. ${result.name}`);
|
|
109
|
-
print(` CAS: ${result.cas.join(', ') || 'N/A'}`);
|
|
110
|
-
print(` Score: ${result.score.toFixed(2)}`);
|
|
111
|
-
if (result.synonyms.length > 0) {
|
|
112
|
-
print(` Synonyms: ${result.synonyms.slice(0, 3).join(', ')}${result.synonyms.length > 3 ? '...' : ''}`);
|
|
113
|
-
}
|
|
114
|
-
print('');
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
print('='.repeat(60));
|
|
118
|
-
print(`${ICONS.PASS} Tests Passed: ${testsPassed}`);
|
|
119
|
-
if (testsFailed > 0) print(`${ICONS.FAIL} Tests Failed: ${testsFailed}`);
|
|
120
|
-
print('='.repeat(60));
|
|
121
|
-
|
|
122
|
-
} catch (error) {
|
|
123
|
-
logError('pegasus-sdk-tests', 'search-tests', 'runTests', error);
|
|
124
|
-
print(`\n${ICONS.FAIL} Test Failed: ${error.message}`);
|
|
125
|
-
process.exit(1);
|
|
126
|
-
} finally {
|
|
127
|
-
await sdk.disconnect();
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
if (require.main === module) {
|
|
132
|
-
runTests().catch((error) => {
|
|
133
|
-
logError('pegasus-sdk-tests', 'search-tests', 'main', error);
|
|
134
|
-
process.exit(1);
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
module.exports = runTests;
|