Skip to content

Commit 890d46f

Browse files
committed
PUT method support for updating metadata
1 parent 3bbd31a commit 890d46f

File tree

2 files changed

+103
-16
lines changed

2 files changed

+103
-16
lines changed

README.md

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ sudo docker run -d --rm --name nica-ems -p 80:8080 -v ./ems.config.yaml:/app/bin
6262

6363
### Methods supported
6464

65-
#### Get event metadata:
65+
#### Read event records (get event metadata):
6666
`GET /event_api/v1/event[?parameter1=value1[&parameter2=value2[...]]]`
6767

6868
Here and below, for parameter values we have
@@ -80,7 +80,7 @@ Here and below, for parameter values we have
8080
- `limit` (int)
8181
- `offset` (int)
8282

83-
* Any custom parameters specified in YAML file
83+
* Any custom parameters specified in YAML configuration file
8484

8585
Example:
8686
`http://127.0.0.1:8080/event_api/v1/event?limit=5&software_version=~19._&beam_particle=~A_&track_number=11|`
@@ -89,39 +89,54 @@ Example:
8989
#### Create event records in the metadata catalog (Writer or Admin role required):
9090
`POST /event_api/v1/event`
9191

92-
Message body must contain the JSON list of events using format as given below.
92+
Message body must contain the JSON list of events to be written, using format as given below. In case of any events
93+
already present, an error is returned and whole transaction is cancelled.
94+
95+
96+
#### Update event records in the metadata catalog (Writer or Admin role required):
97+
`PUT /event_api/v1/event`
98+
99+
Message body must contain the JSON list of events to be created or updated. The request succeeds even if some records
100+
are already present (if any parameters are different, they are updated).
101+
102+
103+
#### Delete event records from the metadata catalog (Admin role required)
104+
`DELETE /event_api/v1/event`
105+
106+
Message body must contain the JSON list of events (only `reference:` part is required, other fields are
107+
optional and ignored, if present).
108+
93109

94110
#### Read software records from dictionary
95111
`GET /event_api/v1/software`
96112

113+
97114
#### Create software record in dictionary
98115
`POST /event_api/v1/software`
99116

100117
Message body example `{"software_id": 100, "software_version": "22.11"}`
101118

119+
102120
#### Read storage records from dictionary
103121
`GET /event_api/v1/storage`
104122

123+
105124
#### Create storage record in dictionary
106125
`POST /event_api/v1/storage`
107126

108127
Message body example `{"storage_id": 100, "storage_name": "data1"}`
109128

110129

111-
#### Delete event records from the metadata catalog (Admin role required)
112-
`DELETE /event_api/v1/event`
113-
114-
Message body must contain the JSON list of events (only `reference:` part is required, other fields are
115-
optional and ignored, if present).
116-
117130
#### TODO: Count number of entries in EMS and return just this value
118131
`GET /count[?parameter1=value1[&parameter2=value2[...]]]`
119132

133+
120134
#### TODO: Get event records as a ROOT file (synchronous)
121135
`GET /event_api/v1/eventFile[?parameter1=value1[&parameter2=value2[...]]]`
122136

123137
File is built and downloaded immediately (same HTTP session)
124138

139+
125140
#### TODO: Get event records as a ROOT file reference (asynchronous)
126141
`GET /event_api/v1/eventFileRef[?parameter1=value1[&parameter2=value2[...]]]`
127142

src/jvmMain/kotlin/Application.kt

Lines changed: 79 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -329,14 +329,12 @@ fun Application.main() {
329329
}
330330

331331
post("/${EVENT_ENTITY_API_NAME}") {
332-
333332
val roles = call.principal<WithRoles>()?.roles!!
334333
// println("Roles in EVENT_ENTITY_API_NAME: $roles")
335334
if (!(roles.isWriter or roles.isAdmin)) {
336335
call.respond(HttpStatusCode.Unauthorized)
337336
return@post
338337
}
339-
340338
var connEMD: Connection? = null
341339
try {
342340
val events = call.receive<Array<EventRepr>>()
@@ -347,10 +345,8 @@ fun Application.main() {
347345
events.forEach { event ->
348346
println("Create event: $event")
349347
val software_id = softwareMap.str_to_id[event.software_version]
348+
val storage_id = storageMap.str_to_id[event.reference.storage_name]
350349
val file_path = event.reference.file_path
351-
val storage_name = event.reference.storage_name
352-
val storage_id = storageMap.str_to_id[storage_name]
353-
354350
val file_guid: Int
355351
val res = connEMD!!.createStatement().executeQuery(
356352
"""SELECT file_guid FROM file_ WHERE storage_id = $storage_id AND file_path = '$file_path'"""
@@ -367,7 +363,7 @@ fun Application.main() {
367363
res2.next()
368364
file_guid = res2.getInt("file_guid")
369365
}
370-
println("File GUID = $file_guid")
366+
println("File GUID for $file_path = $file_guid")
371367
val parameterValuesStr =
372368
page.parameters.joinToString(", ") {
373369
when (it.type.uppercase()) {
@@ -403,7 +399,83 @@ fun Application.main() {
403399
}
404400

405401
put("/${EVENT_ENTITY_API_NAME}") {
406-
TODO()
402+
val roles = call.principal<WithRoles>()?.roles!!
403+
if (!(roles.isWriter or roles.isAdmin)) {
404+
call.respond(HttpStatusCode.Unauthorized)
405+
return@put
406+
}
407+
var connEMD: Connection? = null
408+
try {
409+
val events = call.receive<Array<EventRepr>>()
410+
connEMD = newEMDConnection(config, this.context)
411+
connEMD!!.autoCommit = false
412+
val softwareMap = getSoftwareMap(connEMD!!)
413+
val storageMap = getStorageMap(connEMD!!)
414+
events.forEach { event ->
415+
println("Create or update event: $event")
416+
val software_id = softwareMap.str_to_id[event.software_version]
417+
val storage_id = storageMap.str_to_id[event.reference.storage_name]
418+
val file_path = event.reference.file_path
419+
val file_guid: Int
420+
val res = connEMD!!.createStatement().executeQuery(
421+
"""SELECT file_guid FROM file_ WHERE storage_id = $storage_id AND file_path = '$file_path'"""
422+
)
423+
if (res.next()) { // file record already exists
424+
file_guid = res.getInt("file_guid")
425+
} else { // create file record
426+
val fileQuery = """INSERT INTO file_ (storage_id, file_path) VALUES ($storage_id, '$file_path')"""
427+
println(fileQuery)
428+
connEMD!!.createStatement().executeUpdate(fileQuery)
429+
val res2 = connEMD!!.createStatement().executeQuery(
430+
"""SELECT file_guid FROM file_ WHERE storage_id = $storage_id AND file_path = '$file_path'"""
431+
)
432+
res2.next()
433+
file_guid = res2.getInt("file_guid")
434+
}
435+
println("File GUID for $file_path = $file_guid")
436+
val parameterValuesStr =
437+
page.parameters.joinToString(", ") {
438+
when (it.type.uppercase()) {
439+
"STRING" -> "'" + event.parameters[it.name].toString() + "'"
440+
else -> event.parameters[it.name].toString()
441+
}
442+
}
443+
val parameterNamesEqValuesStr =
444+
page.parameters.joinToString(", ") {
445+
when (it.type.uppercase()) {
446+
"STRING" -> "${it.name}='${event.parameters[it.name].toString()}'"
447+
else -> "${it.name}=${event.parameters[it.name].toString()}"
448+
}
449+
}
450+
val query = """
451+
INSERT INTO ${page.db_table_name}
452+
(file_guid, event_number, software_id, period_number, run_number,
453+
${page.parameters.joinToString(", ") { it.name }})
454+
VALUES ($file_guid, ${event.reference.event_number}, $software_id, ${event.period_number},
455+
${event.run_number}, $parameterValuesStr)
456+
ON CONFLICT (file_guid, event_number) DO UPDATE SET
457+
software_id=$software_id, period_number=${event.period_number}, run_number=${event.run_number},
458+
$parameterNamesEqValuesStr
459+
""".trimIndent()
460+
println(query)
461+
val res3 = connEMD!!.createStatement().executeUpdate(query)
462+
println("res of update is $res3")
463+
}
464+
connEMD!!.commit()
465+
call.respond(HttpStatusCode.OK, "Success: ${events.size} event(s) were put")
466+
} catch (err: PSQLException) {
467+
if (err.toString().contains("The connection attempt failed.")) {
468+
call.respond(HttpStatusCode.ServiceUnavailable, "Database connection failed: $err")
469+
} else {
470+
call.respond(HttpStatusCode.Conflict, "Database error: $err")
471+
}
472+
} catch (err: BadRequestException) {
473+
call.respond(HttpStatusCode.UnprocessableEntity, "Error processing content: $err")
474+
} catch (err: Exception) {
475+
call.respond(HttpStatusCode.InternalServerError, "Error writing event data: $err")
476+
} finally {
477+
connEMD?.close()
478+
}
407479
}
408480

409481
delete("/${EVENT_ENTITY_API_NAME}") {

0 commit comments

Comments
 (0)