Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/finos/morphir
Browse files Browse the repository at this point in the history
  • Loading branch information
stephengoldbaum committed Apr 17, 2024
2 parents 45cdb45 + 4762e1a commit 509cbd6
Show file tree
Hide file tree
Showing 20 changed files with 7,649 additions and 6,466 deletions.
10 changes: 6 additions & 4 deletions .github/ISSUE_TEMPLATE/Meeting.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,15 @@ Thursday DD MMM yyyy - 11am ET / 3pm UK

### Zoom info

- https://zoom.us/j/95452540437?pwd=TEk0bitJcVFsK3lrWVZCYmxyTm5LZz09
- **Meeting ID:** 954 5254 0437
- **Passcode:** 778814
Join Zoom Meeting
- https://zoom.us/j/99313804465
- Meeting ID: 993 1380 4465
- Passcode: 038632


### Dial-in

- **Find your local number:** https://zoom.us/u/aFGSSGV9x
- **Find your local number:** https://zoom.us/u/avGA76WoI

**Github Repo:** https://github.com/finos/morphir/

Expand Down
6 changes: 4 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
./.idea
.idea/
.fake
.ionide
.ionide

.vscode/
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@

[![FINOS Hosted Platform - LCR Interactive](https://img.shields.io/badge/FINOS%20Hosted%20Platform-LCR%20Interactive-blue)](https://lcr-interactive.finos.org/)
[![FINOS - Active](https://cdn.jsdelivr.net/gh/finos/contrib-toolbox@master/images/badge-active.svg)](https://community.finos.org/docs/governance/Software-Projects/stages/active)
[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/6526/badge)](https://bestpractices.coreinfrastructure.org/projects/6526)
[<img src="https://img.shields.io/badge/slack-@finos/morphir-green.svg?logo=slack">](https://finos-lf.slack.com/messages/morphir/)
Expand Down Expand Up @@ -86,6 +88,13 @@ List the roadmap steps; alternatively link the Confluence Wiki page where the pr
3. Support for Microsoft's Bosque language for defining models.
4. Modeling queries and aggregations across databases and event processing.

## Getting Involved

### Project Meetings

A great way to interact with the Morphir community is to attend the bi-weekly Thursday Morphir meetings.
Email help@finos.org to be added to the meeting invite directly, or find the meeting in the [FINOS Community Calendar](https://calendar.finos.org/).

## Contributing

1. Fork it (<https://github.com/finos/morphir/fork>)
Expand Down
Binary file added docs/Distribution Diagrams/Distribution.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/Distribution Diagrams/Types.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 17 additions & 4 deletions docs/insight-readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,13 @@ A morphir-ir.json file should be generated with the IR content
```
<script src="node_modules/morphir-elm/cli/web/insight.js"></script>
```
3. Now you just need to communicate with elm architecture using javascript.
After including the above script file in your code, you can decide between the two below ways of including Insight in your project.
### Initilazing the Elm App directly
You just need to communicate with elm architecture using javascript.
For more details on interoperability [JavaScript Interoperability ](https://guide.elm-lang.org/interop).
**Note** - Every code below this must be either in javascript file or inside script tags.
### Initialise it with Flags
#### Initialise it with Flags
```
var app = Elm.Morphir.Web.Insight.init({
node: document.getElementById('app'),
Expand All @@ -83,7 +86,7 @@ For more details on interoperability [JavaScript Interoperability ](https://guid
For more details on flags [Flags](https://guide.elm-lang.org/interop/flags.html)
### Send Function Name threw ports
#### Send Function Name through ports
- Function name should be pass as combination of exposed module name + local name.
- If your exposed module is `Insight.UseCase1` and it contains a local function with name `limitTracking`. Pass both separated by a colon `:`
```
Expand All @@ -92,7 +95,7 @@ For more details on flags [Flags](https://guide.elm-lang.org/interop/flags.html)
For more details on ports [Ports](https://guide.elm-lang.org/interop/ports.html)
### Send Function Arguments for a path highlighting
#### Send Function Arguments for a path highlighting
- Sending arguments is a bit complex because you need to encode it first. But we are working parallelly to reduce the complexity of encoding.
- You need to send type information of arguments along with its values otherwise it won't be accepted.
- If function signature is :
Expand All @@ -111,6 +114,16 @@ For more details on ports [Ports](https://guide.elm-lang.org/interop/ports.html)
- For better understanding of json mapping from elm to json refer the below file.
[Json Mapping](https://github.com/finos/morphir-elm/blob/master/docs/json-mapping.md)
### Web component
You can also achieve the above functionality using the included ```<morphir-insight>...<\morphir-insight>``` custom web component, which has two input attributes, `fqn` and `arguments`, for the fully qualified name of the function you wish to dispaly, and the the list of inputs (just like in the above method).
#### Initializing the web component
After including the above tag, it's the developers responsibility to call the provided `.init` function on the web component, which expects a valid Morphir IR distribution in a JSON string format. This init function can be called any time after the HTML has been rendered, and will initialize the web component.
### Limitations
Due to inherent limitations stemming from Elm's architecture and design philosphy (total encapsulation of the elm runtime to be able to guarantee no runtime errors), you can't pass values by reference through the port functions. In our case this means that each time an Insight instance is initialized, a new copy of the Morphir IR is added to the Javascript heap. Developers should be mindful of this, as creating multiple Insights with larger IRs has the possibility to be prohibitively memory intensive.
### Example File
- If you are still confused like how to write code for all that steps, you can have a look at example file.
[Insight API Example File](https://github.com/finos/morphir-elm/blob/master/cli/web/insight.html).
2 changes: 1 addition & 1 deletion docs/morphir-typescript-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ title: TypeScript - Morphir API
# Morphir API for Typescript
The purpose of this documentation is to give a user an understanding of how to use the Morphir API created for Typescript.

This API basically enables adding morphir as a dependency in a Typescript project. This allows a user have access to morphir
This API basically enables adding morphir as a dependency in a Typescript project. This allows a user to have access to morphir
types and modules to build tools and/or to aid work on the morphir generated IR. A use-case of the API is the Cadl frontend,
where the API provides modules in Morphir, mapping them to those in Cadl, in order to generate a Morphir IR as the Cadl emitter runs through
a Cadl project.
Expand Down
91 changes: 91 additions & 0 deletions docs/scala/datamodel/enums.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
---
id: enums
title: Enum (Discriminated Union) Encoding
---
Given the following Scala types and values:
```scala
// Types:
case class OneStreamSink(topic: String)
sealed trait Sink
object Sink {
case class OneStream(sinkData: OneStreamSink) extends Sink
case object ConsoleLog extends Sink
}

// Values:
val os = Sink.OneStream(OneStreamSink(topic = "123"))
val oc = Sink.ConsoleLog
```
and the equivalent in Morphir/ELM:
```elm
-- Types
type alias OneStreamSink = { topic: String }
type Sink =
OneStream {- sinkData: -} OneStreamSink
| ConsoleLog

-- Values:
os: Sink
os = OneStream { topic = "123" }

oc: Sink
oc = ConsoleLog
```

The value `os` would be represented in the Morphir data-model as the following:
```scala
val os = Data.Case(
values = List(
EnumLabel.Named("sinkData") ->
Data.Record(L("topic") -> Data.String("123"))
)
enumLabel = "OneStream",
shape = enumConcept /* will be described in just a minute */
)
```

Note how the OneStream enum fields `sinkData` is represented as `EnumLabel.Named("sinkData")`. Not all languages
support the naming for enum fields. As you can see in the Morphir/ELM example abovem it is commented out. Therefore
instead of `EnumLabel.Named("sinkData")` in the Moprhir-data model, it would be represented as `EnumLabel.Empty`.
```scala
val os = Data.Case(
values = List(
EnumLabel.Empty ->
Data.Record(L("topic") -> Data.String("123"))
)
enumLabel = "OneStream",
shape = enumConcept /* will be described in just a minute */
)
```

The value `oc` would be represented as the following:
```scala
// val oc: Sink = Sink.ConsoleLog // (Scala)
// oc = ConsoleLog // (Morphir/ELM)

val oc = Data.Case(
values = List()
enumLabel = "ConsoleLog",
shape = enumConcept /* will be described in just a minute */
)
```

On a schema-level the `Concept` for this enum would be the following:
```scala
Concept.Enum(
name = "Sink",
cases = List(
Concept.Enum.Case(
L("OneStream"),
fields = List(
EnumLabel.Named("sinkData") ->
Concept.Record(L("topic") -> Concept.String)
)
),
Concept.Enum.Case(
L("ConsoleLog"),
fields = List()
)
)
)
```
11 changes: 11 additions & 0 deletions docs/scala/datamodel/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
id: datamodel
title: Data Model
---

The Morphir data model (MDM) was created to simplify integration between data formats and the Morphir IR. Most data
formats have no concept of logic, and as such, a significant portion of the Morphir IR is not relevant if your
intention is to provide a front-end or back-end for a data format.

The Morphir data model implements a front-end and back-end to the Morphir IR and allows those integrating data formats
to only have to integrate with MDM, which closer resembles other data format integration activities.
56 changes: 56 additions & 0 deletions docs/scala/datamodel/lists.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---
id: lists
title: Lists
---
Given the following Scala:
```scala
val items = List("one", "two", "three")
```
and the equivalent Morphir/ELM lists:
```elm
items: List String
items = ["one", "two", "three"]
```

This data should be represented in the Morphir data-model as the following:
```scala
Data.List(
values = List(Data.String("one"), Data.String("two"), Data.String("three")),
shape = Concept.List(elementType = Concept.String)
)
```

List should be able to contain Records, Enums, or any other subtype of Data.
For example, the following data in Scala and Morphir/Elm:
```scala
// Scala
case class Person(name: String, age: Int)
val people = List(Person("Joe", 123), Person("Jim", 456))
```
```elm
-- Morphir/ELM
type alias Person = { name: String, age: Int }
people: List Person
people = [ {name = "Joe", age = 123}, {name = "Jim", age = 456} ]
```
should be represented in the Morphir data-model as the following:
```scala
Data.List(
values = List(
Data.Record(
L("name") -> Data.String("Joe"), L("age") -> Data.Int32(123),
),
Data.Record(
L("name") -> Data.String("Jim"), L("age") -> Data.Int32(456),
)
),
shape = Concept.List(
elementType =
Concept.Record(
L("name") -> Concept.String,
L("age") -> Concept.Int32
)
)
)

```
28 changes: 28 additions & 0 deletions docs/scala/datamodel/maps.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
id: maps
title: Maps
---
Given the following Scala Map:
```scala
val myMap = Map("foo" -> 123, "bar" -> 456)
```
and the equivalent Morphir/ELM dictionary:
```elm
myMap: Dict String Int
myMap = Dict.fromList
[
("foo", 123),
("bar", 456)
]
```

This data should be represented in the Morphir data-model as the following:
```scala
Data.Map(
values = Map(
Data.String("foo") -> Data.Int(123),
Data.String("bar") -> Data.Int(456),
)
shape = Concept.Map(keyType = Concept,String, valueType = Concept.Int)
)
```
16 changes: 16 additions & 0 deletions docs/scala/datamodel/primitives.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
id: primitives
title: Primitive Encoding
---
The following encodings are supported from Scala values into Morphir DDL primitives:

| Morphir DDL | Morphir DDL Type | Scala Class | Scala Example |
|--------------------------|-------------------|---------------------|-----------------------|
| Data.Boolean(true) | Concept.Boolean | scala.Boolean | true |
| Data.Byte(0xf) | Concept.Byte | scala.Byte | 0xf |
| Data.Decimal(BigDecimal) | Concept.Decimal | scala.BigDecimal | BigDecimal("123") |
| Data.Integer(BigInt) | Concept.Integer | scala.BigInt | BigInt("123") |
| Data.Int16(123) | Concept.Int16 | scala.Short | 123.toShort |
| Data.Int32(123) | Concept.Int32 | scala.Int | 123 |
| Data.String("value") | Concept.String | java.lang.String | value |
| Data.LocalDate | Concept.LocalDate | java.time.LocalDate | LocalDate(2023, 1, 1) |
68 changes: 68 additions & 0 deletions docs/scala/datamodel/records.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
---
id: records
title: Record (Case Class) Encoding
---
Scala Case Classes and Morphir/ELM records are represented as the Data.Record type.
Given the following Scala values:
```scala
case class Person(name: String, age: Int)
val joe = Person("Joe", 123)
```

and the equivalent Morphir/ELM value:
```elm
person: { name: String, age: Int }
person = { name = "Joe", age = 123 }
```

The Data and Concept that represents the above is as follows:
```scala
Data.Record(
values = List(
L("name") -> Data.String("Joe"),
L("age") -> Data.Int(123)
)
shape = Concept.Record(
values = List(
L("name") -> Concept.String
L("age") -> Concept.Int
)
)
)
```

The fields of records may themselves be records (as well as collections, enums, or any other kind of Data object).
Given the following Scala data:
```scala
case class Name(first: String, last: String)
case class Person(name: Name, age: Int)

val joe = Person(Name("Joe", "Bloggs"), 123)
```

and the equivalent Morphir/ELM data:
```elm
type alias Name = { first: String, last: String }

joe: { name: Name, age: Int }
joe = {
name = { first = "Joe", last = "Bloggs" },
age = 123
}
```
The data is represented as the following:
```scala
Data.Record(
values = List(
L("name") -> Data.Record(L("first") -> "Joe", L("last") -> "Bloggs")
L("age") -> Data.Int32(123)
),
concept = Concept.Record(
L("name") ->
Data.Record(L("first") -> Concept.String, L("last") -> Concept.String)
L("age") ->
Data.Int32
)
)

```
Loading

0 comments on commit 509cbd6

Please sign in to comment.