Skip to content

Commit fdc2bd9

Browse files
Merge pull request #523 from OHDSI/development
Release 0.6
2 parents f346173 + 2a78296 commit fdc2bd9

File tree

549 files changed

+26521
-11387
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

549 files changed

+26521
-11387
lines changed

backend/.env

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
PORT=3000
2+
DATABASE_PATH=./annotations.duckdb
3+
HOSTNAME='localhost'
4+
NODE_ENV=development

backend/main.js

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#!/usr/bin/env node
2+
import dotenv from 'dotenv';
3+
import app from "./src/app.js";
4+
import logger from "./src/utils/logger.js";
5+
import debug from "debug"
6+
import http from 'http';
7+
8+
dotenv.config();
9+
10+
let port = normalizePort(process.env.PORT || '3000');
11+
const hostName = process.env.HOSTNAME || 'localhost';
12+
13+
app.set('port', port);
14+
15+
let server = http.createServer(app);
16+
17+
server.listen(port, hostName, () => {
18+
logger.info(`Server running on ${hostName}:${port}, mode: ${process.env.NODE_ENV}`);
19+
});
20+
server.on('error', onError);
21+
server.on('listening', onListening);
22+
23+
function normalizePort(val) {
24+
const port = parseInt(val, 10);
25+
26+
if (isNaN(port)) {
27+
// named pipe
28+
return val;
29+
}
30+
31+
if (port >= 0) {
32+
// port number
33+
return port;
34+
}
35+
36+
return false;
37+
}
38+
39+
function onError(error) {
40+
if (error.syscall !== 'listen') {
41+
throw error;
42+
}
43+
44+
const bind = typeof port === 'string'
45+
? 'Pipe ' + port
46+
: 'Port ' + port;
47+
48+
switch (error.code) {
49+
case 'EACCES':
50+
console.error(bind + ' requires elevated privileges');
51+
process.exit(1);
52+
break;
53+
case 'EADDRINUSE':
54+
console.error(bind + ' is already in use');
55+
process.exit(1);
56+
break;
57+
default:
58+
throw error;
59+
}
60+
}
61+
62+
function onListening() {
63+
const addr = server.address();
64+
const bind = typeof addr === 'string'
65+
? 'pipe ' + addr
66+
: 'port ' + addr.port;
67+
debug('Listening on ' + bind);
68+
}
69+
70+
const shutdownHandler = (reason) => {
71+
logger.info(`${reason === 'SIGINT' ? 'Manual shutdown' : 'Forced shutdown'} initiated`);
72+
logger.info(`Server is shutting down...`);
73+
server.close(() => {
74+
logger.info('Server stopped.');
75+
process.exit(0);
76+
});
77+
};
78+
79+
process.on('SIGINT', shutdownHandler);
80+
process.on('SIGTERM', shutdownHandler);

backend/package.json

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"name": "ares-backend",
3+
"version": "0.1",
4+
"private": true,
5+
"scripts": {
6+
"start": "node ./main.js"
7+
},
8+
"type": "module",
9+
"dependencies": {
10+
"@duckdb/node-api": "^1.1.3-alpha.10",
11+
"cookie-parser": "~1.4.4",
12+
"cors": "^2.8.5",
13+
"debug": "~2.6.9",
14+
"dotenv": "^16.4.7",
15+
"express": "~4.16.1",
16+
"http-errors": "~1.6.3",
17+
"winston": "^3.17.0"
18+
}
19+
}

backend/src/app.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import createError from "http-errors"
2+
import express from "express"
3+
import cookieParser from "cookie-parser"
4+
import cors from "cors"
5+
6+
import dbInstance from "./config/dbConnection.js";
7+
import logger from "./utils/logger.js"
8+
import indexRouter from "./routes/annotationRoutes.js"
9+
import initAnnotationTables from "./config/initAnnotationTables.js";
10+
import "./config/dbConnection.js"
11+
import "./controllers/annotationsController.js"
12+
13+
const app = express();
14+
15+
app.use((req, res, next) => {
16+
logger.http(`Request: ${req.method} ${req.url}`);
17+
next();
18+
});
19+
app.use(express.json());
20+
app.use(express.urlencoded({ extended: false }));
21+
app.use(cookieParser());
22+
23+
app.use(cors())
24+
25+
// app.use(express.static(path.join(__dirname, 'public')));
26+
27+
await initAnnotationTables(dbInstance)
28+
29+
app.use('/', indexRouter);
30+
31+
app.use(function(req, res, next) {
32+
next(createError(404));
33+
});
34+
35+
app.use(function(err, req, res, next) {
36+
res.locals.message = err.message;
37+
res.locals.error = req.app.get('env') === 'development' ? err : {};
38+
res.status(err.status || 500);
39+
res.render('error');
40+
});
41+
42+
export default app;

backend/src/config/dbConnection.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { DuckDBInstance } from '@duckdb/node-api';
2+
import dotenv from 'dotenv';
3+
4+
dotenv.config();
5+
6+
const dbInstance = await DuckDBInstance.create(process.env.DATABASE_PATH);
7+
8+
export default dbInstance;
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import logger from "../utils/logger.js";
2+
3+
const initAnnotationTables = async (instance) => {
4+
const connection = await instance.connect();
5+
const checkTableExists = async (tableName) => {
6+
const result = await connection.runAndReadAll(`
7+
SELECT COUNT(*) AS count
8+
FROM information_schema.tables
9+
WHERE table_name = '${tableName}';
10+
`);
11+
const rows = result.getRowObjects();
12+
13+
return rows[0].count;
14+
};
15+
16+
17+
const tablesExist = await checkTableExists('charts');
18+
19+
if (!tablesExist) {
20+
logger.info('Running for the first time. Initiating db.')
21+
await connection.run(`
22+
CREATE TABLE IF NOT EXISTS charts (
23+
id TEXT PRIMARY KEY,
24+
chart_id TEXT,
25+
chart_name TEXT,
26+
report_name TEXT,
27+
domain_name TEXT,
28+
concept_id TEXT
29+
);
30+
`);
31+
32+
await connection.run(`
33+
CREATE TABLE IF NOT EXISTS annotations (
34+
id TEXT PRIMARY KEY,
35+
viz_id TEXT REFERENCES charts(id),
36+
created_by TEXT,
37+
created_at TIMESTAMP,
38+
updated_at TIMESTAMP,
39+
deleted_at TIMESTAMP
40+
);
41+
`);
42+
43+
await connection.run(`
44+
CREATE TABLE IF NOT EXISTS annotations_coordinates (
45+
annotation_id TEXT REFERENCES annotations(id),
46+
xMin DOUBLE PRECISION,
47+
xMax DOUBLE PRECISION,
48+
yMin DOUBLE PRECISION,
49+
yMax DOUBLE PRECISION
50+
);
51+
`);
52+
53+
await connection.run(`
54+
CREATE TABLE IF NOT EXISTS annotations_metadata (
55+
annotation_id TEXT REFERENCES annotations(id),
56+
scope_type TEXT,
57+
scope_value JSON
58+
);
59+
`);
60+
61+
await connection.run(`
62+
CREATE TABLE IF NOT EXISTS annotations_body (
63+
annotation_id TEXT REFERENCES annotations(id),
64+
title TEXT,
65+
description TEXT
66+
);
67+
`);
68+
69+
await connection.run(`
70+
CREATE TABLE IF NOT EXISTS annotations_notes (
71+
note_id TEXT PRIMARY KEY,
72+
annotation_id TEXT REFERENCES annotations(id),
73+
title TEXT,
74+
description TEXT,
75+
created_at TIMESTAMP,
76+
updated_at TIMESTAMP,
77+
created_by TEXT,
78+
last_updated TIMESTAMP
79+
);
80+
`);
81+
}
82+
83+
connection.close();
84+
};
85+
86+
export default initAnnotationTables;

0 commit comments

Comments
 (0)