Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ object Migration extends MdcLoggable {
migrateMetricConsentReferenceId(startedBeforeSchemifier)
migrateMetricCertificateTrust(startedBeforeSchemifier)
dropFastFirehoseAccountsViews(startedBeforeSchemifier)
alterDynamicResourceDocBodyFieldsLength()
}

/**
Expand Down Expand Up @@ -511,6 +512,13 @@ object Migration extends MdcLoggable {
// Retire the fast-firehose SQL views (firehose -> account directory + ABAC). Runs after the create
// migrations above, so a fresh DB creates-then-drops them and an existing DB just drops them. See
// MigrationOfDropFastFireHoseViews.
private def alterDynamicResourceDocBodyFieldsLength(): Boolean = {
val name = nameOf(alterDynamicResourceDocBodyFieldsLength)
runOnce(name) {
MigrationOfDynamicResourceDocBodyFieldsLength.alterColumnsType(name)
}
}

private def dropFastFirehoseAccountsViews(startedBeforeSchemifier: Boolean): Boolean = {
if(startedBeforeSchemifier == true) {
logger.warn(s"Migration.database.dropFastFirehoseAccountsViews(true) cannot be run before Schemifier.")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package code.api.util.migration

import code.api.util.APIUtil
import code.api.util.migration.Migration.{DbFunction, saveLog}
import code.dynamicResourceDoc.DynamicResourceDoc
import net.liftweb.common.Full
import net.liftweb.mapper.Schemifier

object MigrationOfDynamicResourceDocBodyFieldsLength {

def alterColumnsType(name: String): Boolean = {
DbFunction.tableExists(DynamicResourceDoc) match {
case true =>
val startDate = System.currentTimeMillis()
val commitId: String = APIUtil.gitCommit
var isSuccessful = false

val executedSql =
DbFunction.maybeWrite(true, Schemifier.infoF _) {
APIUtil.getPropsValue("db.driver") match {
case Full(dbDriver) if dbDriver.contains("com.microsoft.sqlserver.jdbc.SQLServerDriver") =>
() =>
"""
|-- A realistic dynamic-endpoint request/response body example (or full error
|-- response list) routinely exceeds varchar(255) once it has more than a
|-- handful of JSON fields
|ALTER TABLE dynamicresourcedoc ALTER COLUMN examplerequestbody VARCHAR(MAX);
|ALTER TABLE dynamicresourcedoc ALTER COLUMN successresponsebody VARCHAR(MAX);
|ALTER TABLE dynamicresourcedoc ALTER COLUMN errorresponsebodies VARCHAR(MAX);
|""".stripMargin
case _ =>
() =>
"""
|-- A realistic dynamic-endpoint request/response body example (or full error
|-- response list) routinely exceeds varchar(255) once it has more than a
|-- handful of JSON fields
|ALTER TABLE dynamicresourcedoc ALTER COLUMN examplerequestbody TYPE text;
|ALTER TABLE dynamicresourcedoc ALTER COLUMN successresponsebody TYPE text;
|ALTER TABLE dynamicresourcedoc ALTER COLUMN errorresponsebodies TYPE text;
|""".stripMargin
}
}

val endDate = System.currentTimeMillis()
val comment: String =
s"""Executed SQL:
|$executedSql
|""".stripMargin
isSuccessful = true
saveLog(name, commitId, isSuccessful, startDate, endDate, comment)
isSuccessful

case false =>
val startDate = System.currentTimeMillis()
val commitId: String = APIUtil.gitCommit
val isSuccessful = false
val endDate = System.currentTimeMillis()
val comment: String =
s"""${DynamicResourceDoc._dbTableNameLC} table does not exist""".stripMargin
saveLog(name, commitId, isSuccessful, startDate, endDate, comment)
isSuccessful
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,13 @@ object JSONFactory1_4_0 extends MdcLoggable{
}

def checkFieldOption(jsonBody: Any, rootFields: List[Field]) = {
val types = rootFields.map(f => (f.getName(), f.getType().getCanonicalName().contains("Option")))
// getCanonicalName() is null for a local/anonymous class (Java reflection spec) -- which is
// exactly what a nested case class declared inside a runtime-compiled DynamicResourceDoc
// method body is, from the JVM's perspective (e.g. an example_request_body with a nested
// object generates a locally-scoped case class for that object's type). A field whose
// declared type is such a class is never itself an Option (Option's own canonical name is
// always present, since scala.Option is a top-level class), so None safely defaults to false.
val types = rootFields.map(f => (f.getName(), Option(f.getType().getCanonicalName()).exists(_.contains("Option"))))
(decompose(jsonBody), types)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ class DynamicResourceDoc extends LongKeyedMapper[DynamicResourceDoc] with IdPK w
object RequestUrl extends MappedString(this, 255)
object Summary extends MappedString(this, 255)
object Description extends MappedString(this, 255)
object ExampleRequestBody extends MappedString(this, 255)
object SuccessResponseBody extends MappedString(this, 255)
object ErrorResponseBodies extends MappedString(this, 255)
object ExampleRequestBody extends MappedText(this)
object SuccessResponseBody extends MappedText(this)
object ErrorResponseBodies extends MappedText(this)
object Tags extends MappedString(this, 255)
object Roles extends MappedString(this, 255)
object MethodBody extends MappedText(this)
Expand Down
Loading