diff --git a/adapter/adapter-service/src/main/scala/net/shrine/adapter/dao/model/ShrineQuery.scala b/adapter/adapter-service/src/main/scala/net/shrine/adapter/dao/model/ShrineQuery.scala
index 2d167dd0c..a851498b4 100644
--- a/adapter/adapter-service/src/main/scala/net/shrine/adapter/dao/model/ShrineQuery.scala
+++ b/adapter/adapter-service/src/main/scala/net/shrine/adapter/dao/model/ShrineQuery.scala
@@ -1,37 +1,35 @@
package net.shrine.adapter.dao.model
import javax.xml.datatype.XMLGregorianCalendar
import net.shrine.protocol.query.QueryDefinition
import net.shrine.protocol.QueryMaster
/**
* @author clint
* @since Oct 16, 2012
*
* NB: Can't be final, since Squeryl runs this class through cglib to make a synthetic subclass :(
*/
final case class ShrineQuery(
id: Int,
localId: String,
networkId: Long,
name: String,
username: String,
domain: String,
dateCreated: XMLGregorianCalendar,
isFlagged: Boolean,
- hasBeenRun: Boolean,
+ hasBeenRun: Boolean, //todo this goes next
flagMessage: Option[String],
queryDefinition: QueryDefinition) {
def hasNotBeenRun: Boolean = !hasBeenRun
def withName(newName: String): ShrineQuery = this.copy(name = newName)
//NB: Due to the new i2b2 admin previous queries API, we need to be able to transform
//ourselves into a QueryMaster using either the network or local id .
def toQueryMaster(idField: ShrineQuery => String = _.networkId.toString): QueryMaster = {
- val held = hasNotBeenRun
-
- QueryMaster(idField(this), networkId, name, username, domain, dateCreated, Some(held), Some(isFlagged), if(isFlagged) flagMessage else None)
+ QueryMaster(idField(this), networkId, name, username, domain, dateCreated, Some(isFlagged), if(isFlagged) flagMessage else None)
}
}
diff --git a/adapter/adapter-service/src/test/scala/net/shrine/adapter/AdapterTestHelpers.scala b/adapter/adapter-service/src/test/scala/net/shrine/adapter/AdapterTestHelpers.scala
index 96087d8f9..917b3056e 100644
--- a/adapter/adapter-service/src/test/scala/net/shrine/adapter/AdapterTestHelpers.scala
+++ b/adapter/adapter-service/src/test/scala/net/shrine/adapter/AdapterTestHelpers.scala
@@ -1,54 +1,54 @@
package net.shrine.adapter
import net.shrine.protocol.AuthenticationInfo
import net.shrine.protocol.Credential
import net.shrine.protocol.QueryMaster
import net.shrine.protocol.query.QueryDefinition
import net.shrine.protocol.query.Term
import net.shrine.util.XmlDateHelper
/**
* @author clint
- * @date Nov 28, 2012
+ * @since Nov 28, 2012
*/
trait AdapterTestHelpers {
val queryId = 123
val localMasterId = "kasjdlsajdklajsdkljasd"
val bogusQueryId = 999
val masterId1 = "1"
val masterId2 = "2"
val masterId3 = "3"
val masterId4 = "4"
val networkQueryId1 = 1L
val networkQueryId2 = 2L
val networkQueryId3 = 3L
val networkQueryId4 = 4L
val queryName1 = "query-name1"
val queryName2 = "query-name2"
lazy val queryDef1 = QueryDefinition(queryName1, Term("x"))
lazy val queryDef2 = QueryDefinition(queryName2, Term("y"))
val userId = "some-other-user"
val domain = "Some-other-domain"
val anotherDomain = "some-completely-different-domain"
val password = "some-val"
- lazy val authn = AuthenticationInfo(domain, userId, Credential(password, false))
- lazy val authn2 = AuthenticationInfo(authn.domain, "a-different-user", Credential("jkafhkjdhsfjksdhfkjsdg", false))
+ lazy val authn = AuthenticationInfo(domain, userId, Credential(password, isToken = false))
+ lazy val authn2 = AuthenticationInfo(authn.domain, "a-different-user", Credential("jkafhkjdhsfjksdhfkjsdg", isToken = false))
val projectId = "some-project-id"
import scala.concurrent.duration._
val waitTime = 12345.milliseconds
- lazy val queryMaster1 = QueryMaster(masterId1, networkQueryId1, queryName1, userId, domain, XmlDateHelper.now, held = Some(false), flagged = Some(true))
- lazy val queryMaster2 = QueryMaster(masterId2, networkQueryId2, queryName2, userId, domain, XmlDateHelper.now, held = Some(false), flagged = Some(false))
- lazy val queryMaster4 = QueryMaster(masterId4, networkQueryId4, queryName2, authn2.username, anotherDomain, XmlDateHelper.now, held = Some(false), flagged = Some(true))
+ lazy val queryMaster1 = QueryMaster(masterId1, networkQueryId1, queryName1, userId, domain, XmlDateHelper.now, flagged = Some(true))
+ lazy val queryMaster2 = QueryMaster(masterId2, networkQueryId2, queryName2, userId, domain, XmlDateHelper.now, flagged = Some(false))
+ lazy val queryMaster4 = QueryMaster(masterId4, networkQueryId4, queryName2, authn2.username, anotherDomain, XmlDateHelper.now, flagged = Some(true))
}
\ No newline at end of file
diff --git a/adapter/adapter-service/src/test/scala/net/shrine/adapter/service/AbstractI2b2AdminResourceJaxrsTest.scala b/adapter/adapter-service/src/test/scala/net/shrine/adapter/service/AbstractI2b2AdminResourceJaxrsTest.scala
index 45636c915..8d65f28d7 100644
--- a/adapter/adapter-service/src/test/scala/net/shrine/adapter/service/AbstractI2b2AdminResourceJaxrsTest.scala
+++ b/adapter/adapter-service/src/test/scala/net/shrine/adapter/service/AbstractI2b2AdminResourceJaxrsTest.scala
@@ -1,117 +1,101 @@
package net.shrine.adapter.service
-import scala.xml.XML
-import org.junit.After
-import org.junit.Before
-import net.shrine.util.ShouldMatchersForJUnit
+import junit.framework.TestCase
import net.shrine.adapter.AdapterTestHelpers
import net.shrine.adapter.dao.squeryl.AbstractSquerylAdapterTest
-import net.shrine.client.HttpClient
-import net.shrine.client.HttpResponse
-import net.shrine.client.JerseyHttpClient
-import net.shrine.protocol.ErrorResponse
-import net.shrine.protocol.QueryMaster
-import net.shrine.protocol.ReadI2b2AdminPreviousQueriesRequest
-import net.shrine.protocol.ReadPreviousQueriesResponse
-import net.shrine.protocol.ReadQueryDefinitionRequest
-import net.shrine.protocol.ReadQueryDefinitionResponse
-import net.shrine.protocol.query.QueryDefinition
-import net.shrine.util.XmlUtil
+import net.shrine.client.{HttpClient, HttpResponse, JerseyHttpClient}
import net.shrine.crypto.TrustParam.AcceptAllCerts
-import net.shrine.protocol.I2b2AdminRequestHandler
-import net.shrine.protocol.I2b2AdminReadQueryDefinitionRequest
-import junit.framework.TestCase
-import net.shrine.protocol.DefaultBreakdownResultOutputTypes
+import net.shrine.protocol.{DefaultBreakdownResultOutputTypes, ErrorResponse, I2b2AdminReadQueryDefinitionRequest, I2b2AdminRequestHandler, QueryMaster, ReadI2b2AdminPreviousQueriesRequest, ReadPreviousQueriesResponse, ReadQueryDefinitionResponse}
+import net.shrine.protocol.query.QueryDefinition
+import net.shrine.util.{ShouldMatchersForJUnit, XmlUtil}
+import org.junit.{After, Before}
+
+import scala.xml.XML
/**
* @author clint
- * @date Apr 24, 2013
+ * @since Apr 24, 2013
*/
abstract class AbstractI2b2AdminResourceJaxrsTest extends TestCase with JerseyTestComponent[I2b2AdminRequestHandler] with AbstractSquerylAdapterTest with ShouldMatchersForJUnit with CanLoadTestData with AdapterTestHelpers {
import scala.concurrent.duration._
protected def adminClient = I2b2AdminClient(resourceUrl, JerseyHttpClient(AcceptAllCerts, 5.minutes))
override def resourceClass(handler: I2b2AdminRequestHandler) = I2b2AdminResource(handler, DefaultBreakdownResultOutputTypes.toSet)
override val basePath = "i2b2/admin/request"
@Before
override def setUp(): Unit = this.JerseyTest.setUp()
@After
override def tearDown(): Unit = this.JerseyTest.tearDown()
protected object NeverAuthenticatesMockPmHttpClient extends HttpClient {
override def post(input: String, url: String): HttpResponse = HttpResponse.ok(ErrorResponse("blarg").toI2b2String)
}
protected object AlwaysAuthenticatesMockPmHttpClient extends HttpClient {
override def post(input: String, url: String): HttpResponse = {
HttpResponse.ok(XmlUtil.stripWhitespace {
Some user
{ userId }
{ domain }
{ password }
MANAGER
}.toString)
}
}
protected def doTestReadQueryDefinition(networkQueryId: Long, expectedQueryNameAndQueryDef: Option[(String, QueryDefinition)]) {
val request = I2b2AdminReadQueryDefinitionRequest(projectId, waitTime, authn, networkQueryId)
- val currentHandler = handler
-
val resp = adminClient.readQueryDefinition(request)
def stripNamespaces(s: String) = XmlUtil.stripNamespaces(XML.loadString(s))
expectedQueryNameAndQueryDef match {
case Some((expectedQueryName, expectedQueryDef)) => {
val response @ ReadQueryDefinitionResponse(masterId, name, userId, createDate, queryDefinition) = resp
masterId should be(networkQueryId)
name should be(expectedQueryName)
userId should be(authn.username)
createDate should not be (null)
//NB: I'm not sure why whacky namespaces were coming back from the resource;
//this checks that the gist of the queryDef XML makes it back.
//TODO: revisit this
stripNamespaces(queryDefinition) should equal(stripNamespaces(expectedQueryDef.toI2b2String))
}
case None => resp.isInstanceOf[ErrorResponse] should be(true)
}
}
protected def doTestReadI2b2AdminPreviousQueries(request: ReadI2b2AdminPreviousQueriesRequest, expectedQueryMasters: Seq[QueryMaster]) {
- val currentHandler = handler
-
val ReadPreviousQueriesResponse(queryMasters) = adminClient.readI2b2AdminPreviousQueries(request)
if(expectedQueryMasters.isEmpty) { queryMasters.isEmpty should be(true) }
else {
(queryMasters zip expectedQueryMasters).foreach { case (queryMaster, expected) =>
queryMaster.createDate should not be(null)
queryMaster.name should equal(expected.name)
queryMaster.queryMasterId should equal(expected.queryMasterId)
queryMaster.userId should equal(expected.userId)
queryMaster.groupId should equal(expected.groupId)
queryMaster.flagged should equal(expected.flagged)
- queryMaster.held should equal(expected.held)
}
}
}
}
\ No newline at end of file
diff --git a/adapter/adapter-service/src/test/scala/net/shrine/adapter/service/I2b2AdminResourceJaxrsTest.scala b/adapter/adapter-service/src/test/scala/net/shrine/adapter/service/I2b2AdminResourceJaxrsTest.scala
index 7e35931e4..c58f32baa 100644
--- a/adapter/adapter-service/src/test/scala/net/shrine/adapter/service/I2b2AdminResourceJaxrsTest.scala
+++ b/adapter/adapter-service/src/test/scala/net/shrine/adapter/service/I2b2AdminResourceJaxrsTest.scala
@@ -1,213 +1,194 @@
package net.shrine.adapter.service
+import com.sun.jersey.test.framework.{AppDescriptor, JerseyTest}
+import net.shrine.adapter.service.I2b2AdminResourceJaxrsTest._
+import net.shrine.client.JerseyHttpClient
+import net.shrine.crypto.TrustParam.AcceptAllCerts
import net.shrine.problem.TestProblem
+import net.shrine.protocol.{AbstractReadQueryDefinitionRequest, AuthenticationInfo, Credential, DefaultBreakdownResultOutputTypes, I2b2AdminReadQueryDefinitionRequest, I2b2AdminRequestHandler, I2b2AdminUserWithRole, QueryMaster, QueryResult, ReadI2b2AdminPreviousQueriesRequest, ReadI2b2AdminQueryingUsersRequest, ReadI2b2AdminQueryingUsersResponse, ReadPreviousQueriesResponse, ReadQueryDefinitionResponse, RunHeldQueryRequest, RunQueryResponse, ShrineResponse}
+import net.shrine.protocol.query.{QueryDefinition, Term}
+import net.shrine.util.{JerseyAppDescriptor, ShouldMatchersForJUnit, XmlDateHelper, XmlUtil}
+import org.junit.{After, Before, Test}
import scala.xml.XML
-import org.junit.Test
-import net.shrine.util.ShouldMatchersForJUnit
-import com.sun.jersey.test.framework.AppDescriptor
-import com.sun.jersey.test.framework.JerseyTest
-import I2b2AdminResourceJaxrsTest._
-import net.shrine.client.JerseyHttpClient
-import net.shrine.protocol.AuthenticationInfo
-import net.shrine.protocol.Credential
-import net.shrine.protocol.I2b2AdminRequestHandler
-import net.shrine.protocol.QueryMaster
-import net.shrine.protocol.ReadI2b2AdminPreviousQueriesRequest
-import net.shrine.protocol.ReadI2b2AdminPreviousQueriesRequest
-import net.shrine.protocol.ReadPreviousQueriesResponse
-import net.shrine.protocol.ReadQueryDefinitionRequest
-import net.shrine.protocol.ReadQueryDefinitionResponse
-import net.shrine.protocol.ShrineResponse
-import net.shrine.protocol.query.QueryDefinition
-import net.shrine.protocol.query.Term
-import net.shrine.util.JerseyAppDescriptor
-import net.shrine.util.XmlDateHelper
-import net.shrine.util.XmlUtil
-import net.shrine.crypto.TrustParam.AcceptAllCerts
-import net.shrine.protocol.ReadI2b2AdminQueryingUsersRequest
-import net.shrine.protocol.I2b2AdminUserWithRole
-import net.shrine.protocol.ReadI2b2AdminQueryingUsersResponse
-import net.shrine.protocol.I2b2AdminReadQueryDefinitionRequest
-import net.shrine.protocol.AbstractReadQueryDefinitionRequest
-import net.shrine.protocol.RunHeldQueryRequest
-import net.shrine.protocol.RunQueryResponse
-import net.shrine.protocol.QueryResult
-import junit.framework.TestCase
-import org.junit.Before
-import org.junit.After
-import net.shrine.protocol.DefaultBreakdownResultOutputTypes
-import net.shrine.protocol.ShrineRequestHandler
/**
* @author clint
- * @date Apr 10, 2013
+ * @since Apr 10, 2013
*/
+//noinspection ScalaUnnecessaryParentheses
final class I2b2AdminResourceJaxrsTest extends JerseyTest with ShouldMatchersForJUnit {
var handler: MockShrineRequestHandler = _
def resourceUrl = resource.getURI.toString + "i2b2/admin/request"
override def configure: AppDescriptor = {
JerseyAppDescriptor.thatCreates((h: I2b2AdminRequestHandler) => I2b2AdminResource(h, DefaultBreakdownResultOutputTypes.toSet)).using {
handler = new MockShrineRequestHandler
handler
}
}
@Before
override def setUp(): Unit = super.setUp()
@After
override def tearDown(): Unit = super.tearDown()
import scala.concurrent.duration._
def adminClient = I2b2AdminClient(resourceUrl, new JerseyHttpClient(AcceptAllCerts, 5.minutes))
@Test
- def testReadQueryDefinition {
+ def testReadQueryDefinition() {
val queryId = 987654321L
val request = I2b2AdminReadQueryDefinitionRequest(projectId, waitTime, authn, queryId)
val currentHandler = handler
val response = adminClient.readQueryDefinition(request).asInstanceOf[ReadQueryDefinitionResponse]
response should not be(null)
response.masterId should equal(queryId)
response.name should equal("some-query-name")
response.createDate should not be(null)
response.userId should equal(authn.username)
def stripNamespaces(s: String) = XmlUtil.stripNamespaces(XML.loadString(s))
//NB: I'm not sure why whacky namespaces were coming back from the resource;
//this checks that the gist of the queryDef XML makes it back.
//TODO: revisit this
stripNamespaces(response.queryDefinition) should equal(stripNamespaces(queryDef.toI2b2String))
currentHandler.shouldBroadcastParam should be(false)
currentHandler.readI2b2AdminPreviousQueriesParam should be(null)
currentHandler.readQueryDefinitionParam should equal(request)
}
@Test
- def testReadI2b2AdminPreviousQueries {
+ def testReadI2b2AdminPreviousQueries() {
val searchString = "asdk;laskd;lask;gdjsg"
val maxResults = 123
val sortOrder = ReadI2b2AdminPreviousQueriesRequest.SortOrder.Ascending
val categoryToSearchWithin = ReadI2b2AdminPreviousQueriesRequest.Category.All
val searchStrategy = ReadI2b2AdminPreviousQueriesRequest.Strategy.Exact
import ReadI2b2AdminPreviousQueriesRequest.Username._
val request = ReadI2b2AdminPreviousQueriesRequest(projectId, waitTime, authn, Exactly("@"), searchString, maxResults, None, sortOrder, searchStrategy, categoryToSearchWithin)
val currentHandler = handler
val response = adminClient.readI2b2AdminPreviousQueries(request).asInstanceOf[ReadPreviousQueriesResponse]
response should not be(null)
response.queryMasters should equal(Seq(queryMaster))
currentHandler.shouldBroadcastParam should be(false)
currentHandler.readI2b2AdminPreviousQueriesParam should be(request)
currentHandler.readQueryDefinitionParam should be(null)
}
@Test
- def testReadI2b2QueryingUsers {
+ def testReadI2b2QueryingUsers() {
val projectIdToSearchFor = "foo-project-id"
val request = ReadI2b2AdminQueryingUsersRequest(projectId, waitTime, authn, projectIdToSearchFor)
val currentHandler = handler
val response = adminClient.readI2b2AdminQueryingUsers(request).asInstanceOf[ReadI2b2AdminQueryingUsersResponse]
response should not be(null)
response.users should equal(users)
currentHandler.shouldBroadcastParam should be(false)
currentHandler.readI2b2AdminPreviousQueriesParam should be(null)
currentHandler.readI2b2AdminQueryingUsersParam should be(request)
currentHandler.readQueryDefinitionParam should be(null)
}
}
object I2b2AdminResourceJaxrsTest {
private val queryDef = QueryDefinition("foo", Term("x"))
private val userId = "some-user-id"
private val domain = "some-domain"
private lazy val authn = new AuthenticationInfo(domain, userId, new Credential("some-val", false))
private val projectId = "some-project-id"
import scala.concurrent.duration._
private val waitTime = 12345.milliseconds
- private lazy val queryMaster = QueryMaster("queryMasterId", 123456789L, "name", userId, domain, XmlDateHelper.now, Some(true), Some(true))
+ private lazy val queryMaster = QueryMaster(
+ queryMasterId = "queryMasterId",
+ networkQueryId = 123456789L,
+ name = "name",
+ userId = userId,
+ groupId = domain,
+ createDate = XmlDateHelper.now,
+ flagged = Some(true))
private lazy val users = Seq(
I2b2AdminUserWithRole("projectId1", "joe user", "some important role"),
I2b2AdminUserWithRole("projectId2", "jane user", "some other important role"),
I2b2AdminUserWithRole("projectId3", "some user", "some super important role"))
/**
* Mock ShrineRequestHandler; stores passed parameters for later inspection.
* Private, since this is (basically) the enclosing test class's state
*/
final class MockShrineRequestHandler extends I2b2AdminRequestHandler {
private val lock = new AnyRef
def shouldBroadcastParam = lock.synchronized(_shouldBroadcastParam)
def readQueryDefinitionParam = lock.synchronized(_readQueryDefinitionParam)
def readI2b2AdminPreviousQueriesParam = lock.synchronized(_readI2b2AdminPreviousQueriesParam)
def readI2b2AdminQueryingUsersParam = lock.synchronized(_readI2b2AdminQueryingUsersParam)
def runHeldQueryParam = lock.synchronized(_runHeldQueryParam)
private var _shouldBroadcastParam = false
private var _readQueryDefinitionParam: AbstractReadQueryDefinitionRequest = _
private var _readI2b2AdminPreviousQueriesParam: ReadI2b2AdminPreviousQueriesRequest = _
private var _readI2b2AdminQueryingUsersParam: ReadI2b2AdminQueryingUsersRequest = _
private var _runHeldQueryParam: RunHeldQueryRequest = _
override def readI2b2AdminPreviousQueries(request: ReadI2b2AdminPreviousQueriesRequest, shouldBroadcast: Boolean): ShrineResponse = setShouldBroadcastAndThen(shouldBroadcast) {
lock.synchronized { _readI2b2AdminPreviousQueriesParam = request }
ReadPreviousQueriesResponse(Seq(queryMaster))
}
override def readI2b2AdminQueryingUsers(request: ReadI2b2AdminQueryingUsersRequest, shouldBroadcast: Boolean): ShrineResponse = setShouldBroadcastAndThen(shouldBroadcast) {
lock.synchronized { _readI2b2AdminQueryingUsersParam = request }
ReadI2b2AdminQueryingUsersResponse(users)
}
override def readQueryDefinition(request: I2b2AdminReadQueryDefinitionRequest, shouldBroadcast: Boolean): ShrineResponse = setShouldBroadcastAndThen(shouldBroadcast) {
lock.synchronized { _readQueryDefinitionParam = request }
ReadQueryDefinitionResponse(request.queryId, "some-query-name", request.authn.username, XmlDateHelper.now, queryDef.toI2b2String)
}
override def runHeldQuery(request: RunHeldQueryRequest, shouldBroadcast: Boolean): ShrineResponse = {
lock.synchronized { _runHeldQueryParam = request }
RunQueryResponse(request.networkQueryId, XmlDateHelper.now, request.authn.username, request.projectId, QueryDefinition("bogus", Term("placeholder")), 12345L, QueryResult.errorResult(Some("foo"), "not actually an error",TestProblem))
}
private def setShouldBroadcastAndThen(shouldBroadcast: Boolean)(f: => ShrineResponse): ShrineResponse = {
try { f } finally {
lock.synchronized { _shouldBroadcastParam = shouldBroadcast }
}
}
}
}
\ No newline at end of file
diff --git a/commons/protocol/src/main/scala/net/shrine/protocol/QueryMaster.scala b/commons/protocol/src/main/scala/net/shrine/protocol/QueryMaster.scala
index 2caea9b9a..ceb47358b 100644
--- a/commons/protocol/src/main/scala/net/shrine/protocol/QueryMaster.scala
+++ b/commons/protocol/src/main/scala/net/shrine/protocol/QueryMaster.scala
@@ -1,24 +1,24 @@
package net.shrine.protocol
import javax.xml.datatype.XMLGregorianCalendar
/**
* @author Bill Simons
* @since 4/2/12
* @see http://cbmi.med.harvard.edu
* @see http://chip.org
*
* NOTICE: This software comes with NO guarantees whatsoever and is
* licensed as Lgpl Open Source
* @see http://www.gnu.org/licenses/lgpl.html
*/
final case class QueryMaster (
queryMasterId: String, //Outside of tests, this is always the networkQueryId as a string
networkQueryId: Long,
name: String,
userId: String,
groupId: String,
createDate: XMLGregorianCalendar,
- held: Option[Boolean] = None, //todo field should be removed, along with supporting code and tests. It's never used.
+// held: Option[Boolean] = None, //todo field should be removed, along with supporting code and tests. It's never used.
flagged: Option[Boolean] = None,
flagMessage: Option[String] = None)
\ No newline at end of file
diff --git a/commons/protocol/src/main/scala/net/shrine/protocol/ReadPreviousQueriesResponse.scala b/commons/protocol/src/main/scala/net/shrine/protocol/ReadPreviousQueriesResponse.scala
index b738dce6e..0157f9f74 100644
--- a/commons/protocol/src/main/scala/net/shrine/protocol/ReadPreviousQueriesResponse.scala
+++ b/commons/protocol/src/main/scala/net/shrine/protocol/ReadPreviousQueriesResponse.scala
@@ -1,112 +1,109 @@
package net.shrine.protocol
import xml.NodeSeq
import net.shrine.util.{Tries, XmlUtil, XmlDateHelper, NodeSeqEnrichments}
import net.shrine.serialization.{ I2b2Unmarshaller, XmlUnmarshaller }
import scala.util.Try
/**
* @author Bill Simons
* @since 4/11/11
* @see http://cbmi.med.harvard.edu
* @see http://chip.org
*
* NOTICE: This software comes with NO guarantees whatsoever and is
* licensed as Lgpl Open Source
* @see http://www.gnu.org/licenses/lgpl.html
*
* NB: this is a case class to get a structural equality contract in hashCode and equals, mostly for testing
*/
final case class ReadPreviousQueriesResponse(queryMasters: Seq[QueryMaster]) extends ShrineResponse {
override def i2b2MessageBody: NodeSeq = XmlUtil.stripWhitespace {
DONE
{
for {
master <- queryMasters
} yield {
{ master.queryMasterId }
{ master.networkQueryId }
{ master.name }
{ master.userId }
{ master.groupId }
{ master.createDate }
- { master.held.map(f => { f }).orNull }
{ master.flagged.map(f => { f }).orNull }
{ master.flagMessage.map(f => { f }).orNull }
}
}
}
override def toXml: NodeSeq = XmlUtil.stripWhitespace {
{
queryMasters.map { master =>
{ master.queryMasterId }
{ master.networkQueryId }
{ master.name }
{ master.createDate }
{ master.userId }
{ master.groupId }
- { master.held.map(f => { f }).orNull }
{ master.flagged.map(f => { f }).orNull }
{ master.flagMessage.map(f => { f }).orNull }
}
}
}
}
object ReadPreviousQueriesResponse extends I2b2Unmarshaller[ReadPreviousQueriesResponse] with XmlUnmarshaller[ReadPreviousQueriesResponse] {
override def fromI2b2(xml: NodeSeq): ReadPreviousQueriesResponse = {
//NB: Fail fast
require((xml \ "response_header" \ "result_status" \ "status" \ "@type").text == "DONE")
doFromXml("query_master_id", "network_query_id", "name", "user_id", "group_id", "create_date", "held", "flagged", "flagMessage")(xml \ "message_body" \ "response" \ "query_master")
}
override def fromXml(xml: NodeSeq): ReadPreviousQueriesResponse = doFromXml("masterId", "networkId", "name", "userId", "groupId", "createDate", "held", "flagged", "flagMessage")(xml \ "queryMaster")
private[this] def doFromXml(queryMasterIdTagName: String, networkQueryIdTagName: String, nameTagName: String, userIdTagName: String, groupIdTagName: String, createDateTagName: String, heldTagName: String, flaggedTagName: String, flagMessageTagName: String)(xml: NodeSeq): ReadPreviousQueriesResponse = {
val toQueryMaster = queryMasterExtractor(queryMasterIdTagName, networkQueryIdTagName, nameTagName, userIdTagName, groupIdTagName, createDateTagName, heldTagName, flaggedTagName, flagMessageTagName)
val queryMasterAttempts = xml.map(toQueryMaster)
//NB: Preserve old exception-throwing behavior for now
val queryMasters = Tries.sequence(queryMasterAttempts).get
ReadPreviousQueriesResponse(queryMasters)
}
import NodeSeqEnrichments.Strictness._
private[this] val toText = (_: NodeSeq).text.trim
private[this] val toLong = toText(_: NodeSeq).toLong
private[this] def queryMasterExtractor(queryMasterIdTagName: String, networkQueryIdTagName: String, nameTagName: String, userIdTagName: String, groupIdTagName: String, createDateTagName: String, heldTagName: String, flaggedTagName: String, flagMessageTagName: String): NodeSeq => Try[QueryMaster] = {
(querymasterXml: NodeSeq) => {
for {
queryMasterId <- querymasterXml.withChild(queryMasterIdTagName).map(toText)
networkQueryId <- querymasterXml.withChild(networkQueryIdTagName).map(toLong)
name <- querymasterXml.withChild(nameTagName).map(toText)
userId <- querymasterXml.withChild(userIdTagName).map(toText)
groupId <- querymasterXml.withChild(groupIdTagName).map(toText)
createDateText <- querymasterXml.withChild(createDateTagName).map(toText)
createDate <- XmlDateHelper.parseXmlTime(createDateText)
- held = (querymasterXml \ heldTagName).headOption.map(toText(_).toBoolean)
flagged = (querymasterXml \ flaggedTagName).headOption.map(toText(_).toBoolean)
flagMessage = (querymasterXml \ flagMessageTagName).headOption.map(toText(_))
} yield {
- QueryMaster(queryMasterId, networkQueryId, name, userId, groupId, createDate, held, flagged, flagMessage)
+ QueryMaster(queryMasterId, networkQueryId, name, userId, groupId, createDate, flagged, flagMessage)
}
}
}
}
\ No newline at end of file
diff --git a/commons/protocol/src/test/scala/net/shrine/protocol/ReadPreviousQueriesResponseTest.scala b/commons/protocol/src/test/scala/net/shrine/protocol/ReadPreviousQueriesResponseTest.scala
index 4c362ac1a..0a4256507 100644
--- a/commons/protocol/src/test/scala/net/shrine/protocol/ReadPreviousQueriesResponseTest.scala
+++ b/commons/protocol/src/test/scala/net/shrine/protocol/ReadPreviousQueriesResponseTest.scala
@@ -1,152 +1,177 @@
package net.shrine.protocol
-import java.util.Calendar
import org.junit.Test
import net.shrine.util.XmlUtil
import net.shrine.util.XmlDateHelper
import javax.xml.datatype.XMLGregorianCalendar
/**
* @author Bill Simons
- * @date 4/12/11
- * @link http://cbmi.med.harvard.edu
- * @link http://chip.org
+ * @since 4/12/11
+ * @see http://cbmi.med.harvard.edu
+ * @see http://chip.org
*
* NOTICE: This software comes with NO guarantees whatsoever and is
* licensed as Lgpl Open Source
- * @link http://www.gnu.org/licenses/lgpl.html
+ * @see http://www.gnu.org/licenses/lgpl.html
*/
final class ReadPreviousQueriesResponseTest extends ShrineResponseI2b2SerializableValidator {
val queryMasterId1 = 1111111L
val queryMasterId2 = 222222L
val networkQueryId1 = 123455667L
val networkQueryId2 = 98327592L
val queryName1 = "name1"
val queryName2 = "name2"
val userId1 = Some("user1")
val userId2 = Some("user2")
val groupId1 = Some("group1")
val groupId2 = Some("group2")
val createDate1 = XmlDateHelper.now
val createDate2 = XmlDateHelper.now
- val held1 = None
- val held2 = Some(true)
-
val flagged1 = Some(true)
val flagged2 = None
val flagMessage1 = Some("askldhlaksdjlkasdjklasdjl")
val flagMessage2 = None
- val queryMaster1 = makeQueryMaster(queryMasterId1, networkQueryId1, queryName1, userId1, groupId1, createDate1, held1, flagged1, flagMessage1)
- val queryMaster2 = makeQueryMaster(queryMasterId2, networkQueryId2, queryName2, userId2, groupId2, createDate2, held2, flagged2, flagMessage2)
+ val queryMaster1 = makeQueryMaster(queryMasterId1, networkQueryId1, queryName1, userId1, groupId1, createDate1, flagged1, flagMessage1)
+ val queryMaster2 = makeQueryMaster(queryMasterId2, networkQueryId2, queryName2, userId2, groupId2, createDate2, flagged2, flagMessage2)
- def makeQueryMaster(queryMasterId: Long, networkQueryId: Long, queryName: String, userId: Option[String], groupId: Option[String], createDate: XMLGregorianCalendar, held: Option[Boolean], flagged: Option[Boolean], flagMessage: Option[String]) = {
- QueryMaster(String.valueOf(queryMasterId), networkQueryId, queryName, userId.get, groupId.get, createDate, held, flagged, flagMessage)
+ def makeQueryMaster(queryMasterId: Long, networkQueryId: Long, queryName: String, userId: Option[String], groupId: Option[String], createDate: XMLGregorianCalendar, flagged: Option[Boolean], flagMessage: Option[String]) = {
+ QueryMaster(String.valueOf(queryMasterId), networkQueryId, queryName, userId.get, groupId.get, createDate, flagged, flagMessage)
}
def messageBody = XmlUtil.stripWhitespace {
DONE
{ queryMasterId1 }
{ networkQueryId1 }
{ queryName1 }
{ userId1.get }
{ groupId1.get }
{ createDate1 }
{ flagged1.get }
{ flagMessage1.get }
{ queryMasterId2 }
{ networkQueryId2 }
{ queryName2 }
{ userId2.get }
{ groupId2.get }
{ createDate2 }
- { held2.get }
}
+ //keep the held field around to be sure that old messages can be read.
+ def oldMessageBody = XmlUtil.stripWhitespace {
+
+
+
+ DONE
+
+
+ { queryMasterId1 }
+ { networkQueryId1 }
+ { queryName1 }
+ { userId1.get }
+ { groupId1.get }
+ { createDate1 }
+ { flagged1.get }
+ { flagMessage1.get }
+
+
+ { queryMasterId2 }
+ { networkQueryId2 }
+ { queryName2 }
+ { userId2.get }
+ { groupId2.get }
+ { createDate2 }
+ false
+
+
+
+ }
+
+
val readPreviousQueriesResponse = XmlUtil.stripWhitespace {
{ queryMasterId1 }
{ networkQueryId1 }
{ queryName1 }
{ createDate1 }
{ userId1.get }
{ groupId1.get }
{ flagged1.get }
{ flagMessage1.get }
{ queryMasterId2 }
{ networkQueryId2 }
{ queryName2 }
{ createDate2 }
{ userId2.get }
{ groupId2.get }
- { held2.get }
}
@Test
- def testFromI2b2FailsFast {
+ def testFromI2b2FailsFast() {
intercept[Exception] {
ReadPreviousQueriesResponse.fromI2b2()
}
intercept[Exception] {
ReadPreviousQueriesResponse.fromI2b2(ErrorResponse("foo!").toI2b2)
}
}
@Test
- def testFromXml {
+ def testFromXml() {
val actual = ReadPreviousQueriesResponse.fromXml(readPreviousQueriesResponse)
val expectedQueryMasters = Set(queryMaster1, queryMaster2)
actual.queryMasters.toSet should equal(expectedQueryMasters)
}
@Test
- def testToXml {
+ def testToXml() {
//we compare the string versions of the xml because Scala's xml equality does not always behave properly
ReadPreviousQueriesResponse(Seq(queryMaster1, queryMaster2)).toXmlString should equal(readPreviousQueriesResponse.toString)
}
@Test
- def testFromI2b2 {
+ def testFromI2b2() {
val translatedResponse = ReadPreviousQueriesResponse.fromI2b2(response)
translatedResponse.queryMasters.toSet should equal(Set(queryMaster1, queryMaster2))
}
@Test
- def testToI2b2 {
+ def testToI2b2() {
//Per-queryMaster userids and groupids
//we compare the string versions of the xml because Scala's xml equality does not always behave properly
val actual = ReadPreviousQueriesResponse(Seq(queryMaster1, queryMaster2)).toI2b2String
val expected = response.toString
actual should equal(expected)
}
}
\ No newline at end of file
diff --git a/qep/service/src/main/scala/net/shrine/qep/queries/QepQueryDb.scala b/qep/service/src/main/scala/net/shrine/qep/queries/QepQueryDb.scala
index 9d8b6cf61..1e44b9cc6 100644
--- a/qep/service/src/main/scala/net/shrine/qep/queries/QepQueryDb.scala
+++ b/qep/service/src/main/scala/net/shrine/qep/queries/QepQueryDb.scala
@@ -1,537 +1,536 @@
package net.shrine.qep.queries
import java.sql.SQLException
import java.util.concurrent.TimeoutException
import javax.sql.DataSource
import com.typesafe.config.Config
import net.shrine.audit.{NetworkQueryId, QueryName, Time, UserName}
import net.shrine.log.Loggable
import net.shrine.problem.{AbstractProblem, ProblemSources, ProblemDigest}
import net.shrine.protocol.{ResultOutputTypes, DeleteQueryRequest, RenameQueryRequest, I2b2ResultEnvelope, QueryResult, ResultOutputType, DefaultBreakdownResultOutputTypes, UnFlagQueryRequest, FlagQueryRequest, QueryMaster, ReadPreviousQueriesRequest, ReadPreviousQueriesResponse, RunQueryRequest}
import net.shrine.qep.QepConfigSource
import net.shrine.slick.TestableDataSourceCreator
import net.shrine.util.XmlDateHelper
import slick.driver.JdbcProfile
import scala.collection.immutable.Iterable
import scala.concurrent.duration.{Duration, DurationInt}
import scala.concurrent.{Await, Future, blocking}
import scala.language.postfixOps
import scala.concurrent.ExecutionContext.Implicits.global
import scala.xml.XML
/**
* DB code for the QEP's query instances and query results.
*
* @author david
* @since 1/19/16
*/
case class QepQueryDb(schemaDef:QepQuerySchema,dataSource: DataSource,timeout:Duration) extends Loggable {
import schemaDef._
import jdbcProfile.api._
val database = Database.forDataSource(dataSource)
def createTables() = schemaDef.createTables(database)
def dropTables() = schemaDef.dropTables(database)
def dbRun[R](action: DBIOAction[R, NoStream, Nothing]):R = {
val future: Future[R] = database.run(action)
try {
blocking {
Await.result(future, timeout)
}
}
catch {
case tx:TimeoutException => throw CouldNotRunDbIoActionException(dataSource,tx)
}
}
def insertQepQuery(runQueryRequest: RunQueryRequest):Unit = {
debug(s"insertQepQuery $runQueryRequest")
insertQepQuery(QepQuery(runQueryRequest))
}
def insertQepQuery(qepQuery: QepQuery):Unit = {
dbRun(allQepQueryQuery += qepQuery)
}
def selectAllQepQueries:Seq[QepQuery] = {
dbRun(mostRecentVisibleQepQueries.result)
}
//todo order
def selectPreviousQueries(request: ReadPreviousQueriesRequest):ReadPreviousQueriesResponse = {
val previousQueries: Seq[QepQuery] = selectPreviousQueriesByUserAndDomain(request.authn.username,request.authn.domain,request.fetchSize)
val flags:Map[NetworkQueryId,QepQueryFlag] = selectMostRecentQepQueryFlagsFor(previousQueries.map(_.networkId).to[Set])
val queriesAndFlags = previousQueries.map(x => (x,flags.get(x.networkId)))
ReadPreviousQueriesResponse(queriesAndFlags.map(x => x._1.toQueryMaster(x._2)))
}
//todo order
def selectPreviousQueriesByUserAndDomain(userName: UserName, domain: String, limit:Int):Seq[QepQuery] = {
dbRun(mostRecentVisibleQepQueries.filter(_.userName === userName).filter(_.userDomain === domain).take(limit).result)
}
def renamePreviousQuery(request:RenameQueryRequest):Unit = {
val networkQueryId = request.networkQueryId
dbRun(
for {
queryResults <- mostRecentVisibleQepQueries.filter(_.networkId === networkQueryId).result
_ <- allQepQueryQuery ++= queryResults.map(_.copy(queryName = request.queryName,changeDate = System.currentTimeMillis()))
} yield queryResults
)
}
def markDeleted(request:DeleteQueryRequest):Unit = {
val networkQueryId = request.networkQueryId
dbRun(
for {
queryResults <- mostRecentVisibleQepQueries.filter(_.networkId === networkQueryId).result
_ <- allQepQueryQuery ++= queryResults.map(_.copy(deleted = true,changeDate = System.currentTimeMillis()))
} yield queryResults
)
}
def insertQepQueryFlag(flagQueryRequest: FlagQueryRequest):Unit = {
insertQepQueryFlag(QepQueryFlag(flagQueryRequest))
}
def insertQepQueryFlag(unflagQueryRequest: UnFlagQueryRequest):Unit = {
insertQepQueryFlag(QepQueryFlag(unflagQueryRequest))
}
def insertQepQueryFlag(qepQueryFlag: QepQueryFlag):Unit = {
dbRun(allQepQueryFlags += qepQueryFlag)
}
def selectMostRecentQepQueryFlagsFor(networkIds:Set[NetworkQueryId]):Map[NetworkQueryId,QepQueryFlag] = {
val flags:Seq[QepQueryFlag] = dbRun(mostRecentQueryFlags.filter(_.networkId inSet networkIds).result)
flags.map(x => x.networkQueryId -> x).toMap
}
def insertQepResultRow(qepQueryRow:QueryResultRow) = {
dbRun(allQueryResultRows += qepQueryRow)
}
def insertQueryResult(networkQueryId:NetworkQueryId,result:QueryResult) = {
val adapterNode = result.description.getOrElse(throw new IllegalStateException("description is empty, does not have an adapter node"))
val queryResultRow = QueryResultRow(networkQueryId,result)
val breakdowns: Iterable[QepQueryBreakdownResultsRow] = result.breakdowns.flatMap(QepQueryBreakdownResultsRow.breakdownRowsFor(networkQueryId,adapterNode,result.resultId,_))
val problem: Seq[QepProblemDigestRow] = result.problemDigest.map(p => QepProblemDigestRow(networkQueryId,adapterNode,p.codec,p.stampText,p.summary,p.description,p.detailsXml.toString,System.currentTimeMillis())).to[Seq]
dbRun(
for {
_ <- allQueryResultRows += queryResultRow
_ <- allBreakdownResultsRows ++= breakdowns
_ <- allProblemDigestRows ++= problem
} yield ()
)
}
def selectMostRecentQepResultRowsFor(networkId:NetworkQueryId): Seq[QueryResultRow] = {
dbRun(mostRecentQueryResultRows.filter(_.networkQueryId === networkId).result)
}
def selectMostRecentQepResultsFor(networkId:NetworkQueryId): Seq[QueryResult] = {
val (queryResults, breakdowns,problems) = dbRun(
for {
queryResults <- mostRecentQueryResultRows.filter(_.networkQueryId === networkId).result
breakdowns <- mostRecentBreakdownResultsRows.filter(_.networkQueryId === networkId).result
problems <- mostRecentProblemDigestRows.filter(_.networkQueryId === networkId).result
} yield (queryResults, breakdowns, problems)
)
val resultIdsToI2b2ResultEnvelopes: Map[Long, Map[ResultOutputType, I2b2ResultEnvelope]] = breakdowns.groupBy(_.resultId).map(rIdToB => rIdToB._1 -> QepQueryBreakdownResultsRow.resultEnvelopesFrom(rIdToB._2))
def seqOfOneProblemRowToProblemDigest(problemSeq:Seq[QepProblemDigestRow]):ProblemDigest = {
if(problemSeq.size == 1) problemSeq.head.toProblemDigest
else throw new IllegalStateException(s"problemSeq size was not 1. $problemSeq")
}
val adapterNodesToProblemDigests: Map[String, ProblemDigest] = problems.groupBy(_.adapterNode).map(nodeToProblem => nodeToProblem._1 -> seqOfOneProblemRowToProblemDigest(nodeToProblem._2) )
queryResults.map(r => r.toQueryResult(
resultIdsToI2b2ResultEnvelopes.getOrElse(r.resultId,Map.empty),
adapterNodesToProblemDigests.get(r.adapterNode)
))
}
def insertQueryBreakdown(breakdownResultsRow:QepQueryBreakdownResultsRow) = {
dbRun(allBreakdownResultsRows += breakdownResultsRow)
}
def selectAllBreakdownResultsRows: Seq[QepQueryBreakdownResultsRow] = {
dbRun(allBreakdownResultsRows.result)
}
}
object QepQueryDb extends Loggable {
val dataSource:DataSource = TestableDataSourceCreator.dataSource(QepQuerySchema.config)
val timeout = QepQuerySchema.config.getInt("timeout") seconds
val db = QepQueryDb(QepQuerySchema.schema,dataSource,timeout)
val createTablesOnStart = QepQuerySchema.config.getBoolean("createTablesOnStart")
if(createTablesOnStart) QepQueryDb.db.createTables()
}
/**
* Separate class to support schema generation without actually connecting to the database.
*
* @param jdbcProfile Database profile to use for the schema
*/
case class QepQuerySchema(jdbcProfile: JdbcProfile,moreBreakdowns: Set[ResultOutputType]) extends Loggable {
import jdbcProfile.api._
def ddlForAllTables: jdbcProfile.DDL = {
allQepQueryQuery.schema ++ allQepQueryFlags.schema ++ allQueryResultRows.schema ++ allBreakdownResultsRows.schema ++ allProblemDigestRows.schema
}
//to get the schema, use the REPL
//println(QepQuerySchema.schema.ddlForAllTables.createStatements.mkString(";\n"))
def createTables(database:Database) = {
try {
val future = database.run(ddlForAllTables.create)
Await.result(future,10 seconds)
} catch {
//I'd prefer to check and create schema only if absent. No way to do that with Oracle.
case x:SQLException => info("Caught exception while creating tables. Recover by assuming the tables already exist.",x)
}
}
def dropTables(database:Database) = {
val future = database.run(ddlForAllTables.drop)
//Really wait forever for the cleanup
Await.result(future,Duration.Inf)
}
class QepQueries(tag:Tag) extends Table[QepQuery](tag,"previousQueries") {
def networkId = column[NetworkQueryId]("networkId")
def userName = column[UserName]("userName")
def userDomain = column[String]("domain")
def queryName = column[QueryName]("queryName")
def expression = column[String]("expression")
def dateCreated = column[Time]("dateCreated")
def deleted = column[Boolean]("deleted")
def queryXml = column[String]("queryXml")
def changeDate = column[Long]("changeDate")
def * = (networkId,userName,userDomain,queryName,expression,dateCreated,deleted,queryXml,changeDate) <> (QepQuery.tupled,QepQuery.unapply)
}
val allQepQueryQuery = TableQuery[QepQueries]
val mostRecentQepQueryQuery: Query[QepQueries, QepQuery, Seq] = for(
queries <- allQepQueryQuery if !allQepQueryQuery.filter(_.networkId === queries.networkId).filter(_.changeDate > queries.changeDate).exists
) yield queries
val mostRecentVisibleQepQueries = mostRecentQepQueryQuery.filter(_.deleted === false)
class QepQueryFlags(tag:Tag) extends Table[QepQueryFlag](tag,"queryFlags") {
def networkId = column[NetworkQueryId]("networkId")
def flagged = column[Boolean]("flagged")
def flagMessage = column[String]("flagMessage")
def changeDate = column[Long]("changeDate")
def * = (networkId,flagged,flagMessage,changeDate) <> (QepQueryFlag.tupled,QepQueryFlag.unapply)
}
val allQepQueryFlags = TableQuery[QepQueryFlags]
val mostRecentQueryFlags: Query[QepQueryFlags, QepQueryFlag, Seq] = for(
queryFlags <- allQepQueryFlags if !allQepQueryFlags.filter(_.networkId === queryFlags.networkId).filter(_.changeDate > queryFlags.changeDate).exists
) yield queryFlags
val qepQueryResultTypes = DefaultBreakdownResultOutputTypes.toSet ++ ResultOutputType.values ++ moreBreakdowns
val stringsToQueryResultTypes: Map[String, ResultOutputType] = qepQueryResultTypes.map(x => (x.name,x)).toMap
val queryResultTypesToString: Map[ResultOutputType, String] = stringsToQueryResultTypes.map(_.swap)
implicit val qepQueryResultTypesColumnType = MappedColumnType.base[ResultOutputType,String] ({
(resultType: ResultOutputType) => queryResultTypesToString(resultType)
},{
(string: String) => stringsToQueryResultTypes(string)
})
implicit val queryStatusColumnType = MappedColumnType.base[QueryResult.StatusType,String] ({
statusType => statusType.name
},{
name => QueryResult.StatusType.valueOf(name).getOrElse(throw new IllegalStateException(s"$name is not one of ${QueryResult.StatusType.values.map(_.name).mkString(", ")}"))
})
class QepQueryResults(tag:Tag) extends Table[QueryResultRow](tag,"queryResults") {
def resultId = column[Long]("resultId")
def networkQueryId = column[NetworkQueryId]("networkQueryId")
def instanceId = column[Long]("instanceId")
def adapterNode = column[String]("adapterNode")
def resultType = column[ResultOutputType]("resultType")
def size = column[Long]("size")
def startDate = column[Option[Long]]("startDate")
def endDate = column[Option[Long]]("endDate")
def status = column[QueryResult.StatusType]("status")
def statusMessage = column[Option[String]]("statusMessage")
def changeDate = column[Long]("changeDate")
def * = (resultId,networkQueryId,instanceId,adapterNode,resultType,size,startDate,endDate,status,statusMessage,changeDate) <> (QueryResultRow.tupled,QueryResultRow.unapply)
}
val allQueryResultRows = TableQuery[QepQueryResults]
//Most recent query result rows for each queryId from each adapter
val mostRecentQueryResultRows: Query[QepQueryResults, QueryResultRow, Seq] = for(
queryResultRows <- allQueryResultRows if !allQueryResultRows.filter(_.networkQueryId === queryResultRows.networkQueryId).filter(_.adapterNode === queryResultRows.adapterNode).filter(_.changeDate > queryResultRows.changeDate).exists
) yield queryResultRows
class QepQueryBreakdownResults(tag:Tag) extends Table[QepQueryBreakdownResultsRow](tag,"queryBreakdownResults") {
def networkQueryId = column[NetworkQueryId]("networkQueryId")
def adapterNode = column[String]("adapterNode")
def resultId = column[Long]("resultId")
def resultType = column[ResultOutputType]("resultType")
def dataKey = column[String]("dataKey")
def value = column[Long]("value")
def changeDate = column[Long]("changeDate")
def * = (networkQueryId,adapterNode,resultId,resultType,dataKey,value,changeDate) <> (QepQueryBreakdownResultsRow.tupled,QepQueryBreakdownResultsRow.unapply)
}
val allBreakdownResultsRows = TableQuery[QepQueryBreakdownResults]
//Most recent query result rows for each queryId from each adapter
val mostRecentBreakdownResultsRows: Query[QepQueryBreakdownResults, QepQueryBreakdownResultsRow, Seq] = for(
breakdownResultsRows <- allBreakdownResultsRows if !allBreakdownResultsRows.filter(_.networkQueryId === breakdownResultsRows.networkQueryId).filter(_.adapterNode === breakdownResultsRows.adapterNode).filter(_.resultId === breakdownResultsRows.resultId).filter(_.changeDate > breakdownResultsRows.changeDate).exists
) yield breakdownResultsRows
/*
case class ProblemDigest(codec: String, stampText: String, summary: String, description: String, detailsXml: NodeSeq) extends XmlMarshaller {
*/
class QepResultProblemDigests(tag:Tag) extends Table [QepProblemDigestRow](tag,"queryResultProblemDigests") {
def networkQueryId = column[NetworkQueryId]("networkQueryId")
def adapterNode = column[String]("adapterNode")
def codec = column[String]("codec")
def stamp = column[String]("stamp")
def summary = column[String]("summary")
def description = column[String]("description")
def details = column[String]("details")
def changeDate = column[Long]("changeDate")
def * = (networkQueryId,adapterNode,codec,stamp,summary,description,details,changeDate) <> (QepProblemDigestRow.tupled,QepProblemDigestRow.unapply)
}
val allProblemDigestRows = TableQuery[QepResultProblemDigests]
val mostRecentProblemDigestRows: Query[QepResultProblemDigests, QepProblemDigestRow, Seq] = for(
problemDigests <- allProblemDigestRows if !allProblemDigestRows.filter(_.networkQueryId === problemDigests.networkQueryId).filter(_.adapterNode === problemDigests.adapterNode).filter(_.changeDate > problemDigests.changeDate).exists
) yield problemDigests
}
object QepQuerySchema {
val allConfig:Config = QepConfigSource.config
val config:Config = allConfig.getConfig("shrine.queryEntryPoint.audit.database")
val slickProfileClassName = config.getString("slickProfileClassName")
val slickProfile:JdbcProfile = QepConfigSource.objectForName(slickProfileClassName)
import net.shrine.config.{ConfigExtensions, Keys}
val moreBreakdowns: Set[ResultOutputType] = config.getOptionConfigured(Keys.breakdownResultOutputTypes,ResultOutputTypes.fromConfig).getOrElse(Set.empty)
val schema = QepQuerySchema(slickProfile,moreBreakdowns)
}
case class QepQuery(
networkId:NetworkQueryId,
userName: UserName,
userDomain: String,
queryName: QueryName,
expression: String,
dateCreated: Time,
deleted: Boolean,
queryXml: String,
changeDate: Time
){
def toQueryMaster(qepQueryFlag:Option[QepQueryFlag]):QueryMaster = {
QueryMaster(
queryMasterId = networkId.toString,
networkQueryId = networkId,
name = queryName,
userId = userName,
groupId = userDomain,
createDate = XmlDateHelper.toXmlGregorianCalendar(dateCreated),
- held = None, //todo this field is never used. Remove it in 1.22
flagged = qepQueryFlag.map(_.flagged),
flagMessage = qepQueryFlag.map(_.flagMessage)
)
}
}
object QepQuery extends ((NetworkQueryId,UserName,String,QueryName,String,Time,Boolean,String,Time) => QepQuery) {
def apply(runQueryRequest: RunQueryRequest):QepQuery = {
new QepQuery(
networkId = runQueryRequest.networkQueryId,
userName = runQueryRequest.authn.username,
userDomain = runQueryRequest.authn.domain,
queryName = runQueryRequest.queryDefinition.name,
expression = runQueryRequest.queryDefinition.expr.getOrElse("No Expression").toString,
dateCreated = System.currentTimeMillis(),
deleted = false,
queryXml = runQueryRequest.toXmlString,
changeDate = System.currentTimeMillis()
)
}
}
case class QepQueryFlag(
networkQueryId: NetworkQueryId,
flagged:Boolean,
flagMessage:String,
changeDate:Long
)
object QepQueryFlag extends ((NetworkQueryId,Boolean,String,Long) => QepQueryFlag) {
def apply(flagQueryRequest: FlagQueryRequest):QepQueryFlag = {
QepQueryFlag(
networkQueryId = flagQueryRequest.networkQueryId,
flagged = true,
flagMessage = flagQueryRequest.message.getOrElse(""),
changeDate = System.currentTimeMillis()
)
}
def apply(unflagQueryRequest: UnFlagQueryRequest):QepQueryFlag = {
QepQueryFlag(
networkQueryId = unflagQueryRequest.networkQueryId,
flagged = false,
flagMessage = "",
changeDate = System.currentTimeMillis()
)
}
}
case class QueryResultRow(
resultId:Long,
networkQueryId:NetworkQueryId,
instanceId:Long,
adapterNode:String,
resultType:ResultOutputType,
size:Long,
startDate:Option[Long],
endDate:Option[Long],
status:QueryResult.StatusType,
statusMessage:Option[String],
changeDate:Long
) {
def toQueryResult(breakdowns:Map[ResultOutputType,I2b2ResultEnvelope],problemDigest:Option[ProblemDigest]) = QueryResult(
resultId = resultId,
instanceId = instanceId,
resultType = Some(resultType),
setSize = size,
startDate = startDate.map(XmlDateHelper.toXmlGregorianCalendar),
endDate = endDate.map(XmlDateHelper.toXmlGregorianCalendar),
description = Some(adapterNode),
statusType = status,
statusMessage = statusMessage,
breakdowns = breakdowns,
problemDigest = problemDigest
)
}
object QueryResultRow extends ((Long,NetworkQueryId,Long,String,ResultOutputType,Long,Option[Long],Option[Long],QueryResult.StatusType,Option[String],Long) => QueryResultRow)
{
def apply(networkQueryId:NetworkQueryId,result:QueryResult):QueryResultRow = {
new QueryResultRow(
resultId = result.resultId,
networkQueryId = networkQueryId,
instanceId = result.instanceId,
adapterNode = result.description.getOrElse(s"$result has None in its description field, not a name of an adapter node."),
resultType = result.resultType.getOrElse(ResultOutputType.PATIENT_COUNT_XML), //todo how is this optional??
size = result.setSize,
startDate = result.startDate.map(_.toGregorianCalendar.getTimeInMillis),
endDate = result.endDate.map(_.toGregorianCalendar.getTimeInMillis),
status = result.statusType,
statusMessage = result.statusMessage,
changeDate = System.currentTimeMillis()
)
}
}
case class QepQueryBreakdownResultsRow(
networkQueryId: NetworkQueryId,
adapterNode:String,
resultId:Long,
resultType: ResultOutputType,
dataKey:String,
value:Long,
changeDate:Long
)
object QepQueryBreakdownResultsRow extends ((NetworkQueryId,String,Long,ResultOutputType,String,Long,Long) => QepQueryBreakdownResultsRow){
def breakdownRowsFor(networkQueryId:NetworkQueryId,
adapterNode:String,
resultId:Long,
breakdown:(ResultOutputType,I2b2ResultEnvelope)): Iterable[QepQueryBreakdownResultsRow] = {
breakdown._2.data.map(b => QepQueryBreakdownResultsRow(networkQueryId,adapterNode,resultId,breakdown._1,b._1,b._2,System.currentTimeMillis()))
}
def resultEnvelopesFrom(breakdowns:Seq[QepQueryBreakdownResultsRow]): Map[ResultOutputType, I2b2ResultEnvelope] = {
def resultEnvelopeFrom(resultType:ResultOutputType,breakdowns:Seq[QepQueryBreakdownResultsRow]):I2b2ResultEnvelope = {
val data = breakdowns.map(b => b.dataKey -> b.value).toMap
I2b2ResultEnvelope(resultType,data)
}
breakdowns.groupBy(_.resultType).map(r => r._1 -> resultEnvelopeFrom(r._1,r._2))
}
}
case class QepProblemDigestRow(
networkQueryId: NetworkQueryId,
adapterNode: String,
codec: String,
stampText: String,
summary: String,
description: String,
details: String,
changeDate:Long
){
def toProblemDigest = {
ProblemDigest(
codec,
stampText,
summary,
description,
if(!details.isEmpty) XML.loadString(details)
else
)
}
}
case class CouldNotRunDbIoActionException(dataSource: DataSource, exception: Exception) extends RuntimeException(exception) {
override def getMessage:String = s"Could not use the database defined by $dataSource due to ${exception.getLocalizedMessage}"
}
case class QepDatabaseProblem(x:Exception) extends AbstractProblem(ProblemSources.Qep){
override val summary = "A problem encountered while using a database."
override val throwable = Some(x)
override val description = x.getMessage()
}
\ No newline at end of file