DAML: Reference and set conditions to a pre-defined list in a seperate template - daml

I'm new to DAML and have been scratching my head over this for two solid days.
In this voting system specified in "template Voting", an actor has the ability to add a voter party to a list of voters specified as "choice Add". This voters list (I presume a list) is defined as "voters : Set Party", (of which I can't seem to find the definition), and some conditions are defined in "Choice Vote" and "Choice Decide".
I'm trying to remove the "Choice Add" ability and instead pre-define all voters in a list defined in a separate template. If I understand correctly these predefined voters must be declared as a list: [Party] I created a template called "Creation" containing some variables in conjunction with a custom type called "CreationRights" containing the to be voters list which must be referenced from the voting template.
However, I can't seem to refer to this list in any way. Changing the voters data type to [Party] also gives an error for "voters" in Choice Decide and Choice Vote. rendering the conditions specified unusable:
Couldn't match expected type 'Set a1' with actual type '[Party]'
How can I reference to the predefined voters (votingRight) list while still applying the condition set?
Any tips are very welcome!
Code:
data CreationRights = CreationRights
with
votingRight : [Party]
deriving (Eq, Show)
template Creation
with
actor : Party
creationId : Text
title : Text
votingRight : CreationRights
where
signatory actor
template Voting
with
actor : Party
claim : Claim
voters : Set Party
voted : Set Party
votes : [Bool]
where
signatory actor, voted
observer voters
key (actor, claim) : VotingKey
maintainer key._1
---choice Add : ()
---with voter : Party
---controller actor
---do
---create this with voters = S.insert voter voters
---pure ()
choice Decide : ContractId Decision
controller actor
do
assertMsg "At least 60% must have voted" $ ((size voters / 100) * 60) <= length votes
let approvals = length $ L.filter (\v -> v) votes
let disapprovals = length $ L.filter (\v -> not v) votes
let accept = approvals > disapprovals
create Decision with ..
choice Vote : ()
with
voter : Party
accept : Bool
controller voter
do
assertMsg "Voter not added" $ member voter voters
assertMsg "Voter already voted" $ not $ member voter voted
create this with voted = S.insert voter voted; votes = accept :: votes
pure ()
template Decision
with
actor : Party
claim : Claim
voters : Set Party
accept : Bool
where
signatory actor, voters

You don't have to do any of this to create a Voting instance without using Add. Voting defines its signatories to be actor, voted, so if voted is either empty or a singleton containing the same party, then the initial Voting instance only has one signatory. That means it can be created directly by actor without further interactions. I have included a simplified demonstration of this at the end of this answer.
Given you have created an instance of the Creation, you will have a copy of your list of voters on the ledger. At that point, if you want to use that list, you will have to either exercise a choice on that contract or read that contract off the ledger. You can do the latter with fetch, fetchByKey, lookup, and lookupByKey within a choice on another contract (although you will need to provide either the key or contractId). However as this template instance represents an authority to create Voting instances, representing this authority directly as a choice on Creation is recommended.
Finally, if you change the datatype of voters from a Set to a List then you will also have to change the corresponding functions that use that parameter. So, for instance, S.insert voter voted would have to become voter :: voted or similar.
daml 1.2
module Voting where
import DA.Next.Set as S
import DA.List as L
type Claim = Text
type VotingKey = (Party, Claim)
template Voting
with
actor : Party
claim : Claim
voters : Set Party
voted : Set Party
votes : [Bool]
where
signatory actor, voted
observer voters
key (actor, claim) : VotingKey
maintainer key._1
choice Decide : ContractId Decision
controller actor
do
assertMsg "At least 60% must have voted" $ ((size voters / 100) * 60) <= length votes
let approvals = length $ L.filter identity votes
let disapprovals = length $ L.filter not votes
let accept = approvals > disapprovals
create Decision with actor; claim; voters; accept
choice Vote : ContractId Voting
with
voter : Party
accept : Bool
controller voter
do
assertMsg "Voter not added" $ member voter voters
assertMsg "Voter already voted" . not $ member voter voted
create this with voted = S.insert voter voted; votes = accept :: votes
template Decision
with
actor : Party
claim : Claim
voters : Set Party
accept : Bool
where
signatory actor, voters
test = scenario do
alice <- getParty "Alice"
bob <- getParty "Bob"
charlie <- getParty "Charlie"
alice `submit` create
Voting with
actor = alice
claim = "Pizza"
voters = fromList [ alice, bob, charlie ]
voted = empty
votes = []

Related

Changing attributes over time in relational database

At the core of my app is a table called Entities:
Entities:
-----------
id: number // PK
name: string
position_x: number
position_y: number
These entities have interactions with each other, called Events:
Events:
-----------
id: number // PK
name: string
date: Date
from: number // Entities FK
to: number // Entities FK
With events, we can manage all kinds of events between two entities. By selecting a timestamp / event, we can "time-travel" through each event, and see how changes affect the entities.
I just learned we want to support changes to entity attributes in the timeline as well. (travelling back should still get you the original attributes). So now I want to create a new Event-like table, which would look something like this:
SingleEntityEvents:
-----------
id: number // PK
name: string
date: Date
to: number // Entities FK
type: enum // CHANGE_NAME | CHANGE_POSITION
payload: json
Now my app would get the entities and render the original name if applicable, but render an updated name if there is a CHANGE_NAME event happening before the currently selected date. However, now I am leaning towards getting rid of the Entities table entirely, and make everything (including Entity creation) an event. But then how do I properly refer to these entities in the original (from -> to) Events? Is this even possible?
In other words, I want to be able to model this stream of events, but I am not sure how to:
Create entity through event:
name: 'Create Entity'
date: 01/01/2022
entityID: 123 // Its not to reference but to create an entity with this ID?
type: CREATE_ENTITY
payload: {
"name": "New Entity",
"position_x": 1,
"position_y": 0
}
If I select any time after this first event, the app should render an entity called "New Entity", positioned on coordinate (1, 0).
Update name of entity through event
name: 'Update Entity Name'
date: 01/03/2022
entityID: 123 // Now, since this is an update event, this is an actual reference to the previously created entity
type: UPDATE_ENTITY_NAME
payload: "Foo Bar"
If I select any time after this second event, the app should now render the same entity but it's now called "Foo Bar". Its position is unchanged so its still on (1, 0).
My question is, are there best practices to model such event streams? And how do I go about creating this entity ID?

How to take two paramters (start_date and end date) to filter out events in django using query_params.get()?

I want to pass two parameters in GET method in django. The one is start_date and the second is end_date. But I just know about passing only one method. here is my code where I want to filter out account deposit history in range of dates .
class BusinessDonationHistoryController(BaseController):
view = ListView
#entity(Business, arg="business")
def read(self, request, response, business):
request.query_params.get() #Here I need help
deposits = Deposit.objects.filter(
business=business, deposit_type=deposit_types.BUSINESS_DONATION)
credit_accounts = CreditAccount.objects.filter(deposit__in=deposits)
deposit_map = defaultdict(list)
# create a mapping of deposit id and associated credit accounts
for credit_account in credit_accounts:
deposit_map[credit_account.deposit_id].append(credit_account)
history = []
for deposit in deposits:
history.append({
"date": deposit.created_date,
"total_amount": from_cents(deposit.amount),
"amount_disbursed": from_cents(sum([ca.total_amount - ca.current_amount for ca in deposit_map.get(deposit.id)]))
})
print(history)
Checked all the links on StackOverflow but I found nothing relevant.
checked this link even

Odoo CSV import: Found multiple matches for field

I am using https://github.com/tfrancoi/odoo_csv_import to import data into Odoo "res.partner" model. There is no problem importing most of the fields, but when I try to import the field state_id this error is thrown: "Found multiple matches for field 'State' (2 matches)".
res_partner_mapping = {
(........ more fields here)
'country_id/id' : mapper.const('base.es'),
'state_id': mapper.map_val('myStateField', my_state_dictionary),
}
Here my_state_dictionary simply returns the state_id searched, for example "AV", "M" or "B".
The problem is that state_id is a a composed key so it should be filtered by country_id and state_id. For example, "AV" is a state in Spain, but it is also a different state in Italy, so if it is only filtered by state_id it returns 2 records.
The field is declared in Odoo this way:
state = fields.Many2one('country',related=city.country)
How can I specify the relation related=city.country to import the data with odoo_csv_import?
I recently had the same problem and this is how I fixed it: I added the create function where I am looking for the state with my country code.
judet_id is the state ID field in my model and RO is country code.
#api.model
def create(self, vals):
state_curent = self.env['res.country.state'].search([("id","=",vals['judet_id'])])
if(state_curent and state_curent.country_id.code != 'RO'):
state = self.env['res.country.state'].search([("code","=", state_curent.code), ("country_id.code","=", "RO")])
if state:
vals['judet_id'] = state.id
return super().create(vals)

writing script in scala to join two mysql tables and create one object (quill)

I have two mysql tables: Owners & Pets
Owner case class:
Owner(id: Int, name: String, age: Int)
Pet case class:
Pet(id: Int, ownerId: Int, type: String, name: String)
I want to create out of those tables list of OwnerAndPets:
case class OwnerAndPets(ownerId: Int,
name: String,
age: String,
pets: List[Pet])
(its for migrations purposes, I want to move those tables to be a collection of mongodb, which the collection documents would be OwnerAndPets objects)
I have two issues:
when I use join with quill on Owner & Pet I get list of tuples [(Owner, Pet)]
and if I have few pets for an owner I will get:
[(Owner(1, "john", 30), Pet(3,1,"dog","max")),
(Owner(1, "john", 30), Pet(4,1,"cat","snow"))]
I need it as (Owner(1, "john", 30), [Pet(3,1,"dog","max"), Pet(4,1,"cat","snow")])
how can I make it like this?
when I use join with quill on Owner & Pet I will not get owners that dont have pets and its fine cause this is what it supposed to be, but in my script in this case I would want to create object like:
OwnerAndPets(Owner(2, "mark", 30), List[])
Would appreciate any help, thanks
this is my join query:
query[Owner].join(query[Pet]).on((o, p) => o.id == p.o_id)
Your question highlights one of the major differences between FRM (Functional Relational Mapping) systems like Quill and Slick as opposed to ORMs like Hibernate. The purpose of FRM systems is not to build a particular domain-specific object hierarchy e.g. OwnersAndPets, but rather, to be able translate a single database query into some set of objects that can reasonably be pulled out of that single query's result set - this is typically a tuple. This means it is up to you to join the tuples (Owner_N, Pet_1-N) object into a single OwnersAndPets object in memory. Typically this can be done via groupBy and map operators:
run(query[Owner].join(query[Pet]).on((o, p) => o.id == p.o_id))
.groupBy(_._1)
.map({case (owner,ownerPetList) =>
OwnerAndPets(
owner.id,owner.name,owner.age+"", // Not sure why you made 'age' a String in OwnerAndPets
ownerPetList.map(_._2))
})
That said, there are some database vendors (e.g. Postgres) that internally implement array types so in some cases you can do the join on the database-level but this is not the case for MySQL and many others.

Map Reduce with Relational Databases

I have 2 relational tables
Table A (Person 1, Title of Book Read)
Table B (Book Title, Author Name)
I'm creating a map-reduce job which counts the books by author which are read by every person in table 1.
This means that if there were 2 books by the same author and the person read both, then the map-reduce would yield:
(Person1, Author 1, 2);
My map function (at the Meta-level) is:
map {
emit(TableB.BookTitle, 1)
}
and my reduce function is:
reduce function (title,values)
{
while(values.hasNext())
{
if(title == tableA.bookRead)
sum+=values
}
output.collect(tableA.person1, tableB.author, sum)
}
I know there are some holes to be filled between the person reading the books but I'm not quite sure how to approach it? Also would I have to run this query for every person in the Table B?
We can break the given problem into two jobs:
1) In the first part we should create a map reduce job with two mapper. For First Mapper-A Table A is the input and for second Mapper-B table B is the input. And there will be only one reducer.
Mapper A emits "BooK Title" as Key and "Person Name#Table-A".
Mapper B emits "Book Title" as Key and "Author Name#Table-B"
Since in Map-Reduce records for one key goes to same reducer and in this job we just have one reducer so records will reach over there like
{Book Title,
Then you need to implement logic to extract out Person Name and Author Name. At the reducer end and Reducer will emit its output as:
Book Title %Author Name%PersonName
for eg.
while(values.hasNext())
{
String line = values.next().toString();
String[] det_array = line.split("#");
if(det_array[0].equals("person_book"))
{
person_name = det_array[1];
emit_value = emit_value + person_name + ",";
}
else if(det_array[0].equals("auth_book") && !author_seen)
{
author_name = det_array[1];
emit_value = emit_value + "%" + author_name + "%" + ",";
author_seen = true;
}
}
output.collect(new Text(key),new Text(emit_value));
Then Your Final Output File Will Look Like:
Book Title %Author_Name%Person Name
2) In the Second Map Reduce Job: Code Just One Mapper and Reducer. Input for Your Job is of format:
Book Title %Author_Name%Person Name1,PersonName2 etc..
For Your Mapper Output Key is Author_Name+Person and Value is 1.
As at this stage you have Combination of Author_Name and Person in Reducer you just need to count 1 and emit outout as Person Name, Author Name and Total Count.
Please let me know if this is not clear to you or you would like to see actual java code.
THanks !!