Skip to content

Commit 6438eb9

Browse files
committed
Add 'src/mddb-database/' from commit '4402758ce8e1347e14b6f3f2dd56f38c9744d08e'
git-subtree-dir: src/mddb-database git-subtree-mainline: 870484c git-subtree-split: 4402758
2 parents 870484c + 4402758 commit 6438eb9

9 files changed

Lines changed: 1487 additions & 0 deletions

File tree

‎src/mddb-database/README.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# MDDB database
2+
3+
This is a database handler used in multiple MDDB git repositories.

‎src/mddb-database/index.js‎

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// Connect to the mongo database and return the connection
2+
// Alternatively, in 'test' context, connect to a local fake mongo database and return the connection
3+
const databaseConnection = process.env.NODE_ENV === 'test'
4+
? require('./utils/fake-mongo')
5+
: require('./utils/connect-mongo');
6+
7+
// Import collections configuration
8+
const {
9+
LOCAL_COLLECTIONS,
10+
GLOBAL_COLLECTIONS,
11+
REFERENCES,
12+
STANDARD_TRAJECTORY_FILENAME,
13+
STANDARD_STRUCTURE_FILENAME,
14+
} = require('./utils/constants');
15+
16+
// GridFSBucket manages the saving of files bigger than 16 Mb, splitting them into 4 Mb fragments (chunks)
17+
const { GridFSBucket } = require('mongodb');
18+
19+
// Set the database class
20+
class Database {
21+
constructor (client, isGlobal) {
22+
if (!client) throw new Error('No client');
23+
if (isGlobal !== false && isGlobal !== true)
24+
throw new Error('The "isGlobal" argument must be either true or false.');
25+
// Store inputs
26+
this.client = client;
27+
this.isGlobal = isGlobal;
28+
// Get the mongo specific database
29+
this.db = this.client.db(process.env.DB_NAME);
30+
// Set the mongo collections depending of it we are aiming for the global database
31+
this.COLLECTIONS = this.isGlobal ? GLOBAL_COLLECTIONS : LOCAL_COLLECTIONS;
32+
// Set all collections as values of the database itself
33+
for (const [ collectionKey, collectionConfig ] of Object.entries(this.COLLECTIONS)) {
34+
this[collectionKey] = this.db.collection(collectionConfig.name);
35+
}
36+
// Save additional constants just to have them available more easily
37+
this.STANDARD_TRAJECTORY_FILENAME = STANDARD_TRAJECTORY_FILENAME;
38+
this.STANDARD_STRUCTURE_FILENAME = STANDARD_STRUCTURE_FILENAME;
39+
// Get the available references in a single string, which may be used for logs
40+
this.REFERENCES = REFERENCES;
41+
this.AVAILABLE_REFERENCES = Object.keys(this.REFERENCES).join(', ');
42+
// Save some internal values
43+
this._bucket = undefined;
44+
};
45+
46+
// Get the grid fs bucket
47+
get bucket () {
48+
// Return the internal value if it is already declared
49+
if (this._bucket !== undefined) return this._bucket;
50+
// Instantiate the bucket otherwise
51+
this._bucket = new GridFSBucket(this.db);
52+
return this._bucket;
53+
}
54+
55+
// Close the connection to mongo and delete this handler
56+
close = () => {
57+
this.client.close();
58+
delete this;
59+
}
60+
}
61+
62+
// Connect to the database
63+
// Then construct and return the database handler
64+
const connectToDatabase = async isGlobal => {
65+
// Save the mongo database connection
66+
const client = await dbConnection;
67+
// Instantiate the database handler
68+
return new Database(client, isGlobal);
69+
};
70+
71+
// Get the database client
72+
// Note that this function is set separatedly and not integrated in the handler since it is async
73+
const getDatabaseClient = async () => {
74+
const client = await dbConnection;
75+
}
76+
77+
module.exports = {
78+
databaseConnection,
79+
Database,
80+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
const mongodb = require('mongodb');
2+
3+
// Try to connect with the mongo db
4+
const establishConnection = async () => {
5+
let client;
6+
try {
7+
client = await mongodb.MongoClient.connect(
8+
`mongodb://${process.env.DB_SERVER}:${process.env.DB_PORT}`,
9+
{
10+
auth: {
11+
username: process.env.DB_AUTH_USER,
12+
password: process.env.DB_AUTH_PASSWORD,
13+
},
14+
authSource: process.env.DB_AUTHSOURCE,
15+
useNewUrlParser: true,
16+
useUnifiedTopology: true,
17+
},
18+
);
19+
return client;
20+
} catch (error) {
21+
console.error('mongodb connection error');
22+
console.error(error);
23+
if (client && 'close' in client) client.close();
24+
}
25+
};
26+
27+
module.exports = establishConnection();
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
// Set the configuration of every mongo collection
2+
// Set local and global collections separatedly since they may use different indexes
3+
// name - Actual name of the collection inside the database
4+
// indexes - Index configuration in the database, for the collections setup
5+
// documentNames - Document names used for displaying only
6+
const LOCAL_COLLECTIONS = {
7+
projects: {
8+
name: 'projects',
9+
indexes: [{ published: 1 }],
10+
documentNames: { singular: 'project', plural: 'projects' },
11+
},
12+
uniprot_refs: {
13+
name: 'references',
14+
documentNames: { singular: 'reference', plural: 'references' },
15+
},
16+
inchikey_refs: {
17+
name: 'inchikey_refs',
18+
documentNames: { singular: 'inchikey', plural: 'inchikeys' },
19+
},
20+
pdb_refs: {
21+
name: 'pdb_refs',
22+
documentNames: { singular: 'PDB', plural: 'PDBs' },
23+
},
24+
chain_refs: {
25+
name: 'chain_refs',
26+
documentNames: { singular: 'chain', plural: 'chains' },
27+
},
28+
collection_refs: {
29+
name: 'collection_refs',
30+
documentNames: { singular: 'collection', plural: 'collections' },
31+
},
32+
topologies: {
33+
name: 'topologies',
34+
indexes: [{ project: 1 }],
35+
documentNames: { singular: 'topology', plural: 'topologies' },
36+
},
37+
files: {
38+
name: 'fs.files',
39+
indexes: [{ 'metadata.project': 1 }],
40+
documentNames: { singular: 'file', plural: 'files' },
41+
},
42+
chunks: {
43+
name: 'fs.chunks',
44+
documentNames: { singular: 'chunk', plural: 'chunks' },
45+
},
46+
analyses: {
47+
name: 'analyses',
48+
indexes: [{ project: 1 }],
49+
documentNames: { singular: 'analysis', plural: 'analyses' },
50+
},
51+
counters: {
52+
name: 'counters',
53+
documentNames: { singular: 'counter', plural: 'counters' }
54+
},
55+
};
56+
const GLOBAL_COLLECTIONS = {
57+
projects: {
58+
name: 'global.projects',
59+
indexes: [{ posited: 1 }, { accession: 1 }, { node: 1, local: 1 }],
60+
documentNames: { singular: 'project', plural: 'projects' },
61+
},
62+
topologies: {
63+
name: 'global.topologies',
64+
documentNames: { singular: 'topology', plural: 'topologies' },
65+
},
66+
uniprot_refs: {
67+
name: 'global.references',
68+
indexes: [{ uniprot: 1 }],
69+
documentNames: { singular: 'reference', plural: 'references' },
70+
},
71+
inchikey_refs: {
72+
name: 'global.inchikeys',
73+
indexes: [{ inchikey: 1 }],
74+
documentNames: { singular: 'inchikey', plural: 'inchikeys' },
75+
},
76+
pdb_refs: {
77+
name: 'global.pdb_refs',
78+
indexes: [{ id: 1 }],
79+
documentNames: { singular: 'pdb', plural: 'pdbs' },
80+
},
81+
chain_refs: {
82+
name: 'global.chain_refs',
83+
documentNames: { singular: 'chain', plural: 'chains' },
84+
},
85+
collection_refs: {
86+
name: 'global.collection_refs',
87+
documentNames: { singular: 'collection', plural: 'collections' },
88+
},
89+
nodes: {
90+
name: 'global.nodes',
91+
documentNames: { singular: 'topology', plural: 'topologies' },
92+
},
93+
counters: {
94+
name: 'global.counters',
95+
documentNames: { singular: 'counter', plural: 'counters' }
96+
},
97+
pointers: {
98+
name: 'pointers',
99+
documentNames: { singular: 'pointers', plural: 'pointers' }
100+
}
101+
};
102+
103+
// Set the configuration of every reference collection
104+
// Configuration for local and global collections should be identical
105+
// The 'idField' is the field inside every reference document which stores the reference id
106+
// The 'projectIdsField' is the field inside project documents with a list of reference ids related to the project
107+
const REFERENCES = {
108+
proteins: {
109+
collectionName: 'uniprot_refs',
110+
idField: 'uniprot',
111+
projectIdsField: 'metadata.REFERENCES'
112+
},
113+
inchikeys: {
114+
collectionName: 'inchikey_refs',
115+
idField: 'inchikey',
116+
projectIdsField: 'metadata.INCHIKEYS'
117+
},
118+
pdbs: {
119+
collectionName: 'pdb_refs',
120+
idField: 'id',
121+
projectIdsField: 'metadata.PDBIDS'
122+
},
123+
chains: {
124+
collectionName: 'chain_refs',
125+
idField: 'sequence',
126+
projectIdsField: 'metadata.PROTSEQ'
127+
},
128+
collections: {
129+
collectionName: 'collection_refs',
130+
idField: 'id',
131+
projectIdsField: 'metadata.COLLECTIONS'
132+
}
133+
};
134+
135+
// Set some constants
136+
module.exports = {
137+
// Export mongo collections
138+
LOCAL_COLLECTIONS,
139+
GLOBAL_COLLECTIONS,
140+
// Export references
141+
REFERENCES,
142+
// Standard filenames
143+
STANDARD_TRAJECTORY_FILENAME: 'trajectory.bin',
144+
STANDARD_STRUCTURE_FILENAME: 'structure.pdb',
145+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// This library provides a fake mongo db which is useful to perform tests
2+
// More information: https://github.com/nodkz/mongodb-memory-server
3+
const mongodb = require('mongodb');
4+
const { MongoMemoryServer } = require('mongodb-memory-server');
5+
6+
// Set some fake projects to be uploaded
7+
const project1 = require('./project_1.json');
8+
const project2 = require('./project_2.json');
9+
const reference1 = require('./reference_1.json');
10+
const reference2 = require('./reference_2.json'); // entropies and epitopes removed for comodity
11+
12+
// Set up the fake server and return an available connection to this server
13+
// DANI: This has not been maintained in a while, expect problems when trying
14+
const establishFakeConnection = async () => {
15+
let client;
16+
try {
17+
// Create the server with a stablished port and dbname, so the connection string is always the same
18+
const mongod = await MongoMemoryServer.create({
19+
instance: { port: +process.env.DB_PORT, dbName: process.env.DB_NAME },
20+
});
21+
const connectionString = await mongod.getUri();
22+
client = await mongodb.MongoClient.connect(connectionString, {
23+
useUnifiedTopology: true,
24+
});
25+
//console.log(mongod.getInstanceInfo());
26+
// Add data to the server to simulate the MoDEL structure
27+
const db = client.db(process.env.DB_NAME);
28+
const projects = await db.createCollection('projects');
29+
await projects.insertOne(project1);
30+
await projects.insertOne(project2);
31+
const references = await db.createCollection('references');
32+
await references.insertOne(reference1);
33+
await references.insertOne(reference2);
34+
await db.createCollection('topologies');
35+
return client;
36+
} catch (error) {
37+
console.error('fake mongodb connection error');
38+
console.error(error);
39+
if (client && 'close' in client) client.close();
40+
}
41+
};
42+
43+
module.exports = establishFakeConnection();

0 commit comments

Comments
 (0)