Skip to content

Commit e88ef99

Browse files
authored
Add an Ordered Dict Row Table Blob Store (#1075)
* Add a Ordered Dict Row Table Blob Store * add RowBlobStore constructors for tables * FolderStore label as kwarg
1 parent 3591188 commit e88ef99

File tree

6 files changed

+182
-9
lines changed

6 files changed

+182
-9
lines changed

Project.toml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ SHA = "ea8e919c-243c-51af-8825-aaa63cd721ce"
2525
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
2626
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
2727
StructTypes = "856f2bd8-1eba-4b0a-8007-ebc267875bd4"
28+
Tables = "bd369af6-aec1-5ad0-b16a-f7cc5008161c"
2829
Tar = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e"
2930
TensorCast = "02d47bb6-7ce6-556a-be16-bb1710789e2b"
3031
TimeZones = "f269a46b-ccf7-5d73-abea-4c690281aa53"
@@ -52,8 +53,8 @@ Graphs = "1.4"
5253
InteractiveUtils = "1.10"
5354
JSON3 = "1"
5455
LinearAlgebra = "1.10"
55-
ManifoldsBase = "0.14, 0.15"
5656
Manifolds = "0.9"
57+
ManifoldsBase = "0.14, 0.15"
5758
OrderedCollections = "1.4"
5859
Pkg = "1.4, 1.5"
5960
ProgressMeter = "1"
@@ -64,9 +65,10 @@ SparseArrays = "1.10"
6465
StaticArrays = "1"
6566
Statistics = "1.10"
6667
StructTypes = "1"
68+
Tables = "v1.11.1"
6769
Tar = "1.9"
68-
Test = "1.10"
6970
TensorCast = "0.3.3, 0.4"
71+
Test = "1.10"
7072
TimeZones = "1.3.1"
7173
UUIDs = "1.10"
7274
julia = "1.10"

src/DataBlobs/services/BlobEntry.jl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,16 @@ function getBlobEntryFirst(dfg::AbstractDFG, label::Symbol, key::Regex)
130130
return getBlobEntryFirst(getVariable(dfg, label), key)
131131
end
132132

133+
# TODO Consider autogenerating all methods of the form:
134+
# verbNoun(dfg::DFGVariable, label::Symbol, args...; kwargs...) = verbNoun(getVariable(dfg, label), args...; kwargs...)
135+
# with something like:
136+
# getvariablemethod = [
137+
# :getBlobEntryFirst,
138+
# ]
139+
# for met in methodstooverload
140+
# @eval DistributedFactorGraphs $met(dfg::AbstractDFG, label::Symbol, args...; kwargs...) = $met(getVariable(dfg, label), args...; kwargs...)
141+
# end
142+
133143
function getBlobEntry(dfg::AbstractDFG, label::Symbol, key::Union{Symbol, UUID})
134144
return getBlobEntry(getVariable(dfg, label), key)
135145
end

src/DataBlobs/services/BlobStores.jl

Lines changed: 128 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -181,13 +181,13 @@ struct FolderStore{T} <: AbstractBlobStore{T}
181181
folder::String
182182
end
183183

184-
function FolderStore(foldername::String; createfolder = true)
184+
function FolderStore(foldername::String; label = :default_folder_store, createfolder = true)
185185
if createfolder && !isdir(foldername)
186186
@info "Folder '$foldername' doesn't exist - creating."
187187
# create new folder
188188
mkpath(foldername)
189189
end
190-
return FolderStore{Vector{UInt8}}(:default_folder_store, foldername)
190+
return FolderStore{Vector{UInt8}}(label, foldername)
191191
end
192192

193193
blobfilename(store::FolderStore, blobId::UUID) = joinpath(store.folder, string(blobId))
@@ -254,7 +254,7 @@ struct InMemoryBlobStore{T} <: AbstractBlobStore{T}
254254
end
255255

256256
function InMemoryBlobStore{T}(storeKey::Symbol) where {T}
257-
return InMemoryBlobStore{Vector{UInt8}}(storeKey, Dict{UUID, T}())
257+
return InMemoryBlobStore{T}(storeKey, Dict{UUID, T}())
258258
end
259259
function InMemoryBlobStore(storeKey::Symbol = :default_inmemory_store)
260260
return InMemoryBlobStore{Vector{UInt8}}(storeKey)
@@ -338,3 +338,128 @@ end
338338

339339
deleteBlob!(store::LinkStore, ::BlobEntry) = deleteBlob!(store)
340340
deleteBlob!(store::LinkStore, ::UUID) = deleteBlob!(store)
341+
342+
##==============================================================================
343+
## RowBlobStore Ordered Dict Row Table Blob Store
344+
##==============================================================================
345+
346+
# RowBlob
347+
# T must be compatable with the AbstactRow iterator
348+
# struct and named tuple as examples
349+
struct RowBlob{T} <: Tables.AbstractRow
350+
id::UUID
351+
blob::T
352+
end
353+
354+
function RowBlob(::Type{T}, nt::NamedTuple) where {T}
355+
id = nt.id
356+
blob = T(nt[keys(nt)[2:end]])
357+
return RowBlob(id, blob)
358+
end
359+
360+
function Tables.getcolumn(row::RowBlob, i::Int)
361+
return i == 1 ? getfield(row, :id) : Tables.getcolumn(getfield(row, :blob), i - 1)
362+
end
363+
function Tables.getcolumn(row::RowBlob, nm::Symbol)
364+
return nm == :id ? getfield(row, :id) : Tables.getcolumn(getfield(row, :blob), nm)
365+
end
366+
function Tables.columnnames(row::RowBlob)
367+
return (:id, Tables.columnnames(getfield(row, :blob))...)
368+
end
369+
370+
## RowBlobStore
371+
372+
struct RowBlobStore{T} <: AbstractBlobStore{T}
373+
key::Symbol
374+
blobs::OrderedDict{UUID, RowBlob{T}}
375+
end
376+
377+
function RowBlobStore{T}(storeKey::Symbol) where {T}
378+
return RowBlobStore{T}(storeKey, OrderedDict{UUID, RowBlob{T}}())
379+
end
380+
function RowBlobStore(storeKey::Symbol, T::DataType)
381+
return RowBlobStore{T}(storeKey)
382+
end
383+
384+
function RowBlobStore(storeKey::Symbol, T::DataType, table)
385+
store = RowBlobStore(storeKey, T)
386+
for nt in Tables.namedtupleiterator(table)
387+
row = DFG.RowBlob(T, nt)
388+
store.blobs[row.id] = row
389+
end
390+
return store
391+
end
392+
393+
# Tables interface
394+
Tables.istable(::Type{RowBlobStore{T}}) where {T} = true
395+
Tables.rowaccess(::Type{RowBlobStore{T}}) where {T} = true
396+
Tables.rows(store::RowBlobStore) = values(store.blobs)
397+
#TODO
398+
# Tables.materializer(::Type{RowBlobStore{T}}) where T = Tables.rowtable
399+
400+
##
401+
function getBlob(store::RowBlobStore, blobId::UUID)
402+
return getfield(store.blobs[blobId], :blob)
403+
end
404+
405+
function addBlob!(store::RowBlobStore{T}, blobId::UUID, blob::T) where {T}
406+
if haskey(store.blobs, blobId)
407+
error("Key '$blobId' blob already exists.")
408+
end
409+
store.blobs[blobId] = RowBlob(blobId, blob)
410+
return blobId
411+
end
412+
413+
function updateBlob!(store::RowBlobStore{T}, blobId::UUID, blob::T) where {T}
414+
if haskey(store.blobs, blobId)
415+
@warn "Key '$blobId' doesn't exist."
416+
end
417+
return store.blobs[blobId] = RowBlob(blobId, blob)
418+
end
419+
420+
function deleteBlob!(store::RowBlobStore, blobId::UUID)
421+
return getfield(pop!(store.blobs, blobId), :blob)
422+
end
423+
424+
hasBlob(store::RowBlobStore, blobId::UUID) = haskey(store.blobs, blobId)
425+
426+
listBlobs(store::RowBlobStore) = collect(keys(store.blobs))
427+
428+
# TODO also see about wrapping a table directly
429+
##
430+
if false
431+
rb = RowBlob(uuid4(), (a = [1, 2], b = [3, 4]))
432+
433+
Tables.columnnames(rb)
434+
435+
tstore = RowBlobStore(:namedtuple, @NamedTuple{a::Vector{Int}, b::Vector{Int}})
436+
437+
addBlob!(tstore, uuid4(), (a = [1, 2], b = [3, 4]))
438+
addBlob!(tstore, uuid4(), (a = [5, 6], b = [7, 8]))
439+
addBlob!(tstore, uuid4(), (a = [9, 10], b = [11, 12]))
440+
441+
rowtbl = Tables.rowtable(tstore)
442+
coltbl = Tables.columntable(rowtbl)
443+
444+
Tables.rows(tstore)
445+
tbl = Tables.rowtable(tstore)
446+
447+
first(Tables.namedtupleiterator(tstore))
448+
449+
# Tables.materializer(tstore)
450+
451+
##
452+
struct Foo
453+
a::Float64
454+
b::Float64
455+
end
456+
457+
sstore = RowBlobStore(:struct_Foo, Foo)
458+
459+
addBlob!(sstore, uuid4(), Foo(1, 2))
460+
addBlob!(sstore, uuid4(), Foo(3, 4))
461+
addBlob!(sstore, uuid4(), Foo(5, 6))
462+
463+
Tables.rowtable(sstore)
464+
end
465+
##

src/DataBlobs/services/HelpersDataWrapEntryBlob.jl

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ function getData(
122122
return de => db
123123
end
124124

125+
#FIXME Should `addData!`` not return entry=>blob pair?
125126
function addData!(
126127
dfg::AbstractDFG,
127128
label::Symbol,
@@ -171,7 +172,6 @@ function addData!(
171172
)
172173
end
173174

174-
#FIXME id used wrong
175175
function addData!(
176176
dfg::AbstractDFG,
177177
blobstore::AbstractBlobStore,
@@ -182,14 +182,15 @@ function addData!(
182182
description = "",
183183
metadata = "",
184184
mimeType::String = "application/octet-stream",
185-
id::Union{UUID, Nothing} = nothing, #only assign if blobstore issued you an id
185+
id::Union{UUID, Nothing} = nothing,
186+
blobId::Union{UUID, Nothing} = nothing, #only assign if blobstore issued you an id
186187
originId::UUID = uuid4(),
187188
hashfunction = sha256,
188189
)
189190
#
190-
@warn "ID's and origin IDs should be reconciled here in DFG.addData!." maxlog = 50
191191
entry = BlobEntry(;
192192
id,
193+
blobId,
193194
originId,
194195
label = bLbl,
195196
blobstore = blobstore.key,
@@ -204,6 +205,40 @@ function addData!(
204205
return addData!(dfg, blobstore, vLbl, entry, blob; hashfunction)
205206
end
206207

208+
function addData!(
209+
dfg::AbstractDFG,
210+
blobstore::AbstractBlobStore{T},
211+
vLbl::Symbol,
212+
blobLabel::Symbol,
213+
blob::T,
214+
timestamp = now(localzone());
215+
description = "",
216+
metadata = "",
217+
mimeType::String = "application/octet-stream",
218+
origin = buildSourceString(dfg, vLbl),
219+
# hashfunction = sha256,
220+
) where {T}
221+
#
222+
# checkhash && assertHash(entry, blob; hashfunction)
223+
blobId = addBlob!(blobstore, blob)
224+
225+
entry = BlobEntry(;
226+
blobId,
227+
originId = blobId,
228+
label = blobLabel,
229+
blobstore = blobstore.key,
230+
# hash = string(bytes2hex(hashfunction(blob))),
231+
hash = "",
232+
origin,
233+
description,
234+
mimeType,
235+
metadata,
236+
timestamp,
237+
)
238+
addBlobEntry!(dfg, vLbl, entry)
239+
return entry => blob
240+
end
241+
207242
function updateData!(
208243
dfg::AbstractDFG,
209244
label::Symbol,

src/DistributedFactorGraphs.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ using OrderedCollections
3838
export OrderedDict
3939

4040
using CSV
41+
using Tables
4142

4243
# used for @defVariable
4344
import ManifoldsBase

src/services/AbstractDFG.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1302,7 +1302,7 @@ function getNeighborhood(
13021302
solvable::Int = 0,
13031303
)
13041304
# find neighbors at distance to add
1305-
neighbors = Symbol[]
1305+
neighbors = Set{Symbol}()
13061306
if distance > 0
13071307
for l in variableFactorLabels
13081308
union!(neighbors, getNeighborhood(dfg, l, distance))

0 commit comments

Comments
 (0)