Skip to content

Instantly share code, notes, and snippets.

@vr100
Created December 5, 2014 12:38
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save vr100/81b37e89e9688d2ad02d to your computer and use it in GitHub Desktop.
Save vr100/81b37e89e9688d2ad02d to your computer and use it in GitHub Desktop.
String and timestamp support in evolutions for play framework
/**
* Read evolution files from the application environment.
*/
@Singleton
class EvolutionsReader @Inject() (environment: Environment) {
/**
* Read the application evolutions.
*
* @param db the database name
*/
def evolutions(db: String): Seq[Evolution] = {
val upsMarker = """^#.*!Ups.*$""".r
val downsMarker = """^#.*!Downs.*$""".r
val UPS = "UPS"
val DOWNS = "DOWNS"
val UNKNOWN = "UNKNOWN"
val mapUpsAndDowns: PartialFunction[String, String] = {
case upsMarker() => UPS
case downsMarker() => DOWNS
case _ => UNKNOWN
}
val isMarker: PartialFunction[String, Boolean] = {
case upsMarker() => true
case downsMarker() => true
case _ => false
}
val fileNamesList = environment.listFileNamesInDirectory(Evolutions.directoryName(db)).toList
val resourceNamesList = environment.listFileNamesInResourceDirectory(
Evolutions.resourceDirectoryName(db)).filter(x => !fileNamesList.exists(_ == x)).toList
val filesList = fileNamesList ::: resourceNamesList
val sortedList = filesList.filter(x => {
try {
x.split("\\.")(0).split("_")(0).toLong > 0
} catch {
case e: Exception => false
}
}).sortWith((e1, e2) => {
val rev1 = e1.split("\\.")(0).split("_")(0).toLong
val rev2 = e2.split("\\.")(0).split("_")(0).toLong
if (rev1 == rev2) e1.compareTo(e2) < 0 else rev1 < rev2
})
sortedList.map(x => {
environment.getExistingFile(Evolutions.directoryName(db) + "/" + x).map(new FileInputStream(_)).orElse {
environment.resourceAsStream(Evolutions.resourceDirectoryName(db) + "/" + x)
}
}).filter(_ != None).map(stream => {
val script = PlayIO.readStreamAsString(stream.get)(Codec.UTF8)
Collections.unfoldLeft(("", script.split('\n').toList.map(_.trim))) {
case (_, Nil) => None
case (context, lines) => {
val (some, next) = lines.span(l => !isMarker(l))
Some((next.headOption.map(c => (mapUpsAndDowns(c), next.tail)).getOrElse("" -> Nil),
context -> some.mkString("\n")))
}
}.reverse.drop(1).groupBy(i => i._1).mapValues { _.map(_._2).mkString("\n").trim }
}).zip(Stream from 1).map(pair => {
val (parsed, revision) = pair
Evolution(
revision,
parsed.get(UPS).getOrElse(""),
parsed.get(DOWNS).getOrElse(""))
})
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment