From 4d192147fafa8d209d95362278afc53ba2bf51b8 Mon Sep 17 00:00:00 2001 From: kelly-thai <89568879+kelly-thai@users.noreply.github.com> Date: Tue, 27 Aug 2024 11:03:50 -0500 Subject: [PATCH] adding more showcases (#831) --- .../Build an M2M hosted service/info.md | 7 +- .../Querying/Having clause/code.pure | 152 ++++++++++++++++++ .../Essential/Querying/Having clause/info.md | 13 ++ .../Super types/code.pure | 20 +++ .../Super types/info.md | 6 +- .../Mapping/service/basic/code.pure | 28 ++-- .../Model Store/Mapping/service/basic/info.md | 36 ++++- .../Connection/Postgres/code.pure | 37 +++++ .../Connection/Postgres/info.md | 10 +- .../Mapping/Joins/Distinct Mapping/code.pure | 107 ++++++++++++ .../Mapping/Joins/Distinct Mapping/info.md | 7 + 11 files changed, 398 insertions(+), 25 deletions(-) create mode 100644 showcases/data/Essential/Querying/Having clause/code.pure create mode 100644 showcases/data/Essential/Querying/Having clause/info.md create mode 100644 showcases/data/Store/Relational Store/Mapping/Joins/Distinct Mapping/code.pure create mode 100644 showcases/data/Store/Relational Store/Mapping/Joins/Distinct Mapping/info.md diff --git a/showcases/data/End To End Examples/Build an M2M hosted service/info.md b/showcases/data/End To End Examples/Build an M2M hosted service/info.md index 8d8ed1543..b7202a476 100644 --- a/showcases/data/End To End Examples/Build an M2M hosted service/info.md +++ b/showcases/data/End To End Examples/Build an M2M hosted service/info.md @@ -1,7 +1,4 @@ --- -title: Build an M2M hosted service -description: -development: true +Title: Legend Model-to-Model Services & Hosting +Description: Example implementation of Legend Model-to-Model Services and Hosting --- - -TODO: Some dummy description \ No newline at end of file diff --git a/showcases/data/Essential/Querying/Having clause/code.pure b/showcases/data/Essential/Querying/Having clause/code.pure new file mode 100644 index 000000000..a23cce5e4 --- /dev/null +++ b/showcases/data/Essential/Querying/Having clause/code.pure @@ -0,0 +1,152 @@ +###Relational +Database example::store::MyDepartmentStore +( + Schema DepartmentStore + ( + Table EmployeeDepartment + ( + uid INTEGER PRIMARY KEY, + employeeName VARCHAR(100) NOT NULL, + department VARCHAR(100) NOT NULL + ) + ) +) + + +###Service +Service example::service::EmployeeAssignmentService +{ + pattern: '/EmployeeAssignmentService'; + ownership: DID { identifier: '' }; + documentation: ''; + autoActivateUpdates: true; + execution: Single + { + query: |example::model::EmployeeAssignment.all()->groupBy( + [ + x|$x.name + ], + [ + agg( + x|$x.department, + x|$x->distinct()->count() + ) + ], + [ + 'Name', + 'Distinct Departments' + ] + )->filter( + row|$row.getInteger('Distinct Departments') > 1 + ); + mapping: example::mapping::EmployeeAssignmentMapping; + runtime: example::runtime::EmployeeAssignmentRuntime; + } +} + + +###Pure +Class example::model::EmployeeAssignment +{ + name: String[1]; + department: String[1]; +} + + +###Mapping +Mapping example::mapping::EmployeeAssignmentMapping +( + *example::model::EmployeeAssignment: Relational + { + ~primaryKey + ( + [example::store::MyDepartmentStore]DepartmentStore.EmployeeDepartment.uid + ) + ~mainTable [example::store::MyDepartmentStore]DepartmentStore.EmployeeDepartment + name: [example::store::MyDepartmentStore]DepartmentStore.EmployeeDepartment.employeeName, + department: [example::store::MyDepartmentStore]DepartmentStore.EmployeeDepartment.department + } + + testSuites: + [ + TestSuite1: + { + function: |example::model::EmployeeAssignment.all()->project( + [ + x|$x.name, + x|$x.department + ], + [ + 'Name', + 'Department' + ] +); + tests: + [ + Test1: + { + data: + [ + example::store::MyDepartmentStore: + Relational + #{ + DepartmentStore.EmployeeDepartment: + 'uid,employeeName,department\n'+ + '1001,Elsa,Electrical\n'+ + '1002,Etienne,Electrical\n'+ + '1003,Chidi,Cosmetics\n'+ + '1004,Chidi,Cafe\n'+ + '1005,Heidi,Haberdashery\n'+ + '1006,Heidi,Homewares\n'; + }# + ]; + asserts: + [ + expectedAssertion: + EqualToJson + #{ + expected: + ExternalFormat + #{ + contentType: 'application/json'; + data: '[\n {\n "Name": "Elsa",\n "Department": "Electrical"\n },\n {\n "Name": "Etienne",\n "Department": "Electrical"\n },\n {\n "Name": "Chidi",\n "Department": "Cosmetics"\n },\n {\n "Name": "Chidi",\n "Department": "Cafe"\n },\n {\n "Name": "Heidi",\n "Department": "Haberdashery"\n },\n {\n "Name": "Heidi",\n "Department": "Homewares"\n }\n]'; + }#; + }# + ]; + } + ]; + } + ] +) + + +###Connection +RelationalDatabaseConnection example::connection::MyDepartmentStoreConnection +{ + store: example::store::MyDepartmentStore; + type: H2; + specification: LocalH2 + { + testDataSetupSqls: [ + 'Create Schema if not exists DepartmentStore;\nDrop Table if exists DepartmentStore.EmployeeDepartment;\nCreate Table DepartmentStore.EmployeeDepartment (uid INTEGER, employeeName VARCHAR(100), department VARCHAR(100));\nINSERT INTO DepartmentStore.EmployeeDepartment(uid,employeeName,department) VALUES (1001,\'Elsa\',\'Electrical\');\nINSERT INTO DepartmentStore.EmployeeDepartment(uid,employeeName,department) VALUES (1002,\'Etienne\',\'Electrical\');\nINSERT INTO DepartmentStore.EmployeeDepartment(uid,employeeName,department) VALUES (1003,\'Chidi\',\'Cosmetics\');\nINSERT INTO DepartmentStore.EmployeeDepartment(uid,employeeName,department) VALUES (1004,\'Chidi\',\'Cafe\');\nINSERT INTO DepartmentStore.EmployeeDepartment(uid,employeeName,department) VALUES (1005,\'Heidi\',\'Haberdashery\');\nINSERT INTO DepartmentStore.EmployeeDepartment(uid,employeeName,department) VALUES (1006,\'Heidi\',\'Homewares\');' + ]; + }; + auth: DefaultH2; +} + + +###Runtime +Runtime example::runtime::EmployeeAssignmentRuntime +{ + mappings: + [ + example::mapping::EmployeeAssignmentMapping + ]; + connections: + [ + example::store::MyDepartmentStore: + [ + connection_1: example::connection::MyDepartmentStoreConnection + ] + ]; +} \ No newline at end of file diff --git a/showcases/data/Essential/Querying/Having clause/info.md b/showcases/data/Essential/Querying/Having clause/info.md new file mode 100644 index 000000000..90222de9d --- /dev/null +++ b/showcases/data/Essential/Querying/Having clause/info.md @@ -0,0 +1,13 @@ +--- +title: Having clause in Alloy +description: Using services to simulate HAVING in SQL statements +--- + +This project showcases how services can be used to simulate the same behavior as the HAVING clause in a typical SQL SELECT statement. +The service here behaves the same as if this query was run: +SELECT + username, + count(distinct(department)) +FROM table +GROUP BY username +HAVING count(distinct(department)) > 1 diff --git a/showcases/data/Model/Leverage profiles in your model/Super types/code.pure b/showcases/data/Model/Leverage profiles in your model/Super types/code.pure index e69de29bb..f1581e0fb 100644 --- a/showcases/data/Model/Leverage profiles in your model/Super types/code.pure +++ b/showcases/data/Model/Leverage profiles in your model/Super types/code.pure @@ -0,0 +1,20 @@ +###Text +Text showcase::model::README +{ + type: markdown; + content: '---\ntitle: Super types\ndescription: This an example that shows how to use super types in your data model\n---\n\nThe showcase shows how you can add a super type to a class in your data model. Navigate to the \'Super Type\' profile and click on \'+\' to add a super type. \nIn this example, the class \'Animal\' has been added as a superclass in class \'Dog\'. The class \'Dog\' has inherited all properties from class \'Animal\'.'; +} + + +###Pure +Class showcase::model::Dog extends showcase::model::Animal +{ + breed: String[1]; +} + +Class showcase::model::Animal +{ + name: String[1]; + sound: String[1]; + age: String[1]; +} diff --git a/showcases/data/Model/Leverage profiles in your model/Super types/info.md b/showcases/data/Model/Leverage profiles in your model/Super types/info.md index 7428c6d30..696af0967 100644 --- a/showcases/data/Model/Leverage profiles in your model/Super types/info.md +++ b/showcases/data/Model/Leverage profiles in your model/Super types/info.md @@ -1,7 +1,7 @@ --- title: Super types -description: -development: true +description: This an example that shows how to use super types in your data model --- -TODO: Some dummy description \ No newline at end of file +The showcase shows how you can add a super type to a class in your data model. Navigate to the 'Super Type' profile and click on '+' to add a super type. +In this example, the class 'Animal' has been added as a superclass in class 'Dog'. The class 'Dog' has inherited all properties from class 'Animal'. \ No newline at end of file diff --git a/showcases/data/Store/Model Store/Mapping/service/basic/code.pure b/showcases/data/Store/Model Store/Mapping/service/basic/code.pure index 9a904c3d6..cebb72342 100644 --- a/showcases/data/Store/Model Store/Mapping/service/basic/code.pure +++ b/showcases/data/Store/Model Store/Mapping/service/basic/code.pure @@ -1,14 +1,22 @@ ###Data -Data data::IBMFirmData +Data data::MyFirmData { ExternalFormat #{ contentType: 'application/json'; - data: '{\n "employees": [\n {\n "firstName": "John",\n "lastName": "Smith"\n }\n ],\n "legalName": "IBM",\n "type": "llc"\n}'; + data: '{\n "employees": [\n {\n "firstName": "John",\n "lastName": "Smith"\n }\n ],\n "legalName": "Business",\n "type": "llc"\n}'; }# } +###Text +Text mapping::m2mREADME +{ + type: plainText; + content: '---\nTitle: Legend Model-to-Model Services & Hosting\nDescription: Example implementation of Legend Model-to-Model Services and Hosting\n---\n\n# Overview\n\nTry out Legend Services! [Go to the guide!](https://legend.finos.org/docs/overview/legend-overview)\n\n# Use Legend to Create Model-to-Model Mapping, Services, and Hosting\n\n## Prerequisite\n\n## Modeling\nThe first step of this implementation involves creating models.\n\nFor the purposes of this showcase (and for any model-to-model service), you will need to create two models: one source model and one target model.\n\nBy doing this, you are able to take in input data and transform this data from source to target.\n\nIn this example, our input data is stored in JSON format in `data::MyFirmData`.\n\nOur JSON data is connected to via `mapping::FirmConnection`, and `mapping::FirmRuntime` uses the connection to map the data into the model.\n\nOur source models are `model::Firm` and `model::Person`.\n\nOur target models are `model::target::_Firm` and `model::target::_Person`\n\n## Model-to-Model Service\nServices contain three different components, as follows:\n1. Function: uses a graphFetch query to select the properties of the target class that should be mapped and returned in the JSON response\n 1a. In our example, our Function is located under `mapping::FirmService`\n2. Mapping: a standard model-to-model mapping\n 2a. In our example, our Mapping is located under `mapping::ModelToModelMapping`\n3. Runtime: connection types are JsonModel, XmlModel, and FlatData.\n 3a. In our example, our Runtime is a JsonModel, and is located under `mapping::FirmRuntime`'; +} + + ###Service Service mapping::FirmService { @@ -54,7 +62,7 @@ Service mapping::FirmService ExternalFormat #{ contentType: 'application/json'; - data: '{\n "employees": [\n {\n "firstName": "John",\n "lastName": "Smith"\n }\n ],\n "legalName": "IBM",\n "type": "llc"\n}'; + data: '{\n "employees": [\n {\n "firstName": "John",\n "lastName": "Smith"\n }\n ],\n "legalName": "Business",\n "type": "llc"\n}'; }# ] ] @@ -72,7 +80,7 @@ Service mapping::FirmService ExternalFormat #{ contentType: 'application/json'; - data: '{\n "myLegalName()": "my name is: IBM",\n "name": "IBM",\n "employees": [\n {\n "fullName": "John Smith"\n }\n ]\n}'; + data: '{\n "myLegalName()": "my name is: Business",\n "name": "Business",\n "employees": [\n {\n "fullName": "John Smith"\n }\n ]\n}'; }#; }# ] @@ -222,7 +230,7 @@ Mapping mapping::ModelToModelMapping }# ]; }, - IBMData: + MyData: { doc: ''; data: @@ -233,7 +241,7 @@ Mapping mapping::ModelToModelMapping model::Firm: Reference #{ - data::IBMFirmData + data::MyFirmData }# }# ]; @@ -246,12 +254,12 @@ Mapping mapping::ModelToModelMapping ExternalFormat #{ contentType: 'application/json'; - data: '{\r\n "employees" : [ {\r\n "fullName" : "John Smith"\r\n } ],\r\n "name" : "IBM",\r\n "myLegalName()" : "my name is: IBM"\r\n}'; + data: '{\r\n "employees" : [ {\r\n "fullName" : "John Smith"\r\n } ],\r\n "name" : "Business",\r\n "myLegalName()" : "my name is: Business"\r\n}'; }#; }# ]; }, - IBMData2: + MyData2: { doc: ''; data: @@ -262,7 +270,7 @@ Mapping mapping::ModelToModelMapping model::Firm: Reference #{ - data::IBMFirmData + data::MyFirmData }# }# ]; @@ -275,7 +283,7 @@ Mapping mapping::ModelToModelMapping ExternalFormat #{ contentType: 'application/json'; - data: '{\n "employees" : [ {\n "fullName" : "John Smith"\n } ],\n "name" : "IBM",\n "myLegalName()" : "my name is: IBM"\n}'; + data: '{\n "employees" : [ {\n "fullName" : "John Smith"\n } ],\n "name" : "Business",\n "myLegalName()" : "my name is: Business"\n}'; }#; }# ]; diff --git a/showcases/data/Store/Model Store/Mapping/service/basic/info.md b/showcases/data/Store/Model Store/Mapping/service/basic/info.md index 5c34678c1..38bf9cabe 100644 --- a/showcases/data/Store/Model Store/Mapping/service/basic/info.md +++ b/showcases/data/Store/Model Store/Mapping/service/basic/info.md @@ -1,6 +1,36 @@ --- -title: Model To Model Service - Querying _Firm using json input -description: Mapping of Firm to _Firm with tests and a service fetching _Firm output +Title: Legend Model-to-Model Services & Hosting +Description: Example implementation of Legend Model-to-Model Services and Hosting --- -This project showcases a model to model mapping from `Firm` to `_Firm` outlining a mapping test and a service test for model to model. \ No newline at end of file +# Overview + +Try out Legend Services! [Go to the guide!](https://legend.finos.org/docs/overview/legend-overview) + +# Use Legend to Create Model-to-Model Mapping, Services, and Hosting + +## Prerequisite + +## Modeling +The first step of this implementation involves creating models. + +For the purposes of this showcase (and for any model-to-model service), you will need to create two models: one source model and one target model. + +By doing this, you are able to take in input data and transform this data from source to target. + +In this example, our input data is stored in JSON format in `data::MyFirmData`. + +Our JSON data is connected to via `mapping::FirmConnection`, and `mapping::FirmRuntime` uses the connection to map the data into the model. + +Our source models are `model::Firm` and `model::Person`. + +Our target models are `model::target::_Firm` and `model::target::_Person` + +## Model-to-Model Service +Services contain three different components, as follows: +1. Function: uses a graphFetch query to select the properties of the target class that should be mapped and returned in the JSON response + 1a. In our example, our Function is located under `mapping::FirmService` +2. Mapping: a standard model-to-model mapping + 2a. In our example, our Mapping is located under `mapping::ModelToModelMapping` +3. Runtime: connection types are JsonModel, XmlModel, and FlatData. + 3a. In our example, our Runtime is a JsonModel, and is located under `mapping::FirmRuntime` \ No newline at end of file diff --git a/showcases/data/Store/Relational Store/Connection/Postgres/code.pure b/showcases/data/Store/Relational Store/Connection/Postgres/code.pure index e69de29bb..b19f85be7 100644 --- a/showcases/data/Store/Relational Store/Connection/Postgres/code.pure +++ b/showcases/data/Store/Relational Store/Connection/Postgres/code.pure @@ -0,0 +1,37 @@ +###Relational +Database showcase::store::DemoStore +( + Table Person + ( + id INTEGER PRIMARY KEY, + firm_id INTEGER, + firstName VARCHAR(200), + lastName VARCHAR(200) + ) +) + + +###Text +Text showcase::README +{ + type: markdown; + content: '---\ntitle: Postgres Connection\ndescription: Showcase of Postgres connection\n---\n\n Feature: Postgres connection is defined when we need to read data from Postgres.\n Usage: Define a new connection and choose Connection Type as "Relational Connection", Database Type as "Postgres". Add database specifications - host, port, db name. Also mention the authentication strategy.'; +} + + +###Connection +RelationalDatabaseConnection showcase::connection::PostgresConnection +{ + store: showcase::store::DemoStore; + type: Postgres; + specification: Static + { + name: 'DemoStore'; + host: 'url.here'; + port: 480; + }; + auth: DelegatedKerberos + { + serverPrincipal: 'kerberos'; + }; +} diff --git a/showcases/data/Store/Relational Store/Connection/Postgres/info.md b/showcases/data/Store/Relational Store/Connection/Postgres/info.md index 8e10ed66f..f1c4c5749 100644 --- a/showcases/data/Store/Relational Store/Connection/Postgres/info.md +++ b/showcases/data/Store/Relational Store/Connection/Postgres/info.md @@ -1,5 +1,7 @@ --- -title: Relational Database Connection Postgres -description: Examples of all valid Postgres connection specs -development: true ---- \ No newline at end of file +title: Postgres Connection +description: Showcase of Postgres connection +--- + +Feature: Postgres connection is defined when we need to read data from Postgres. +Usage: Define a new connection and choose Connection Type as "Relational Connection", Database Type as "Postgres". Add database specifications - host, port, db name. Also mention the authentication strategy. \ No newline at end of file diff --git a/showcases/data/Store/Relational Store/Mapping/Joins/Distinct Mapping/code.pure b/showcases/data/Store/Relational Store/Mapping/Joins/Distinct Mapping/code.pure new file mode 100644 index 000000000..b2746c698 --- /dev/null +++ b/showcases/data/Store/Relational Store/Mapping/Joins/Distinct Mapping/code.pure @@ -0,0 +1,107 @@ +###Relational +Database showcase::stores::SimpleDB +( + Schema SimpleDBSchema + ( + Table Pets + ( + id INTEGER PRIMARY KEY, + owner_id INTEGER, + pet_type VARCHAR(50), + pet_name VARCHAR(50) + ) + Table People + ( + id INTEGER PRIMARY KEY, + person_name VARCHAR(200) + ) + ) + + Join PersonPet(SimpleDBSchema.Pets.owner_id = SimpleDBSchema.People.id) +) + + +###Text +Text showcase::README +{ + type: markdown; + content: '---\ntitle: Relational Mapping with Join and Distinct showcase\ndescription: Showcase displaying a relational mapping with a join and a distinct clause\n---\n\nIn this showcase, two tables (Pets and People) are joined to find all distinct combinations(Person Name and Pet Type) of People and the type of pets they have. A test case explaining the use case is added.\n\n'; +} + + +###Pure +Class showcase::models::Pet +{ + pet_type: String[0..1]; + person_name: String[0..1]; +} + + +###Mapping +Mapping showcase::mapping::PetMapping +( + showcase::models::Pet: Relational + { + ~distinct + ~primaryKey + ( + [showcase::stores::SimpleDB]SimpleDBSchema.Pets.id + ) + ~mainTable [showcase::stores::SimpleDB]SimpleDBSchema.Pets + pet_type: [showcase::stores::SimpleDB]SimpleDBSchema.Pets.pet_type, + person_name: [showcase::stores::SimpleDB]@PersonPet | [showcase::stores::SimpleDB]SimpleDBSchema.People.person_name + } + + testSuites: + [ + testSuite1: + { + function: |showcase::models::Pet.all()->project( + [ + x|$x.person_name, + x|$x.pet_type + ], + [ + 'Person name', + 'Pet type' + ] +)->distinct(); + tests: + [ + test1: + { + data: + [ + showcase::stores::SimpleDB: + Relational + #{ + SimpleDBSchema.People: + 'id,person_name\n'+ + '1,Jim\n'+ + '2,Tom\n'; + + SimpleDBSchema.Pets: + 'id,owner_id,pet_type,pet_name\n'+ + '1,1,Dog,Coco\n'+ + '2,1,Dog,Pam\n'+ + '3,2,Cat,Van\n'; + }# + ]; + asserts: + [ + expectedAssertion: + EqualToJson + #{ + expected: + ExternalFormat + #{ + contentType: 'application/json'; + data: '[\n {\n "Person name": "Jim",\n "Pet type": "Dog"\n },\n {\n "Person name": "Tom",\n "Pet type": "Cat"\n }\n]'; + }#; + }# + ]; + } + ]; + } + ] +) diff --git a/showcases/data/Store/Relational Store/Mapping/Joins/Distinct Mapping/info.md b/showcases/data/Store/Relational Store/Mapping/Joins/Distinct Mapping/info.md new file mode 100644 index 000000000..ef8d0f5b6 --- /dev/null +++ b/showcases/data/Store/Relational Store/Mapping/Joins/Distinct Mapping/info.md @@ -0,0 +1,7 @@ +--- +title: Relational Mapping with Join and Distinct showcase +description: Showcase displaying a relational mapping with a join and a distinct clause +--- + +In this showcase, two tables (Pets and People) are joined to find all distinct combinations(Person Name and Pet Type) of People and the type of pets they have. A test case explaining the use case is added. +