Skip to content
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

TINKERPOP-1483: valueMap should always return string keys #446

Merged
merged 7 commits into from
Nov 30, 2016
Merged

TINKERPOP-1483: valueMap should always return string keys #446

merged 7 commits into from
Nov 30, 2016

Conversation

JPMoresmau
Copy link
Contributor

Code changed, test added

@okram
Copy link
Contributor

okram commented Sep 30, 2016

Hm. This is a hard pill to swallow as its not backwards compatible. I was thinking you were going to go the route of making it Map<Object,Object> and thus, allow the enums as they are. If people have code that is map.get(id), your changes will break their code.

@JPMoresmau
Copy link
Contributor Author

JPMoresmau commented Sep 30, 2016

Well, I wasn't going to change the API on my very first PR :-). The first thing I did with a valueMap result was to iterate on the keys, which crashes... Of course if you want to change the API to Map<Object,Object> it's fine. But surely changing the api from Map<String,Object> to Map<Object,Object> is also going to break existing code? I suppose it will fail at compile time, and not at runtime, which is arguably better.

@dkuppitz
Copy link
Contributor

I've seen lots of code where people actually use id as a property name.

gremlin> g = TinkerGraph.open().traversal()
==>graphtraversalsource[tinkergraph[vertices:0 edges:0], standard]
gremlin> g.addV().property("id", UUID.randomUUID())
==>v[0]
gremlin> g.V().valueMap(true)
==>[id:0,id:[02f29cc6-7f04-477c-a884-d5196064109a],label:vertex]
gremlin> g.V().project("vertexId","applicationId").by(id).by("id").next()
==>vertexId=0
==>applicationId=02f29cc6-7f04-477c-a884-d5196064109a

Those people would be in big trouble if we would merge this PR:

VOTE: -1

@okram
Copy link
Contributor

okram commented Oct 29, 2016

Yea, this is a troublesome PR. VOTE -1.

@JPMoresmau
Copy link
Contributor Author

Fine, but if you don't want to change the implementation to match the interface, you'll have to change the interface of valueMap... Having keys of a type that is not allowed by the actual generic signature of the map is not great...

@dkuppitz
Copy link
Contributor

To support something like valueMap(T.label, "name")? This would be cool, but would go into another PR.

@JPMoresmau
Copy link
Contributor Author

What? I'm just saying that currently valueMap returns Map<String,Object>, so if you iterate on all the keys as String, you get a runtime crash because there are keys that are not strings. So if you don't want to put only String as keys, you need to change the Map to Map<Object,Object> , which will also break existing code.

@dkuppitz
Copy link
Contributor

Oh, now I see what you're saying. Yes, this would be the right way to go. The current PropertyMapStep implementation is pretty weird.

protected Map<String, E> map(...) {
    final Map<Object, Object> map = new HashMap<>();
    ...
    return (Map) map;
}

@robertdale
Copy link
Member

Can this PR be updated with Map<Object, Object> or should it be closed and open a new one?

@robertdale
Copy link
Member

This is interesting. I was unaware of some or didn't understand some implementation details. Taking a step back and looking at this again, I wonder if the original intent is more correct. Sorry @JPMoresmau
😃

We have to ask what is the purpose of Hidden? And what is the purpose of T.*.getAccessor()? Looks like Has step internally use T.*.getAccessor() for equality tests. Is this more of an internal method or should it be exposed?

Ultimately, the question is with what or how do we expect to access T tokens in a value map?

Given: map = g.V().valueMap(true).next()

Access by: map.get(T.id) or map.get(T.id.getAccessor())?

If the answer is T.id then the interface must be <Object,Object>

If the answer is T.id.getAccessor() then the interface must be <String,Object>

In either case, there is no conflict between system-level T tokens (e.g. T.id), as these are either Enum or Hidden, and user-level strings (e.g. id).

@dkuppitz
Copy link
Contributor

Access by: map.get(T.id) or map.get(T.id.getAccessor())?

By map.get(T.id). Providers may allow property names that match TinkerPop's token accessors, hence map.get(T.id) must not be the same as map.get("id") / map.get(T.id.getAccessor()) and a user-defined id property may not overwrite and may not be overwritten by the internal element id.

@robertdale
Copy link
Member

Thanks for the clarification @dkuppitz

./docker/build.sh -t -i -n passes

VOTE: +1

@okram
Copy link
Contributor

okram commented Nov 28, 2016

Yea, Map<Object,Object> is the thing. :| ... I really don't like valueMap(). For this reason and for the boolean argument overload ... fuggly.

VOTE +1.

@spmallette
Copy link
Contributor

This requires CHANGELOG and upgrade docs too (unless a committer wants to take responsibility for that).

@okram
Copy link
Contributor

okram commented Nov 28, 2016

@dkuppitz -- will you handle merge and thus, do the CHANGELOG and update the upgrade docs on merge?

@JPMoresmau
Copy link
Contributor Author

JPMoresmau commented Nov 28, 2016

I've updated the changelog and upgrade doc, not sure it's sufficient, please check! thanks!

@@ -46,6 +46,7 @@ TinkerPop 3.3.0 (Release Date: NOT OFFICIALLY RELEASED YET)
* Removed `tryRandomCommit()` from `AbstractGremlinTest`.
* Changed `gremlin-benchmark` system property for the report location to `benchmarkReportDir` for consistency.
* Added SysV and systemd init scripts.
* `valueMap` now returns a `Map<Object,E>` since keys could be `T.id` or `T.label`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please make it read GraphTraversal.valueMap().

@@ -73,6 +73,13 @@ bin/gremlin.sh -e gremlin.groovy

See: link:https://issues.apache.org/jira/browse/TINKERPOP-1283[TINKERPOP-1283]

ValueMap
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GraphTraversal valueMap() Signature Updated

@@ -483,7 +483,7 @@
* @param <E2> the value type of the returned properties
* @return the traversal with an appended {@link PropertyMapStep}.
*/
public default <E2> GraphTraversal<S, Map<String, E2>> valueMap(final String... propertyKeys) {
public default <E2> GraphTraversal<S, Map<Object, E2>> valueMap(final String... propertyKeys) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, this can still be Map<String,E2>. Its only when you have a boolean "includeTokens" that its Map<Object,Object>.

@okram
Copy link
Contributor

okram commented Nov 28, 2016

I just realized that valueMap() is Map<String,Object>, but valueMap(boolean) is Map<Object,Object>. We should maintain that level of explicitness as I suspect in the future valueMap(boolean) will change given that its sort of a wart right now.

@@ -42,5 +42,10 @@ public abstract class GroovyValueMapTest {
public Traversal<Vertex, Map<String, List<String>>> get_g_VX1X_outXcreatedX_valueMap(final Object v1Id) {
new ScriptTraversal<>(g, "gremlin-groovy", "g.V(v1Id).out('created').valueMap", "v1Id", v1Id)
}

@Override
public Traversal<Vertex, Map<Object, Object>> get_g_V_valueMapToken() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method is named wrong, it should be:

get_g_V_hasLabelXpersonX_filterXoutEXcreatedXX_valueMapXtrueX()

*/
@Test
@LoadGraphWith(MODERN)
public void valueMapHasObjectKeys() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method is named wrong, it should be like the traversal generator method name, minus the get_ prefix.

@okram
Copy link
Contributor

okram commented Nov 30, 2016

This is looking really good. We need one more VOTE.

@dkuppitz
Copy link
Contributor

Hold on, I've been busy with other stuff. I will look into this PR today.

@dkuppitz
Copy link
Contributor

Looked through the code, did some manual test - all good.

VOTE: +1

Gonna merge it in a few.

@asfgit asfgit merged commit 02345aa into apache:master Nov 30, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants