Skip to content
Open
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
8 changes: 5 additions & 3 deletions src/main/scala/defaultLocations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import ohnosequences.datasets._
import ohnosequences.cosas._, types._, fns._, klists._
import ohnosequences.awstools.s3._

class defaultS3LocationForTask[T <: AnyTask](val task: T) extends DepFn1[
case class defaultS3LocationForTask[T <: AnyTask]() extends DepFn1[
AnyData,
AnyDenotation { type Value = S3Resource }
]
{

implicit def default[D <: AnyData]: AnyApp1At[this.type, D] { type Y = D := S3Resource } =
case object defaultS3LocationForTask {

implicit def defApp[T <: AnyTask, D <: AnyData](implicit task: T)
: AnyApp1At[defaultS3LocationForTask[T], D] { type Y = D := S3Resource } =
App1 { d: D => d := S3Resource(task.s3Output / d.label) }
}

Expand Down
1 change: 1 addition & 0 deletions src/main/scala/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ import ohnosequences.datasets._

package object projects {

type NoData = |[AnyData]
val noData: |[AnyData] = |[AnyData]
}
103 changes: 55 additions & 48 deletions src/main/scala/projects.scala
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ trait AnyProject {
lazy val s3Input : S3Folder = s3 / "data" / "in" /
lazy val s3Output : S3Folder = s3 / "data" / "out" /


// TODO one role per project, created when initialized
// lazy val role: Role = projects
}
Expand All @@ -56,11 +55,12 @@ abstract class Project(val name: String) extends AnyProject
*/
trait AnyTask extends AnyType {

type Raw = AnyTaskState :: List[Input#Raw] :: List[Output#Raw] :: *[Any]

type Project <: AnyProject
val project: Project

val deadline: LocalDate
def deadlinePassed: Boolean = deadline.isAfter(LocalDate.now)

val name: String
lazy val fullName : String = s"${project.name}.${name}"
lazy val label : String = fullName
Expand All @@ -72,83 +72,67 @@ trait AnyTask extends AnyType {

Both inputs and outputs are records of `AnyData`. Normally you would define a task as an `object`, with nested `object`s for the input and output. Then you just need to set the corresponding types and values.
*/
type Input <: AnyDataSet
type Input <: AnyProductType { type Types <: AnyKList.Of[AnyData] }
val input: Input

type Output <: AnyDataSet
type Output <: AnyProductType { type Types <: AnyKList.Of[AnyData] }
val output: Output

type Raw = AnyTaskState :: List[Input#Raw] :: List[Output#Raw] :: *[Any]

// NOTE in a future better world we could use this
lazy val branch = name

/*
This is a depfn which when applied on data: `task.defaultS3Location(d)` yields the default S3 location for `d`. You can use it for building data Loquat data mappings, for example, by mapping over the types of the input/output records.
*/
case object defaultS3Location extends defaultS3LocationForTask(this)

/* the returned depfn will let you add a qualifier after the standard output path for this task. See the tests for an example of its use */
def defaultLocationWithQualifier(qual: String): insertAfter = insertAfter(s3Output.key, qual)

def defaultOutputS3Location[
O <: Output#Raw
](implicit
def defaultS3Locations[O <: AnyKList { type Bound = AnyDenotation { type Value = S3Resource } }](implicit
mapper: AnyApp2At[
mapKList[defaultS3Location.type, AnyDenotation { type Value = S3Resource }],
defaultS3Location.type,
Output#Keys#Types
mapKList[defaultS3LocationForTask[this.type], AnyDenotation { type Value = S3Resource }],
defaultS3LocationForTask[this.type], Output#Types
] { type Y = O }
)
: O =
mapper(defaultS3Location, output.keys.types)
: O = mapper(defaultS3LocationForTask[this.type], output.types)
}

val deadline: LocalDate
case object AnyTask {

implicit def denotationSyntax[T <: AnyTask, V <: T#Raw](td: T := V): TaskDenotationSyntax[T,V] =
TaskDenotationSyntax(td)
}
case class TaskDenotationSyntax[T <: AnyTask, V <: T#Raw](val td: T := V) {

// abstract class Task[P <: AnyProject](val project: P)(val deadline: LocalDate) extends AnyTask {
//
// type Project = P
//
// lazy val name: String = toString
// }
def isDeadlineOK: Boolean = td.value.head match {
case Failed | Cancelled | Expired | Completed => true
case Specified | InReview |Started => td.tpe.deadlinePassed
}
}

/*
This is a helper constructor for doing something like

``` scala
case object doSomething extends Task(project)(input)(output)(date)`
case object doSomething extends Task(project)(date) {

type Input = NoData
val input = noData

type Output = NoData
val output = noData
}
```
*/
class Task[
P <: AnyProject,
I <: AnyProductType { type Types <: AnyKList.Of[AnyData] },
O <: AnyProductType { type Types <: AnyKList.Of[AnyData] }
abstract class Task[
P <: AnyProject
](
val project: P
)(
val inputData: I
)(
val outputData: O
)(
val deadline: LocalDate
)(
implicit
proof1: noDuplicates isTrueOn I#Types,
proof2: noDuplicates isTrueOn O#Types
)
extends AnyTask {

type Project = P

type Input = DataSet[I]
lazy val input: Input = new DataSet(inputData) {}

type Output = DataSet[O]
lazy val output: Output = new DataSet(outputData) {}

lazy val name: String = toString
}


sealed trait AnyTaskState

case object Specified extends AnyTaskState {
Expand Down Expand Up @@ -184,3 +168,26 @@ abstract class ProjectTasks[P <: AnyProject, Ks <: AnyProductType { type Types <
noDuplicates: noDuplicates isTrueOn Ks#Types
)
extends RecordType(tasks)

case object getState extends DepFn1[AnyDenotation, (AnyTask, AnyTaskState)] {

implicit def default[
T <: AnyTask,
V <: T#Raw
]
: AnyApp1At[this.type, T := V] { type Y = (T,V#Head) } =
getState at { tv: T := V => (tv.tpe, tv.value.head) }
}

// TODO return the task if not or somethikn similar
case object taskDeadlineOK extends DepFn1[AnyDenotation, Boolean] {

implicit def default[T <: AnyTask, V <: T#Raw]
: AnyApp1At[taskDeadlineOK.type, T := V] { type Y = Boolean } =
App1 {
tv: T := V => tv.value.head match {
case Failed | Cancelled | Expired | Completed => true
case Specified | InReview |Started => tv.tpe.deadlinePassed
}
}
}
46 changes: 23 additions & 23 deletions src/test/scala/DefaultLocationsTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ case object example {

case object buh extends era7.projects.Project("buh")

case object doSomething extends Task(buh)(x :×: |[AnyData])(x :×: |[AnyData])(LocalDate.of(2016,3,2))
// case object doSomething extends Task(buh)(x :×: |[AnyData])(x :×: |[AnyData])(LocalDate.of(2016,3,2))
}

class DefaultLocationsTest extends FunSuite {
Expand All @@ -24,32 +24,32 @@ class DefaultLocationsTest extends FunSuite {

test("default S3 locations") {

assert {
(doSomething.input.keys.types map doSomething.defaultS3Location) === (
(x := S3Resource(doSomething.s3Output / x.label)) :: *[AnyDenotation]
)
}

assert {
(doSomething.input.keys.types map doSomething.defaultS3Location) === doSomething.defaultOutputS3Location
}
// assert {
// (doSomething.input.types map doSomething.defaultS3Location) === (
// (x := S3Resource(doSomething.s3Output / x.label)) :: *[AnyDenotation]
// )
// }
//
// assert {
// (doSomething.input.types map doSomething.defaultS3Location) === doSomething.defaultOutputS3Location
// }
}

test("can map over default locations") {

// NOTE just something which serves as a classifier for different denotations of the same resource
val samples = Set("hola", "scalac", "que tal")

val s3PerSample = samples map {
s => {

val addSamplePrefix = doSomething.defaultLocationWithQualifier(s)
import addSamplePrefix._

doSomething.defaultOutputS3Location map addSamplePrefix
}
}

println { s3PerSample }
// val samples = Set("hola", "scalac", "que tal")
//
// val s3PerSample = samples map {
// s => {
//
// val addSamplePrefix = doSomething.defaultLocationWithQualifier(s)
// import addSamplePrefix._
//
// doSomething.defaultOutputS3Location map addSamplePrefix
// }
// }
//
// println { s3PerSample }
}
}
45 changes: 33 additions & 12 deletions src/test/scala/exampleProject.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,31 @@ case object preparePaellaTasks extends ProjectTasks(preparePaella)(
case object rice extends Data("La Fallera")
case object seafood extends Data("Preparado de Paella Pescanova")

case object buyRice extends Task(preparePaella)(noData)(rice :×: |[AnyData])(LocalDate.of(2016,3,2))
case object buySeafood extends Task(preparePaella)(noData)(seafood :×: |[AnyData])(LocalDate.of(2016,3,2))
case object buyRice extends Task(preparePaella)(LocalDate.of(2016,3,2)) {

type Input = NoData; val input = noData
type Output = rice.type :×: |[AnyData]; val output = rice :×: |[AnyData]
}
case object buySeafood extends Task(preparePaella)(LocalDate.of(2016,3,2)) {

type Input = NoData; val input = noData
type Output = seafood.type :×: |[AnyData]; val output = seafood :×: |[AnyData]
}

case object projectState {

// Now imagine that I already got my rice, but no seafood yet
val current = preparePaellaTasks := {
buyRice( Completed :: List(*[AnyDenotation]) :: List(buyRice.defaultOutputS3Location) :: *[Any] ) ::
buySeafood( Specified :: List(*[AnyDenotation]) :: List(buySeafood.defaultOutputS3Location) :: *[Any] ) ::
buyRice(
Completed ::
List(*[AnyDenotation]) ::
List(buyRice.defaultS3Locations) :: *[Any]
) ::
buySeafood(
Specified ::
List(*[AnyDenotation]) ::
List(buySeafood.defaultS3Locations) :: *[Any]
) ::
*[AnyDenotation]
}
}
Expand All @@ -36,15 +52,20 @@ abstract class GenericTasksTests[
PT <: ProjectTasks[P, Ks]
](val pt: PT) extends org.scalatest.FunSuite {

test("dummy test with tasks") {
test("dummy test with tasks") {}
}

class ExampleProjectTests extends org.scalatest.FunSuite {

test("deadlines are still in the future") {

assertResult(true) {

val zzz: List[Boolean] = (projectState.current.value map taskDeadlineOK).asList

// println { pt.keys.types.asList toString }
zzz.foldLeft(true)(_ && _)
}
}
}

class buh extends GenericTasksTests[
preparePaella.type,
buyRice.type :×:
buySeafood.type :×: |[AnyTask],
preparePaellaTasks.type
](preparePaellaTasks)
class preparePaellaDefaultTests extends GenericProjectStateTest(preparePaella)(preparePaellaTasks.keys)(preparePaellaTasks)(projectState.current)
27 changes: 27 additions & 0 deletions src/test/scala/genericTests.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package era7.projects.test

import era7.projects._
import ohnosequences.cosas._, types._, klists._, fns._

abstract class GenericProjectStateTest[
P <: AnyProject,
Ks <: AnyProductType { type Types <: AnyKList { type Bound <: AnyTask } },
PT <: ProjectTasks[P, Ks],
PTS <: PT#Raw,
BL <: AnyKList { type Bound = Boolean }
](val p: P)(val pks: Ks)(val pt: PT)(val state: PT := PTS)(implicit
mapper: AnyApp2At[
mapKList[taskDeadlineOK.type, Boolean],
taskDeadlineOK.type,
PTS
] {
type Y = BL
}
) extends org.scalatest.FunSuite {

test("check deadlines")
{

// println { mapper(taskDeadlineOK, state.value) }
}
}