Skip to content

Commit

Permalink
Merge pull request #302 from michelchan/addtype
Browse files Browse the repository at this point in the history
Adding Type
  • Loading branch information
michelchan authored Oct 3, 2024
2 parents 89ec528 + 1eac843 commit c43f442
Show file tree
Hide file tree
Showing 20 changed files with 1,096 additions and 1 deletion.
4 changes: 3 additions & 1 deletion build.sc
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,9 @@ object morphir extends CrossPlatform { root =>
ivy"org.typelevel::literally::${V.literally}",
ivy"io.kevinlee::just-semver::${V.`just-semver`}",
ivy"org.scalameta::metaconfig-core::${V.metaconfig}",
ivy"org.scalameta::metaconfig-sconfig::${V.metaconfig}"
ivy"org.scalameta::metaconfig-sconfig::${V.metaconfig}",
ivy"dev.zio::zio:${V.zio}",
ivy"dev.zio::zio-prelude:${V.`zio-prelude`}"
)

def compileIvyDeps = Agg(
Expand Down
1 change: 1 addition & 0 deletions mill-build/src/org/finos/morphir/build/versions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ object V {
val scalatest = "3.2.19"
val t2 = "2.0.0"
val zio = "2.1.9"
val `zio-prelude` = "1.0.0-RC31"

object Scala {
val scala3LTSVersion = "3.3.3"
Expand Down
59 changes: 59 additions & 0 deletions morphir/src/org/finos/morphir/ir/gen1/AccessControlled.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package org.finos.morphir.ir.gen1

import org.finos.morphir.ir.gen1.AccessControlled.Access

final case class AccessControlled[+A](access: Access, value: A) {
self =>
def map[B](f: A => B): AccessControlled[B] =
AccessControlled(access, f(value))

def flatMap[B](f: A => AccessControlled[B]): AccessControlled[B] =
f(value)

def fold[B](ifPublic: A => B, ifPrivate: A => B): B =
access match {
case Access.Public => ifPublic(self.value)
case Access.Private => ifPrivate(self.value)
}

def withPublicAccess: Option[A] = self match {
case AccessControlled(Access.Public, a) => Some(a)
case _ => None
}

/** Get the value with private access level. Will always return the value.
*/
def withPrivateAccess: A = self match {
case AccessControlled(Access.Public, a) => a
case AccessControlled(Access.Private, a) => a
}

def zip[B](that: AccessControlled[B]): AccessControlled[(A, B)] =
AccessControlled(access, (value, that.value))
}

object AccessControlled {

def publicAccess[A](value: A): AccessControlled[A] = AccessControlled(Access.Public, value)

def privateAccess[A](value: A): AccessControlled[A] = AccessControlled(Access.Private, value)

sealed trait Access

object Access {
case object Public extends Access

case object Private extends Access
}

object WithPrivateAccess {
def unapply[A](accessControlled: AccessControlled[A]): Option[A] =
Some(accessControlled.withPrivateAccess)
}

object WithPublicAccess {
def unapply[A](accessControlled: AccessControlled[A]): Option[A] =
accessControlled.withPublicAccess
}

}
48 changes: 48 additions & 0 deletions morphir/src/org/finos/morphir/ir/gen1/Attribute.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package org.finos.morphir.ir.gen1

import izumi.reflect.Tag

sealed class Attribute[A](
val name: String,
val initial: A,
val valueCangeInterceptor: AttributeValueChangingInterceptor[A],
private val tag: Tag[A]
) extends Serializable { self =>
import Attribute.*
def :=(value: A): Binding[A] = Binding(self, value)
override def equals(that: Any): Boolean = (that: @unchecked) match {
case that: Attribute[_] => (name, tag) == ((that.name, that.tag))
}

override lazy val hashCode: Int =
(name + tag).hashCode
}
object Attribute {

def apply[A](name: String, initial: A)(implicit tag: Tag[A]): Attribute[A] =
new Attribute(name, initial, AttributeValueChangingInterceptor.KeepNewValue, tag)

def apply[A](name: String, initial: A, interceptor: AttributeValueChangingInterceptor[A])(implicit
tag: Tag[A]
): Attribute[A] =
new Attribute(name, initial, interceptor, tag)

/** Alias for `makeMonoidal`.
*/
def makeMetric[V](name: String, initial: V, combine: (V, V) => V)(implicit tag: Tag[V]): Attribute[V] =
makeMonoidal(name, initial, combine)

def makeMonoidal[V](name: String, initial: V, combine: (V, V) => V)(implicit tag: Tag[V]): Attribute[V] =
new Attribute[V](name, initial, AttributeValueChangingInterceptor(combine), tag)

def unapply[V](property: Attribute[V]): Some[(String, V, AttributeValueChangingInterceptor[V])] = Some(
(property.name, property.initial, property.valueCangeInterceptor)
)

final case class Binding[V](property: Attribute[V], value: V)
}

sealed abstract case class AttributeValue[V] private (value: V, tag: Tag[V])
object AttributeValue {
def apply[V](value: V)(implicit tag: Tag[V]): AttributeValue[V] = new AttributeValue(value, tag) {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.finos.morphir.ir.gen1

sealed trait AttributeValueChangingInterceptor[A] extends ((A, A) => A)
object AttributeValueChangingInterceptor {

def apply[A](f: (A, A) => A): AttributeValueChangingInterceptor[A] = new AttributeValueChangingInterceptor[A] {
override def apply(v1: A, v2: A): A = f(v1, v2)
}

def KeepNewValue[A]: AttributeValueChangingInterceptor[A] =
AttributeValueChangingInterceptor((_, newValue) => newValue)

def KeepOldValue[A]: AttributeValueChangingInterceptor[A] =
AttributeValueChangingInterceptor((oldValue, _) => oldValue)
}
36 changes: 36 additions & 0 deletions morphir/src/org/finos/morphir/ir/gen1/Attributes.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package org.finos.morphir.ir.gen1

import org.finos.morphir.ir.gen1.Attribute.Binding

final class Attributes private (private val map: Map[Attribute[Any], AnyRef]) {
self =>
def ++=(bindings: Seq[Binding[_]]): Attributes = new Attributes(
(self.map.toVector ++ bindings.map(b => b.property.asInstanceOf[Attribute[Any]] -> b.value.asInstanceOf[AnyRef]))
.foldLeft[Map[Attribute[Any], AnyRef]](Map()) { case (acc, (property, value)) =>
acc.updated(
property,
acc.get(property).fold(value)(property.valueCangeInterceptor(_, value).asInstanceOf[AnyRef])
)
}
)
def get[V](property: Attribute[V]): V =
map.get(property.asInstanceOf[Attribute[Any]]).fold(property.initial)(_.asInstanceOf[V])

def hasProperty[V](property: Attribute[V]): Boolean = map.contains(property.asInstanceOf[Attribute[Any]])

private def overwrite[V](property: Attribute[V], value: V): Attributes =
new Attributes(map.updated(property.asInstanceOf[Attribute[Any]], value.asInstanceOf[AnyRef]))

def update[V](property: Attribute[V], f: V => V): Attributes =
overwrite(property, f(get(property)))

def set[V](property: Attribute[V], value: V): Attributes =
update[V](property, property.valueCangeInterceptor(_, value))
}

object Attributes {
type Id[A]
val empty: Attributes = new Attributes(Map.empty)
def apply(bindings: Binding[_]*): Attributes =
empty ++= bindings
}
17 changes: 17 additions & 0 deletions morphir/src/org/finos/morphir/ir/gen1/Documented.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.finos.morphir.ir.gen1

import zio.prelude.*

final case class Documented[+A](doc: String, value: A) {
def map[B](f: A => B): Documented[B] = Documented(doc, f(value))

def flatMap[B](f: A => Documented[B]): Documented[B] = f(value)

def zip[B](that: Documented[B]): Documented[(A, B)] = Documented(doc, (value, that.value))
}

object Documented {
implicit val CovariantDocumented: Covariant[Documented] = new Covariant[Documented] {
def map[A, B](f: A => B): Documented[A] => Documented[B] = _.map(f)
}
}
59 changes: 59 additions & 0 deletions morphir/src/org/finos/morphir/ir/gen1/Field.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package org.finos.morphir.ir.gen1

import org.finos.morphir.ir.gen1.naming.*
import org.finos.morphir.ir.gen1.*
import zio.prelude.*

final case class Field[+A](name: Name, data: A) { self =>

@inline def fieldType[A0](implicit ev: A <:< Type[A0]): Type[A0] = data

def forEach[G[+_]: IdentityBoth: Covariant, B](f: A => G[B]): G[Field[B]] =
f(self.data).map(newType => self.copy(data = newType))

def map[B](f: A => B): Field[B] = Field(name, f(data))

def mapFieldType[A0, A1](f: Type[A0] => Type[A1])(implicit ev: A <:< Type[A0]): Field[Type[A1]] =
self.copy(data = f(self.data))

/// Map the name of the field to get a new field.
def transformFieldName(f: Name => Name): Field[A] = Field(f(name), data)
}

object Field {

def apply[A](name: String, data: A): Field[A] = Field(Name.fromString(name), data)

@inline def define[A](name: String, fieldType: Type[A]): Field[Type[A]] = Field(name, fieldType)
@inline def define[A](name: Name, fieldType: Type[A]): Field[Type[A]] = Field(name, fieldType)

type Untyped = Field[Unit]
object Untyped {
def apply(name: Name): Field[Unit] = Field(name, ())
def unapply(field: Field[Unit]): Name = field.name
}

type Attributed = Field[Type[Attributes]]
object Attributed {
def unapply(field: Field[Type[Attributes]]): Some[(Attributes, Name, Type[Attributes])] =
Some((field.fieldType.attributes, field.name, field.fieldType))
}

final implicit class FieldOfType[A](private val self: Field[Type[A]]) {

def fieldType: Type[A] = self.data

/** Attributes the field with the given `attributes`.
*/
def attributeTypeAs[Attribs](attributes: => Attribs): Field[Type[Attribs]] =
Field(self.name, self.data.mapAttributes(_ => attributes))

/** Attributes the field's type using the given function.
*/
def attributeTypeWith[B](f: A => B): Field[Type[B]] =
Field(self.name, self.data.mapAttributes(f))

def mapAttributes[B](f: A => B): Field[Type[B]] =
Field(self.name, self.data.mapAttributes(f))
}
}
Loading

0 comments on commit c43f442

Please sign in to comment.