Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding Type #302

Merged
merged 1 commit into from
Oct 3, 2024
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
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
Loading