Skip to content

Commit

Permalink
[WIP] Add Data.Basic EnumWrappers. Move derivers to datamodel base. (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
deusaquilus authored Jul 25, 2023
1 parent 7459c47 commit 299d9f8
Show file tree
Hide file tree
Showing 18 changed files with 613 additions and 127 deletions.
51 changes: 51 additions & 0 deletions CustomizeTheBuild.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Customizing the Build

## Using build.user.conf

* Add a build.user.conf to the root directory.
* This file can be used to set BuildSettings -> ScalaSettings.
* The path to each setting is based on the path in the BuildSettings case class

For example, to disable the JavaScript and Native builds, as well as
to only build with Scala 3.3.0 do the following:

```
# build.user.conf
js.enable=false
native.enable=false
scala.defaultCrossScalaVersions=3.3.0
```

It is very useful to generate the IntelliJ settings file in this mode
as it will radically increase IntelliJ's build performance.

```bash
./mill mill.scalalib.GenIdea/idea
```

## Command Environment Variables

Another way to specify certain properties on the command line is
through environment variables.
```
MORPHIR_BUILD_JVM_ENABLE=false ./mill -i showBuildSettings
```
Make sure to use `./mill -i` with this feature in order to
for these settings to take effect. Otherwise mill will use the background
mill server which is on a separate JVM and these settings will not take
effect (however the build.user.conf approach above will still work).

## Modifying JVM Properties

Use `.mill-jvm-opts` to set Java properties for the build.

## Dev Mode

In order to easily disable Native/JS builds and set the Scala
version to 3.3.0 you can also use a global environment variable.
Add the following to your `.zprofile` (on OSX) or `.bashrc` (on Linux)
etc...

```
export MORPHIR_SCALA_DEV_MODE='true'
```
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ Morphir-jvm use [mill](https://com-lihaoyi.github.io/mill) as its build tool.
If you are using IntelliJ IDEA to edit morphir-jvm's Scala code, you can create the
IntelliJ project files via:

```bash
````bash
./mill mill.scalalib.GenIdea/idea
```
````

### BSP Setup

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module Morphir.Examples.App.EnumTest exposing (..)

type Amount = Amount Int

amount: Amount
amount = Amount 123
7 changes: 7 additions & 0 deletions morphir/datamodel/src-2/datamodel/Deriver.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.finos.morphir.datamodel

// Stub so Scala 2 can compile org.finos.morphir.datamodel package since it requires the Deriver trait
trait Deriver[T] {
def derive(value: T): Data
def concept: Concept
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,12 @@ trait Deriver[T] {
def concept: Concept
}

trait SpecificDeriver[T] extends Deriver[T] {
def derive(value: T): Data
def concept: Concept
}

object Deriver {
import DeriverTypes._
import DeriverMacros._

inline def toData[T](value: T): Data = {
import org.finos.morphir.datamodel.Derivers.{given, _}
import org.finos.morphir.datamodel.{given, _}
val deriver = Deriver.gen[T]
deriver.derive(value)
}
Expand Down
228 changes: 113 additions & 115 deletions morphir/datamodel/src-3/org/finos/morphir/datamodel/Derivers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,119 +14,117 @@ import org.finos.morphir.datamodel.Concept
import scala.collection.immutable.ListMap
import scala.collection.mutable.LinkedHashMap

object Derivers {
given SpecificDeriver[Boolean] with
def derive(value: Boolean) = Data.Boolean(value)
def concept = Concept.Boolean

given SpecificDeriver[Byte] with
def derive(value: Byte) = Data.Byte(value)
def concept = Concept.Byte

given SpecificDeriver[BigDecimal] with
def derive(value: BigDecimal) = Data.Decimal(value)
def concept = Concept.Decimal

given SpecificDeriver[BigInt] with
def derive(value: BigInt) = Data.Integer(value)
def concept = Concept.Integer

given SpecificDeriver[Short] with
def derive(value: Short) = Data.Int16(value)
def concept = Concept.Int16

given SpecificDeriver[Int] with
def derive(value: Int) = Data.Int32(value)
def concept = Concept.Int32

given SpecificDeriver[String] with
def derive(value: String) = Data.String(value)
def concept = Concept.String

given SpecificDeriver[LocalDate] with
def derive(value: LocalDate) = Data.LocalDate(value)
def concept = Concept.LocalDate

given SpecificDeriver[Month] with
def derive(value: Month) = Data.Month(value)
def concept = Concept.Month

given SpecificDeriver[LocalTime] with
def derive(value: LocalTime) = Data.LocalTime(value)
def concept = Concept.LocalTime

given SpecificDeriver[Char] with
def derive(value: Char) = Data.Char(value)
def concept = Concept.Char

given SpecificDeriver[Unit] with
def derive(value: Unit) = Data.Unit
def concept = Concept.Unit

given optionDeriver[T](using elementDeriver: Deriver[T]): SpecificDeriver[Option[T]] with
def derive(value: Option[T]) =
value match
case Some(value) => Data.Optional.Some(elementDeriver.derive(value), elementDeriver.concept)
case None => Data.Optional.None(elementDeriver.concept)
def concept = Concept.Optional(elementDeriver.concept)

given optionSomeDeriver[T](using elementDeriver: Deriver[T]): SpecificDeriver[Some[T]] with
def derive(value: Some[T]) = Data.Optional.Some(elementDeriver.derive(value.value), elementDeriver.concept)
def concept = Concept.Optional(elementDeriver.concept)

given optionNoneDeriver: SpecificDeriver[scala.None.type] with
def derive(value: scala.None.type) = Data.Optional.None(Concept.Nothing)
def concept = Concept.Optional(Concept.Nothing)

given listDeriver[T](using elementDeriver: Deriver[T]): SpecificDeriver[List[T]] with {
def derive(value: scala.List[T]) =
def toData(value: T) = elementDeriver.derive(value)
// Take the schema from the elementDeriver instead of the list elements
// because even if the elements themeselves have more specific schemas than the derver schema,
// the deriver schema has a generalization of the elements whose type is the only valid
// type for the whole list.
Data.List(value.map(toData(_)), elementDeriver.concept)

def concept: Concept.List = Concept.List(elementDeriver.concept)
}

/*
* Since we want to have the option to use either ordered or unordered maps in the DDL,
* derivers for ordered and non-ordered map variants have been provided. In particular
* since the Scala ListMap is problematic in many ways (e.g. lookup time is O(n)) the
* baseline implementation for the deriver uses scala's LinkedHashMap. Since
* this datastructure is mutable, we make a copy of it during the derivation process
* so that changes to it will not cause changes to the underlying Data object.
*/

given linkedMapDeriver[K, V](using
keyDeriver: Deriver[K],
valueDeriver: Deriver[V]
): SpecificDeriver[LinkedHashMap[K, V]] with {
def derive(value: LinkedHashMap[K, V]) =
def toData(value: (K, V)) = (keyDeriver.derive(value._1), valueDeriver.derive(value._2))
Data.Map.copyFrom(value.map(toData(_)), Concept.Map(keyDeriver.concept, valueDeriver.concept))

def concept: Concept.Map = Concept.Map(keyDeriver.concept, valueDeriver.concept)
}

given listMapDeriver[K, V](using
keyDeriver: Deriver[K],
valueDeriver: Deriver[V]
): SpecificDeriver[ListMap[K, V]] with
def derive(value: ListMap[K, V]): Data = linkedMapDeriver[K, V].derive(LinkedHashMap.from(value))
def concept: Concept = linkedMapDeriver[K, V].concept

given mapDeriver[K, V](using
keyDeriver: Deriver[K],
valueDeriver: Deriver[V]
): SpecificDeriver[Map[K, V]] with
def derive(value: Map[K, V]): Data = linkedMapDeriver[K, V].derive(LinkedHashMap.from(value))
def concept: Concept = linkedMapDeriver[K, V].concept

implicit inline def autoProductDeriver[T <: Product]: GenericProductDeriver[T] =
GenericProductDeriver.gen[T]

implicit inline def autoSumDeriver[T]: GenericSumDeriver[T] =
GenericSumDeriver.gen[T]
given booleanDeriver: SpecificDeriver[Boolean] with
def derive(value: Boolean) = Data.Boolean(value)
def concept = Concept.Boolean

given byteDeriver: SpecificDeriver[Byte] with
def derive(value: Byte) = Data.Byte(value)
def concept = Concept.Byte

given bigDecimalDeriver: SpecificDeriver[BigDecimal] with
def derive(value: BigDecimal) = Data.Decimal(value)
def concept = Concept.Decimal

given bigIntDeriver: SpecificDeriver[BigInt] with
def derive(value: BigInt) = Data.Integer(value)
def concept = Concept.Integer

given shortDeriver: SpecificDeriver[Short] with
def derive(value: Short) = Data.Int16(value)
def concept = Concept.Int16

given intDeriver: SpecificDeriver[Int] with
def derive(value: Int) = Data.Int32(value)
def concept = Concept.Int32

given stringDeriver: SpecificDeriver[String] with
def derive(value: String) = Data.String(value)
def concept = Concept.String

given localDateDeriver: SpecificDeriver[LocalDate] with
def derive(value: LocalDate) = Data.LocalDate(value)
def concept = Concept.LocalDate

given monthDeriver: SpecificDeriver[Month] with
def derive(value: Month) = Data.Month(value)
def concept = Concept.Month

given localTimeDeriver: SpecificDeriver[LocalTime] with
def derive(value: LocalTime) = Data.LocalTime(value)
def concept = Concept.LocalTime

given charDeriver: SpecificDeriver[Char] with
def derive(value: Char) = Data.Char(value)
def concept = Concept.Char

given unitDeriver: SpecificDeriver[Unit] with
def derive(value: Unit) = Data.Unit
def concept = Concept.Unit

given optionDeriver[T](using elementDeriver: Deriver[T]): SpecificDeriver[Option[T]] with
def derive(value: Option[T]) =
value match
case Some(value) => Data.Optional.Some(elementDeriver.derive(value), elementDeriver.concept)
case None => Data.Optional.None(elementDeriver.concept)
def concept = Concept.Optional(elementDeriver.concept)

given optionSomeDeriver[T](using elementDeriver: Deriver[T]): SpecificDeriver[Some[T]] with
def derive(value: Some[T]) = Data.Optional.Some(elementDeriver.derive(value.value), elementDeriver.concept)
def concept = Concept.Optional(elementDeriver.concept)

given optionNoneDeriver: SpecificDeriver[scala.None.type] with
def derive(value: scala.None.type) = Data.Optional.None(Concept.Nothing)
def concept = Concept.Optional(Concept.Nothing)

given listDeriver[T](using elementDeriver: Deriver[T]): SpecificDeriver[List[T]] with {
def derive(value: scala.List[T]) =
def toData(value: T) = elementDeriver.derive(value)
// Take the schema from the elementDeriver instead of the list elements
// because even if the elements themeselves have more specific schemas than the derver schema,
// the deriver schema has a generalization of the elements whose type is the only valid
// type for the whole list.
Data.List(value.map(toData(_)), elementDeriver.concept)

def concept: Concept.List = Concept.List(elementDeriver.concept)
}

/*
* Since we want to have the option to use either ordered or unordered maps in the DDL,
* derivers for ordered and non-ordered map variants have been provided. In particular
* since the Scala ListMap is problematic in many ways (e.g. lookup time is O(n)) the
* baseline implementation for the deriver uses scala's LinkedHashMap. Since
* this datastructure is mutable, we make a copy of it during the derivation process
* so that changes to it will not cause changes to the underlying Data object.
*/

given linkedMapDeriver[K, V](using
keyDeriver: Deriver[K],
valueDeriver: Deriver[V]
): SpecificDeriver[LinkedHashMap[K, V]] with {
def derive(value: LinkedHashMap[K, V]) =
def toData(value: (K, V)) = (keyDeriver.derive(value._1), valueDeriver.derive(value._2))
Data.Map.copyFrom(value.map(toData(_)), Concept.Map(keyDeriver.concept, valueDeriver.concept))

def concept: Concept.Map = Concept.Map(keyDeriver.concept, valueDeriver.concept)
}

given listMapDeriver[K, V](using
keyDeriver: Deriver[K],
valueDeriver: Deriver[V]
): SpecificDeriver[ListMap[K, V]] with
def derive(value: ListMap[K, V]): Data = linkedMapDeriver[K, V].derive(LinkedHashMap.from(value))
def concept: Concept = linkedMapDeriver[K, V].concept

given mapDeriver[K, V](using
keyDeriver: Deriver[K],
valueDeriver: Deriver[V]
): SpecificDeriver[Map[K, V]] with
def derive(value: Map[K, V]): Data = linkedMapDeriver[K, V].derive(LinkedHashMap.from(value))
def concept: Concept = linkedMapDeriver[K, V].concept

implicit inline def autoProductDeriver[T <: Product]: GenericProductDeriver[T] =
GenericProductDeriver.gen[T]

implicit inline def autoSumDeriver[T]: GenericSumDeriver[T] =
GenericSumDeriver.gen[T]
Loading

0 comments on commit 299d9f8

Please sign in to comment.