Generate field from association - uml

I want to generate a field from association.
The problem that I have is that I'm using:
[for (p: Property | aClass.getAssociations().ownedEnd -> select(p: Property | p.type <> aClass)) separator('\n')]
[p.visibility/] [p.type.name/] [p.type.name.toLowerFirst()/];
[/for]
[for (p: Property | aClass.getAssociations().ownedEnd -> select(p: Property | p.type = p.getOtherEnd().type)) separator('\n')]
[p.visibility/] [p.type.name/] [p.type.name.toLowerFirst()/];
[/for]
So that checks for all associations and if the association type isn't the same ass class type it creates a field of that type.
And if the ends are the same type it creates a field of the same type as the class in which it is contained.
So basically if there is association A - B and A - A
For B create A, for A create B and A.
But there is a problem with second loop. It creates two fields instead of one, which is pretty logical. And here comes the question. How I can fix this? I'm not sure if I'm able to declare some kind of variable here and check %2. I can't just take one value, because there could be multiple associations.
Perhaps I did all the thing wrong? Maybe there is a way to iterate over the ends that would save me all those checks and two for loops?

[for (a: Association | aClass.getAssociations())]
[if a.ownedEnd.type = a.ownedEnd.getOtherEnd().type]
[a.visibility/] [a.endType.name/] [a.endType.name.toLowerFirst()/];
[else]
[for (p: Property | a.ownedEnd -> select (type <> aClass))]
[p.visibility/] [p.type.name/] [p.type.name.toLowerFirst()/];
[/for]
[/if]
[/for]
That seems to do the trick

Related

How can I generate the list of `EntityField`s for a `PersistEntity`?

I was trying to implement some form of repsertBy: repsert where the key is a provided Unique, in the line of getBy, upsertBy etc.
My approach: implement it on top of upsertBy. Now upsertBy takes a unique constraint, a record, and a list of changes to apply in case of a unique collision. To implement repsertBy I'd like that list of changes to be “assign all fields to the new value”.
repsertBy :: (MonadIO m, PersistRecordBackend record backend)
=> Unique record -> record
-> ReaderT backend m (Entity record)
repsertBy unique record = upsertBy unique record [ entifyField =. value | … ]
And there I'm stuck.
I can generate the list of values by calling toPersistValue on the record's toPersistFields. But where can I get the EntityFields from?
I'd have expected them to be available somewhere from the entity definition at èntityDef, but haven't found any as of now. I've tried comparing with actual backends' implementations of replace and upsert, but only found SQL-level string banging.
I'm currently spelling out the fields by hand, but at some point I'm going to add one in the entity and forget to update it in the repsertBy. Is there any way to access the EntityFields?

default values for PersistList on SQLite - Yesod

I would like to add a PersistList value into a user entity with a default value. My model file looks like this. And Models.hs file:
User
ident Text
password Text Maybe
UniqueUser ident
perms [Privileges] default=[PrvDemoOne]
deriving Typeable
data Privileges =
PrvDemoOne -- ^ what can be demo one...
| PrvDemoTwo -- ^ what can be demo two...
deriving (Show,Read,Eq)
derivePersistField "Privileges"
the code compiles but when a new user is added into the table save an empty array instead of an array with the default value.
1|google-uid:223344555661778819911||[]
The question is how I could save the column with the default value?
Have you read this? The value of the default field doesn't really have anything to do with the Haskell side per-se, it's being passed to set the "default value" description your DBMS. In this case [PrvDemoOne] is being passed directly to SQLite, which will interpret it as gibberish (because it's not a valid SQL expression) so this is either ignored or (what seems to be the case here) treated as if you hadn't set a default at all.
If you want a "Haskell side" default value you should just create a function for that, i.e. something like
defaultUser :: Text -> Maybe Text -> User
defaultUser i maybePw = User { ident = i, password = maybePw, perms = [PrvDemoOne] }
If you want a SQL side default you need to write the corresponding SQL expression for the value you're trying to represent.
On a non-Haskell related note: the 'normal' way to represent lists (or sets in this case, rather!) in SQL is via relations, so you'd normally have a many-to-many relationship mapping users to their privileges instead of a list field.

Storing type fields in a list

Hello i am faced with the following problem. I have a data type with multiple fields.I need to enumerate them and store them in a collection for further mapping.
data Worker=Worker{
age::Int,
name::String,
title::Title,
income::Int
}
data Title=Manager | Dev | Tester deriving (Show)
instance Show Worker where
show w=let !names=["age","name", "title","income"]
!props= [age,name,title,income] in -- Do i need to define another new type to be able to flat them down to a list?
"{"++intercalate "," (zipWith (\x y-> x++":"++ y w) names props)++"}"
Where can i store all all properties (methods)to be able to further use them as a parameter in a higher order function on a given variable of type Worker in our case.
You can get sort of close to the thing you're looking for, but it's not going to be pretty.
We can use RecordWildCards to bring all of the accessor names into scope as though they were ordinary variables, but that still introduces a new problem.
-- Not runnable Haskell code
foo Worker {..} = let names = ["age", "name", "title", "income"]
props = [age, name, title, income]
in ...
We're pattern matching on Worker {..}, which introduces a bunch of accessor names into the local scope. However, props is trying to be a heterogeneous list, which Haskell does not allow. It contains two integers, a string, and a title, whereas Haskell lists are only supposed to contain one type.
Since you're trying to show each field, you're going to have to apply show to each element by hand. Like I said, this is going to be a bit ugly.
foo Worker {..} = let names = ["age", "name", "title", "income"]
props = [show age, show name, show title, show income]
in ...
It may look like we can do map show [age, name, title, income], but we can't. That list still wouldn't be valid, and we're applying three different show functions here (they just happen to share a name), so we can't meaningfully map the same show over each element.
However, as the comments say, your best bet is to familiarize yourself with a proper JSON library, and Aeson is easily the best choice in Haskell for that sort of thing.

How do I store Either (Key a) (Key b)?

I have the following model:
User
...
Group
...
Sharing
objectId (Either UserId GroupId)
In Sharing entity I want to store either UserId or GroupId and differentiate between them. Simply using Either doesn't work:
Not in scope: type constructor or class `UserId'
Not in scope: type constructor or class `GroupId'
Adding a new sum-type also doesn't work:
data SharingIdType = SharingUserId UserId | SharingGroupId GroupId
Not in scope: type constructor or class `SharingIdType'
Moving SharingIdType into another module isn't possible, because it uses UserId and GroupId types. The only way I see is to create an entity for each sharing type, like UserSharing/GroupSharing.
Other than that, how to approach this problem?
After searching for some time and thinking about it I concluded there are two possible solutions:
1.
If number of SharingIdTypes is static or rarely changes (means, it is OK to recompile the source to change it or alter the DB schema), the proper way to handle the problem is to have to entities for each sharing type:
User
...
Group
...
UserSharing
userId UserId
GroupSharing
groupId GroupId
Here the "sumness" of the problem is moved to DB queries. Whenever I need to find out with what something shared, I make two selectLists and query two tables instead of one.
2.
If number of SharingIdTypes needs to be altered dynamically, the SharingType entity is needed:
User
...
Group
...
SharingType
description String
Sharing
objectId SharingTypeId
This table is filled up with values corresponding to SharingIdTypes constructors:
do
insert $ SharingType "user"
insert $ SharingType "group"
Now whenever we share something, we refer SharingTypeId.

OCL verify value in parameter

Class Game
Method: addPlayer(param Player)
I would like to create an invariant for my method addPlayer so it verifies that parameter Player exists.
Example:
context Game::addPlayer(pl:Player)
inv pl->exists( p : Player | p.playerID = pl.playerID )
Not sure if syntax is valid
I´m not going to get into the discussion if the constraint itself makes sense. Just some comments to help you understand OCL in this case.
Invariants are created on classes. They don´t make sense in an operation context.
Probably what you want is an Operation precondition.
"exists" is an operator (existential quantifier) to work on a collection. The point is that you are implicitly creating a collection with the parameter p1 (by doing pl->exists(...), so your constraint will always be true.
A probably better constraint would be the following
Using the allInstances() operation
context Game::addPlayer(pl:Player)
pre : Player.allInstances()->exists(p : Player | p.playerID = pl.playerID )

Resources