Skip to content

Commit d8ee0fa

Browse files
authored
Merge pull request #901 from JuliaRobotics/master
release v0.18.6-rc1
2 parents 3a89315 + 9afbff0 commit d8ee0fa

14 files changed

+130
-196
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "DistributedFactorGraphs"
22
uuid = "b5cc3c7e-6572-11e9-2517-99fb8daf2f04"
3-
version = "0.18.5"
3+
version = "0.18.6"
44

55
[deps]
66
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"

src/DataBlobs/entities/AbstractDataEntries.jl

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,50 @@ struct MongodbDataEntry <: AbstractDataEntry
4848
#flags::Bool ready, valid, locked, permissions
4949
#MIMEType::String
5050
end
51+
52+
53+
##==============================================================================
54+
## FileDataEntryBlob Types
55+
##==============================================================================
56+
export FileDataEntry
57+
"""
58+
$(TYPEDEF)
59+
Data Entry in a file.
60+
"""
61+
struct FileDataEntry <: AbstractDataEntry
62+
label::Symbol
63+
id::UUID
64+
folder::String
65+
hash::String #using bytes2hex or perhaps Vector{Uint8}?
66+
createdTimestamp::ZonedDateTime
67+
68+
function FileDataEntry(label, id, folder, hash, timestamp)
69+
if !isdir(folder)
70+
@info "Folder '$folder' doesn't exist - creating."
71+
# create new folder
72+
mkpath(folder)
73+
end
74+
return new(label, id, folder, hash, timestamp)
75+
end
76+
end
77+
78+
79+
##==============================================================================
80+
## InMemoryDataEntry Types
81+
##==============================================================================
82+
export InMemoryDataEntry
83+
"""
84+
$(TYPEDEF)
85+
Store data temporary in memory.
86+
NOTE: Neither Entry nor Blob will be persisted.
87+
"""
88+
struct InMemoryDataEntry{T} <: AbstractDataEntry
89+
label::Symbol
90+
id::UUID
91+
#hash::String #Is this needed?
92+
createdTimestamp::ZonedDateTime
93+
data::T
94+
end
95+
96+
# getHash(::InMemoryDataEntry) = UInt8[]
97+
assertHash(de::InMemoryDataEntry, db; hashfunction = sha256) = true

src/DataBlobs/services/AbstractDataEntries.jl

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,22 @@ buildSourceString(dfg::AbstractDFG, label::Symbol) =
2929
Get data entry
3030
"""
3131
function getDataEntry(var::AbstractDFGVariable, key::Symbol)
32-
!hasDataEntry(var, key) && error("Data entry $(key) does not exist in variable $(getLabel(var))")
32+
!hasDataEntry(var, key) && error("No dataEntry label $(key) found in variable $(getLabel(var))")
3333
return var.dataDict[key]
3434
end
3535

36-
function getDataEntry(dfg::AbstractDFG, label::Symbol, key::Symbol)
37-
return getDataEntry(getVariable(dfg, label), key)
36+
function getDataEntry(var::AbstractDFGVariable, blobId::UUID)
37+
for (k,v) in var.dataDict
38+
if v.id == blobId
39+
return v
40+
end
41+
end
42+
error("No dataEntry with blobId $(blobId) found in variable $(getLabel(var))")
3843
end
3944

45+
getDataEntry(dfg::AbstractDFG, label::Symbol, key::Union{Symbol,UUID}) = getDataEntry(getVariable(dfg, label), key)
46+
47+
4048
"""
4149
$(SIGNATURES)
4250
Add Data Entry to a DFG variable

src/DataBlobs/services/BlobStores.jl

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,13 @@ end
6363
## Store and Entry Data CRUD
6464
##==============================================================================
6565

66-
function getData(dfg::AbstractDFG, blobstore::AbstractBlobStore, label::Symbol, key::Symbol; hashfunction = sha256)
66+
function getData(
67+
dfg::AbstractDFG,
68+
blobstore::AbstractBlobStore,
69+
label::Symbol,
70+
key::Union{Symbol,UUID};
71+
hashfunction = sha256
72+
)
6773
de = getDataEntry(dfg, label, key)
6874
db = getDataBlob(blobstore, de)
6975
assertHash(de, db, hashfunction=hashfunction)

src/DataBlobs/services/DataEntryBlob.jl

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,13 @@ end
111111
## DFG Data CRUD
112112
##==============================================================================
113113

114-
function getData(dfg::AbstractDFG, label::Symbol, key::Symbol; hashfunction = sha256)
115-
de = getDataEntry(dfg, label, key)
114+
function getData(
115+
dfg::AbstractDFG,
116+
vlabel::Symbol,
117+
key::Union{Symbol,UUID};
118+
hashfunction = sha256
119+
)
120+
de = getDataEntry(dfg, vlabel, key)
116121
db = getDataBlob(dfg, de)
117122

118123
assertHash(de, db, hashfunction=hashfunction)

src/DataBlobs/services/FileDataEntryBlob.jl

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,4 @@
1-
##==============================================================================
2-
## FileDataEntryBlob Types
3-
##==============================================================================
4-
export FileDataEntry
5-
"""
6-
$(TYPEDEF)
7-
Data Entry in a file.
8-
"""
9-
struct FileDataEntry <: AbstractDataEntry
10-
label::Symbol
11-
id::UUID
12-
folder::String
13-
hash::String #using bytes2hex or perhaps Vector{Uint8}?
14-
createdTimestamp::ZonedDateTime
151

16-
function FileDataEntry(label, id, folder, hash, timestamp)
17-
if !isdir(folder)
18-
@info "Folder '$folder' doesn't exist - creating."
19-
# create new folder
20-
mkpath(folder)
21-
end
22-
return new(label, id, folder, hash, timestamp)
23-
end
24-
end
252

263
# @generated function ==(x::FileDataEntry, y::FileDataEntry)
274
# mapreduce(n -> :(x.$n == y.$n), (a,b)->:($a && $b), fieldnames(x))

src/DataBlobs/services/InMemoryDataEntryBlob.jl

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,3 @@
1-
##==============================================================================
2-
## InMemoryDataEntry Types
3-
##==============================================================================
4-
export InMemoryDataEntry
5-
"""
6-
$(TYPEDEF)
7-
Store data temporary in memory.
8-
NOTE: Neither Entry nor Blob will be persisted.
9-
"""
10-
struct InMemoryDataEntry{T} <: AbstractDataEntry
11-
label::Symbol
12-
id::UUID
13-
#hash::String #Is this needed?
14-
createdTimestamp::ZonedDateTime
15-
data::T
16-
end
17-
18-
# getHash(::InMemoryDataEntry) = UInt8[]
19-
assertHash(de::InMemoryDataEntry, db; hashfunction = sha256) = true
201

212

223
##==============================================================================

src/Neo4jDFG/entities/Neo4jDFG.jl

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,10 @@ mutable struct Neo4jDFG{T <: AbstractParams} <: AbstractDFG{T}
3333
!isValidLabel(robotId) && error("'$robotId' is not a valid Robot ID")
3434
!isValidLabel(sessionId) && error("'$sessionId' is not a valid Session ID")
3535

36-
# neo4jConnection = Neo4j.Connection(host, port=port, user=dbUser, password=dbPassword);
37-
# graph = Neo4j.getgraph(neo4jConnection)
38-
# neo4jInstance = Neo4jInstance(neo4jConnection, graph)
39-
4036
dfg = new{T}(neo4jInstance, userId, robotId, sessionId, description, addHistory, solverParams, blobStores)
4137
# Create the session if it doesn't already exist
4238
if createSessionNodes
4339
createDfgSessionIfNotExist(dfg)
44-
setUserData!(dfg, userData)
45-
setRobotData!(dfg, robotData)
46-
setSessionData!(dfg, sessionData)
47-
setDescription!(dfg, description)
4840
end
4941

5042
return dfg

src/Neo4jDFG/services/CGStructure.jl

Lines changed: 19 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ end
66

77
# Fastest way I can think to convert the data into a dict
88
#TODO: Probably should be made more efficient...definitely should be made more efficient
9-
# return ::Dict{String, Any}
109
function _convertNodeToDict(abstractNode::N) where N <: AbstractCGNode
1110
cp = deepcopy(abstractNode)
1211
data = length(cp.data) != 0 ? JSON2.write(cp.data) : "{}"
@@ -16,8 +15,6 @@ function _convertNodeToDict(abstractNode::N) where N <: AbstractCGNode
1615
return ser
1716
end
1817

19-
#TODO: Refactor, #HACK :D (but it works!)
20-
# return ::Session
2118
function _convertDictToSession(dict::Dict{String, Any})
2219
data = JSON2.read(String(base64decode(dict["data"])), Dict{Symbol, String})
2320
session = Session(
@@ -31,8 +28,7 @@ function _convertDictToSession(dict::Dict{String, Any})
3128
dict["lastUpdatedTimestamp"])
3229
return session
3330
end
34-
#TODO: Refactor, #HACK :D (but it works!)
35-
# returns ::Robot
31+
3632
function _convertDictToRobot(dict::Dict{String, Any})
3733
data = JSON2.read(String(base64decode(dict["data"])), Dict{Symbol, String})
3834
robot = Robot(
@@ -45,8 +41,7 @@ function _convertDictToRobot(dict::Dict{String, Any})
4541
dict["lastUpdatedTimestamp"])
4642
return robot
4743
end
48-
#TODO: Refactor, #HACK :D (but it works!)
49-
# returns ::User
44+
5045
function _convertDictToUser(dict::Dict{String, Any})
5146
data = JSON2.read(String(base64decode(dict["data"])), Dict{Symbol, String})
5247
user = User(
@@ -59,81 +54,33 @@ function _convertDictToUser(dict::Dict{String, Any})
5954
return user
6055
end
6156

62-
# returns ::User
63-
function createUser(dfg::Neo4jDFG, user::User)
64-
Symbol(dfg.userId) != user.id && error("DFG user ID must match user's ID")
65-
!isValidLabel(user) && error("Node cannot have an ID '$(user.id)'.")
66-
67-
props = _convertNodeToDict(user)
68-
# TODO: Switch to _queryNeo4j
69-
retNode = _createNode(dfg.neo4jInstance, ["USER", String(user.id)], props, nothing)
70-
return user
71-
end
72-
73-
# returns ::Robot
74-
function createRobot(dfg::Neo4jDFG, robot::Robot)
75-
Symbol(dfg.robotId) != robot.id && error("DFG robot ID must match robot's ID")
76-
Symbol(dfg.userId) != robot.userId && error("DFG user ID must match robot's user ID")
77-
!isValidLabel(robot) && error("Node cannot have an ID '$(robot.id)'.")
78-
79-
# Find the parent
80-
parents = _getNeoNodesFromCyphonQuery(dfg.neo4jInstance, "(node:USER:`$(dfg.userId)`)")
81-
length(parents) == 0 && error("Cannot find user '$(dfg.userId)'")
82-
length(parents) > 1 && error("Found multiple users '$(dfg.userId)'")
83-
84-
# Already exists?
85-
length(_getNeoNodesFromCyphonQuery(dfg.neo4jInstance, "(node:ROBOT:`$(dfg.userId)`:`$(robot.id)`)")) != 0 &&
86-
error("Robot '$(robot.id)' already exists for user '$(robot.userId)'")
87-
88-
props = _convertNodeToDict(robot)
89-
# TODO: Switch to _queryNeo4j
90-
retNode = _createNode(dfg.neo4jInstance, ["ROBOT", String(robot.userId), String(robot.id)], props, parents[1], :ROBOT)
91-
return robot
92-
end
93-
94-
# returns ::Session
95-
function createSession(dfg::Neo4jDFG, session::Session)
96-
Symbol(dfg.robotId) != session.robotId && error("DFG robot ID must match session's robot ID")
97-
Symbol(dfg.userId) != session.userId && error("DFG user ID must match session's->robot's->user ID")
98-
!isValidLabel(session) && error("Node cannot have an ID '$(session.id)'.")
99-
100-
# Find the parent
101-
parents = _getNeoNodesFromCyphonQuery(dfg.neo4jInstance, "(node:ROBOT:`$(dfg.robotId)`:`$(dfg.userId)`)")
102-
length(parents) == 0 && error("Cannot find robot '$(dfg.robotId)' for user '$(dfg.userId)'")
103-
length(parents) > 1 && error("Found multiple robots '$(dfg.robotId)' for user '$(dfg.userId)'")
104-
105-
# Already exists?
106-
length(_getNeoNodesFromCyphonQuery(dfg.neo4jInstance, "(node:SESSION:`$(session.userId)`:`$(session.robotId)`:`$(session.id)`)")) != 0 &&
107-
error("Session '$(session.id)' already exists for robot '$(session.robotId)' and user '$(session.userId)'")
108-
109-
props = _convertNodeToDict(session)
110-
# TODO: Switch to _queryNeo4j
111-
retNode = _createNode(dfg.neo4jInstance, ["SESSION", String(session.userId), String(session.robotId), String(session.id)], props, parents[1], :SESSION)
112-
return session
113-
end
114-
11557
"""
11658
$(SIGNATURES)
117-
Shortcut method to create the user, robot, and session if it doesn't already exist.
118-
119-
Notes
120-
- return `::Session`
59+
Efficient shortcut method to create the user, robot, and session if it doesn't already exist.
12160
"""
12261
function createDfgSessionIfNotExist(dfg::Neo4jDFG)
12362
strip(dfg.userId) == "" && error("User ID is not populated in DFG.")
12463
strip(dfg.robotId) == "" && error("Robot ID is not populated in DFG.")
12564
strip(dfg.sessionId) == "" && error("Session ID is not populated in DFG.")
65+
!isValidLabel(dfg.userId) && error("Node cannot have an ID '$(dfg.userId)'.")
66+
!isValidLabel(dfg.robotId) && error("Node cannot have an ID '$(dfg.robotId)'.")
67+
!isValidLabel(dfg.sessionId) && error("Node cannot have an ID '$(dfg.sessionId)'.")
68+
12669
user = User(Symbol(dfg.userId), dfg.userId, "Description for $(dfg.userId)", Dict{Symbol, String}())
12770
robot = Robot(Symbol(dfg.robotId), Symbol(dfg.userId), dfg.robotId, "Description for $(dfg.userId):$(dfg.robotId)", Dict{Symbol, String}())
12871
session = Session(Symbol(dfg.sessionId), Symbol(dfg.robotId), Symbol(dfg.userId), dfg.sessionId, dfg.description, Dict{Symbol, String}())
12972

130-
_getNodeCount(dfg.neo4jInstance, [dfg.userId, "USER"]) == 0 && createUser(dfg, user)
131-
_getNodeCount(dfg.neo4jInstance, [dfg.userId, dfg.robotId, "ROBOT"]) == 0 && createRobot(dfg, robot)
132-
if _getNodeCount(dfg.neo4jInstance, [dfg.userId, dfg.robotId, dfg.sessionId, "SESSION"]) == 0
133-
return createSession(dfg, session)
134-
else
135-
return getSession(dfg)
136-
end
73+
# NOTE that this doesn't get updated then, you need to use the set* (e.g. setSessionData) functions yourself.
74+
query = """
75+
MERGE (u:USER:`$(String(user.id))`) ON CREATE SET $(join(["u.$k = '$(v)'" for (k,v) in _convertNodeToDict(user)], ", "))\r\n
76+
MERGE (r:ROBOT:`$(String(user.id))`:`$(String(robot.id))`) ON CREATE SET $(join(["r.$k = '$(v)'" for (k,v) in _convertNodeToDict(robot)], ", "))\r\n
77+
MERGE (s:SESSION:`$(String(user.id))`:`$(String(robot.id))`:`$(String(session.id))`) ON CREATE SET $(join(["s.$k = '$(v)'" for (k,v) in _convertNodeToDict(session)], ", "))
78+
MERGE (u)-[:ROBOT]->(r)
79+
MERGE (r)-[:SESSION]->(s)
80+
"""
81+
82+
_queryNeo4j(dfg.neo4jInstance, query)
83+
return nothing
13784
end
13885

13986
"""
@@ -320,7 +267,7 @@ Notes
320267
- Returns `::Neo4jDFG `
321268
"""
322269
function copySession!(sourceDFG::Neo4jDFG, destDFG::Union{Nothing, <:Neo4jDFG})
323-
if destDFG == nothing
270+
if destDFG === nothing
324271
destDFG = _getDuplicatedEmptyDFG(sourceDFG)
325272
end
326273
_copyIntoGraph!(sourceDFG, destDFG, union(listVariables(sourceDFG), listFactors(sourceDFG)), true)

src/services/CustomPrinting.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -191,9 +191,9 @@ function Base.show(io::IO, dfg::AbstractDFG)
191191
println(io, " Description: ", dfg.description)
192192
println(io, " Nr variables: ", length(ls(dfg)))
193193
println(io, " Nr factors: ",length(lsf(dfg)))
194-
println(io, " User Data: ", keys(dfg.userData))
195-
println(io, " Robot Data: ", keys(dfg.robotData))
196-
println(io, " Session Data: ", keys(dfg.sessionData))
194+
println(io, " User Data: ", keys(getUserData(dfg)))
195+
println(io, " Robot Data: ", keys(getRobotData(dfg)))
196+
println(io, " Session Data: ", keys(getSessionData(dfg)))
197197
end
198198

199199
Base.show(io::IO, ::MIME"text/plain", dfg::AbstractDFG) = show(io, dfg)

0 commit comments

Comments
 (0)