-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add stronger schema definition for map (structs) mutations #14
Conversation
- Fixing unsafe variables - Fixing non-used variables
Pull Request Test Coverage Report for Build 109
💛 - Coveralls |
Hey @WolfDan , thank you for your PR. I will have a closer look asap. About the issue that nodes don't have a type (or label in different graph databases). I use it in another project where I use exdgraph by adding a This is based on the Dgraph best practises: https://docs.dgraph.io/howto/#giving-nodes-a-type |
Hey @ospaarmann Yeah it is a possible solution, but is not optimal in a bigger project when you need to have more control about the indexes or how to get your data, there is a discussion already in the forum if you like to take a look (I also commented with a solution that I'm working on right now)
Greetings ^^/ |
Hey @WolfDan, so if I understand you correctly what you want is: If you have a struct and use it as the argument in
would result in a schema of
If that is correct: I like the idea. But your PR doesn't seem to achieve that. Most of the changes are made in the generation of tmp uids. This is a little hack that I use to return a map that already contains the
This would return:
Since no uid is set in the json, Dgraph will create a blank node and name it So a solution is to set a uid that doesn't exist, using
https://docs.dgraph.io/mutations/#setting-literal-values So a user inserts their stuff via a map. Each level of the map, I assign a key, value pair
When the mutation comes back, it returns SOMEUUIDHERE with the value of the uid inserted into dgraph. Now I can set the correct uid coming from Dgraph by replacing the tmp uid that I set in the original map with the uid coming back from Dgraph. In order to achieve what you want you would have to write a helper that replaces every key in the struct with a prefixed key. And maybe create a new function Also: This should not be the default behaviour since it changes the db structure without being explicit about it. When sending a query I would have to query for the prefixed predicates:
So this should either be triggered by an option for the This also needs to be documented and added to the Readme. But in general great idea! |
Hey @ospaarmann I must confess that I quite don't understand your point here ^^', the actual implementation takes the struct and add the prefixes to the mutation (the schema and queries to dgraph are done by hand in the actual library so no need to touch them from my point of view) The only field that isn't modified is ¿Why a Map? You might ask structs are build in top of maps in elixir, since elixir is not strongly typed you can bind any values to the struct, so there is no point at all to bring the uids to the given struct and is up to the user if want to bind that map to the struct (is as simple to use builtin function But as I said I quite don't get your point, do you want that the function binds the returning uid into the struct itself and instead of using |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@WolfDan So I had a look again and could reproduce it. So I take back my statement
But your PR doesn't seem to achieve that.
😉. I still would ask you for a couple of changes:
- Right now what happens is not transparent enough since you put the function to change the predicate name based on pattern matching (struct or no struct) inside a function that has nothing to do with that (
set_tmp_uids/2
). AND it is done inside theset_map/2
function, even though it matches for a struct. That is where my confusion came from. Please write a separate functionset_struct/2
and a separate helper that only adds the prefixes for any key other thanuid
. - You could create a little pipeline in
set_struct/2
and replacemap_with_tmp_uids
withprepared_map
or so. - Please write a test to check if nested different structs work as well. When struct
A
contains structB
, the predicates coming fromA
should have the prefixa
and the predicates coming fromB
should have the prefixb
.
@struct_insert_mutation %MutationTest.Person{
name: "Alice",
identifier: "alice_json",
dogs: [
%MutationTest.Dog{
name: "Bello"
}
]
}
- Please document what is going on in
@doc
and in the comments. - Users should be able to turn this feature on and off via configuration. Please add a
enforce_struct_schema
option to the config withdefault == false
. And document that as well
The reason for these change requests is that I want everything to be as transparent as possible. Setting a different predicate name in the db without telling the user or allowing them to turn that off would lead to a lot of confusion. And adding functionality to a function which has a different job will make it much harder for other developers to understand what is going on.
Besides that: Very good idea and can be very helpful! I will definitely use this feature in a project where I throw structs into Dgraph.
As requested @ospaarmann 0/ If I missed something feel free to tell me ^^ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey, thanks for the changes. Looks almost good. I still have two change requests:
- Please add the default value for the new config in /lib/exdgraph/utils.ex
- I would prefer to separate the setting of the tmp uids and the adding of the prefix in two separate functions that are named accordingly. This makes it easier for other developers to understand what each does.
Cheers,
Ole
Hey I added to utils.ex the default value, I didn't understand very well your second request, I've done the changes, but if are wrong just tell me ^^/ |
Hey, about the second request. Almost there! But still the
This way it is clear what is happening. I don't even think that you need a specific If you need two different functions for setting the temp uids the naming is not consistent ( |
Hey @WolfDan, one more thing. And I hope I don't go on your nerves by now! Please also make sure and test that a map inside a struct and a struct inside a map work as well. You could do that recursively by pattern matching for struct and map in That means this should work as well: struct_data = %MutationTest.Person{
name: "Alice",
identifier: "alice_json",
dogs: [
%MutationTest.Dog{
name: "Bello"
}
],
some_map: %{
some: "value",
map_owner: %MutationTest.Person{
name: "Bob"
}
}
} By the way: I now encountered a situation in a project where I would like to insert structs and your PR will be very helpful with that. |
Hey @ospaarmann Well I did the test with the map as you requestted (I'm glad you find this PR usefull) Now for the uids and the schema, I changed the function naming only, basically because you need to re map all the struct and check types again just to change the keys of the schema (and the map don't contains the sctruct info after beign added by the tmp ids), so is easier just to handle it from a single function Anyway just tell me what do you think about it |
That makes sense. Looks good now. I merged the PR. Thanks for the work! |
Hello o/
I've been working with dgraph for a while in a personal project, one of the problems of dgraph is that don't have an strong schema definition, the use of indexes without a "proper" schema is a big problem, here an example of what I mean:
Let's suppose we have a database with movies and their characters, so you define the name edge
name: string @index(term) .
And you add the
movie
with the nameThor
, but you also add thecharacter
with the nameThor
(which is valid in this context), the two have the same name definition, they could have different edges as well, but if you you do a term search for the nameThor
you'll get both themovie
and thecharacter
, I (and others as well) discussed it with the dev team, for the moment the best solution is creating indexes like this:movie.name: string @index(term) .
character.name: string @index(term) .
This allow you to be more explicit on exactly what you want to query and don't have mixed data
So this PR take the user defined structs, check if it is an struct and add the name of that struct (for example
MyApp.Models.Player
and turn it into a "schema" for dgrapg (like thisplayer.(the struct name definition)
, I also fixed a few problems in code that dializer warnedSummary of the PR
Greetings ^^/