-
Notifications
You must be signed in to change notification settings - Fork 6
/
patch-session.js
124 lines (101 loc) · 4.53 KB
/
patch-session.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
const {send, json} = require("micro")
const cors = require("micro-cors")()
const fjp = require("fast-json-patch")
const hash = require("../../utils/hash.js")
const error = require("../../utils/error")
const getDB = require('../db')
const db = getDB({databasePath: 'udt.db', verbose: null})
module.exports = cors(async (req, res) => {
if (req.method === "OPTIONS") return send(res, 200, "ok")
const body = await json(req)
const sessionId = req.params.session_id
if (!body) return error(res, 400, "Need JSON body")
if (!body.patch) return error(res, 400, `Body should have "patch" key`)
const session = db.prepare('SELECT * FROM latest_session_state WHERE short_id = ? LIMIT 1').get(sessionId);
if (!session) return error(res, 404, "Session Not Found")
const samplePatches = body.patch.filter(patch => patch.path.includes('/samples'))
const udtPatches = body.patch.filter(patch => !patch.path.includes('/samples'))
let newJSON = {...JSON.parse(session.udt_json)}
fjp.applyPatch(newJSON, udtPatches)
await patchSamples(session.short_id, samplePatches)
const latestVersion = session.version + 1
const insertStmt = db.prepare(`
INSERT INTO session_state
(previous_session_state_id, short_id, user_name, patch, version, udt_json)
VALUES (?, ?, ?, ?, ?, ?)`);
insertStmt.run(
session.session_state_id,
sessionId,
body.userName || null,
JSON.stringify(body.patch),
latestVersion,
JSON.stringify(newJSON)
);
return send(res, 200, {latestVersion, hashOfLatestState: hash(newJSON)})
})
const patchCreateSamples = (async (sessionId, samplesToAdd) => {
const samplesQueries = []
if (samplesToAdd.length) {
let sessionSampleId = -1
const latestSample = db.prepare('SELECT * FROM sample_state WHERE session_short_id = ? ORDER BY session_sample_id DESC LIMIT 1').get(sessionId);
if (latestSample) {
sessionSampleId = parseInt(latestSample.session_sample_id)
}
samplesToAdd.forEach((sample) => {
sessionSampleId += 1
samplesQueries.push(db.prepare('INSERT INTO sample_state (session_short_id, session_sample_id, content) VALUES (?, ?, ?)').run(sessionId, sessionSampleId, JSON.stringify(sample)));
})
}
return samplesQueries
})
const patchSamplesAnnotation = (async (sessionId, samplePatches) => {
const sampleIds = {}
samplePatches.forEach(patch => {
const pathArray = patch.path.split('/')
const sessionSampleId = pathArray[2]
sampleIds[sessionSampleId] = {sessionSampleId}
})
const samplesArray = []
const samples = db.prepare('SELECT * FROM latest_sample_state WHERE session_short_id = ? ORDER BY session_sample_id ASC').all(sessionId);
samples.forEach(sample => {
const content = JSON.parse(sample.content)
const annotation = JSON.parse(sample.annotation)
samplesArray.push({
...content,
annotation: annotation,
version: parseInt(sample.version),
session_sample_id: sample.session_sample_id
})
})
let newJSON = {samples: samplesArray}
fjp.applyPatch(newJSON, samplePatches)
const queries = []
Object.keys(sampleIds).forEach(sampleId => {
const sample = samplesArray[sampleId]
const session_sample_id = sample.session_sample_id
const version = sample.version + 1
const annotation = sample.annotation
delete sample.session_sample_id
delete sample.version
delete sample.annotation
queries.push(
db.prepare('INSERT INTO sample_state (session_short_id, session_sample_id, version, annotation, content) VALUES (?, ?, ?, ?, ?)')
.run(sessionId, session_sample_id, version, JSON.stringify(annotation), JSON.stringify(sample)));
})
return queries
})
const patchSamples = (async (sessionId, samplePatches) => {
const samplesToAdd = []
const samplesAnnotationPatches = []
samplePatches.forEach(patch => {
if (patch.op === 'add' && patch.path === '/samples/-') {
samplesToAdd.push(patch.value)
}
if (/samples\/[0-9]*\/annotation/.test(patch.path)) {
samplesAnnotationPatches.push(patch)
}
})
const patchCreateSamplesQuery = await patchCreateSamples(sessionId, samplesToAdd)
const patchSamplesAnnotationQueries = await patchSamplesAnnotation(sessionId, samplesAnnotationPatches)
await Promise.all([...patchCreateSamplesQuery, ...patchSamplesAnnotationQueries])
})