-
Notifications
You must be signed in to change notification settings - Fork 56
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #302 from michelchan/addtype
Adding Type
- Loading branch information
Showing
20 changed files
with
1,096 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
59 changes: 59 additions & 0 deletions
59
morphir/src/org/finos/morphir/ir/gen1/AccessControlled.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) {} | ||
} |
15 changes: 15 additions & 0 deletions
15
morphir/src/org/finos/morphir/ir/gen1/AttributeValueChangingInterceptor.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)) | ||
} | ||
} |
Oops, something went wrong.