Skip to content

Commit

Permalink
make it easier to work with metadata by providing more default behavi…
Browse files Browse the repository at this point in the history
…ors (#56)
  • Loading branch information
bkamins authored Nov 9, 2022
1 parent ca91305 commit 69313ee
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 13 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "DataAPI"
uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a"
authors = ["quinnj <quinn.jacobd@gmail.com>"]
version = "1.12.0"
version = "1.13.0"

[compat]
julia = "1"
Expand Down
65 changes: 61 additions & 4 deletions src/DataAPI.jl
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,28 @@ mapping for `key` is missing. If `style=true` return `(default, :default)`.
"""
function metadata end

"""
metadata(x; style::Bool=false)
Return a dictionary mapping all metadata keys to metadata values associated
with object `x`. Throw an error if `x` does not support reading metadata.
If `style=true` values are tuples of metadata value and metadata style. Metadata
style is an additional information about the kind of metadata that is stored for
the `key`.
$STYLE_INFO
The returned dictionary may be freshly allocated on each call to `metadata` and
is considered to be owned by `x` so it must not be modified.
"""
function metadata(x::T; style::Bool=false) where {T}
if !metadatasupport(T).read
throw(ArgumentError("Objects of type $T do not support reading metadata"))
end
return Dict(key => metadata(x, key, style=style) for key in metadatakeys(x))
end

"""
metadatakeys(x)
Expand All @@ -356,10 +378,10 @@ Throw an error if `x` does not support reading metadata.
function metadatakeys end

"""
metadata!(x, key::AbstractString, value; style)
metadata!(x, key::AbstractString, value; style::Symbol=:default)
Set metadata for object `x` for key `key` to have value `value`
and style `style` and return `x`.
and style `style` (`:default` by default) and return `x`.
Throw an error if `x` does not support setting metadata.
$STYLE_INFO
Expand Down Expand Up @@ -404,6 +426,41 @@ If `style=true` return `(default, :default)`.
"""
function colmetadata end

"""
colmetadata(x, [col]; style::Bool=false)
If `col` is not passed return a dictionary mapping columns represented as
`Symbol` that have associated metadata to dictionaries mapping all
metadata keys to metadata values associated with table `x` for a given column.
If `col` is passed return a dictionary mapping all column metadata keys to metadata values
associated with column `col` of table `x`. Throw an error if `x` does not
support reading metadata for column `col` or column `col` is not present in `x`.
If `style=true` values are tuples of metadata value and metadata style. Metadata
style is an additional information about the kind of metadata that is stored for
the `key`.
$STYLE_INFO
The returned dictionary may be freshly allocated on each call to `colmetadata`
and is considered to be owned by `x` so it must not be modified.
"""
function colmetadata(x::T, col; style::Bool=false) where {T}
if !colmetadatasupport(T).read
throw(ArgumentError("Objects of type $T do not support reading column metadata"))
end
return Dict(key => colmetadata(x, col, key, style=style) for key in colmetadatakeys(x, col))
end

function colmetadata(x::T; style::Bool=false) where {T}
if !colmetadatasupport(T).read
throw(ArgumentError("Objects of type $T do not support reading column metadata"))
end
return Dict(col => Dict(key => colmetadata(x, col, key, style=style) for key in keys)
for (col, keys) in colmetadatakeys(x))
end

"""
colmetadatakeys(x, [col])
Expand All @@ -421,10 +478,10 @@ If `x` does not support column metadata return `()`.
function colmetadatakeys end

"""
colmetadata!(x, col, key::AbstractString, value; style)
colmetadata!(x, col, key::AbstractString, value; style::Symbol=:default)
Set metadata for table `x` for column `col` for key `key` to have value `value`
and style `style` and return `x`.
and style `style` (`:default` by default) and return `x`.
Throw an error if `x` does not support setting metadata for column `col`.
$COL_INFO
Expand Down
28 changes: 20 additions & 8 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,7 @@ end

DataAPI.metadatakeys(x::TestMeta) = keys(x.table)

function DataAPI.metadata!(x::TestMeta, key::AbstractString, value; style)
x.table[key] = (value, style)
return x
end

function DataAPI.metadata!(x::TestMeta, key::AbstractString, value; style)
function DataAPI.metadata!(x::TestMeta, key::AbstractString, value; style::Symbol=:default)
x.table[key] = (value, style)
return x
end
Expand All @@ -52,7 +47,8 @@ function DataAPI.colmetadata(x::TestMeta, col::Symbol, key::AbstractString; styl
return style ? x.col[col][key] : x.col[col][key][1]
end

function DataAPI.colmetadata(x::TestMeta, col::Symbol, key::AbstractString, default; style::Bool=false)
function DataAPI.colmetadata(x::TestMeta, col::Symbol, key::AbstractString, default;
style::Bool=false)
haskey(x.table, col) && haskey(x.table[col], key) && return DataAPI.metadata(x, key, style=style)
return style ? (default, :default) : default
end
Expand All @@ -67,7 +63,8 @@ function DataAPI.colmetadatakeys(x::TestMeta)
return (col => keys(x.col[col]) for col in keys(x.col))
end

function DataAPI.colmetadata!(x::TestMeta, col::Symbol, key::AbstractString, value; style)
function DataAPI.colmetadata!(x::TestMeta, col::Symbol, key::AbstractString, value;
style::Symbol=:default)
if haskey(x.col, col)
x.col[col][key] = (value, style)
else
Expand Down Expand Up @@ -264,7 +261,9 @@ end
@test_throws MethodError DataAPI.deletemetadata!(1, "a")
@test_throws MethodError DataAPI.emptymetadata!(1)
@test_throws MethodError DataAPI.metadata(1, "a")
@test_throws ArgumentError DataAPI.metadata(1)
@test_throws MethodError DataAPI.metadata(1, "a", style=true)
@test_throws ArgumentError DataAPI.metadata(1, style=true)
@test_throws MethodError DataAPI.metadatakeys(1)

@test_throws MethodError DataAPI.colmetadata!(1, :col, "a", 10, style=:default)
Expand All @@ -274,7 +273,11 @@ end
@test_throws MethodError DataAPI.emptycolmetadata!(1, 1)
@test_throws MethodError DataAPI.emptycolmetadata!(1)
@test_throws MethodError DataAPI.colmetadata(1, :col, "a")
@test_throws ArgumentError DataAPI.colmetadata(1, :col)
@test_throws ArgumentError DataAPI.colmetadata(1)
@test_throws MethodError DataAPI.colmetadata(1, :col, "a", style=true)
@test_throws ArgumentError DataAPI.colmetadata(1, :col, style=true)
@test_throws ArgumentError DataAPI.colmetadata(1, style=true)
@test_throws MethodError DataAPI.colmetadata!(1, 1, "a", 10, style=:default)
@test_throws MethodError DataAPI.colmetadata(1, 1, "a")
@test_throws MethodError DataAPI.colmetadata(1, 1, "a", style=true)
Expand All @@ -290,14 +293,18 @@ end
@test DataAPI.colmetadatasupport(TestMeta) == (read=true, write=true)

@test isempty(DataAPI.metadatakeys(tm))
@test DataAPI.metadata(tm) == Dict()
@test DataAPI.metadata(tm, style=true) == Dict()
@test DataAPI.metadata!(tm, "a", "100", style=:note) == tm
@test collect(DataAPI.metadatakeys(tm)) == ["a"]
@test_throws KeyError DataAPI.metadata(tm, "b")
@test DataAPI.metadata(tm, "b", 123) == 123
@test_throws KeyError DataAPI.metadata(tm, "b", style=true)
@test DataAPI.metadata(tm, "b", 123, style=true) == (123, :default)
@test DataAPI.metadata(tm, "a") == "100"
@test DataAPI.metadata(tm) == Dict("a" => "100")
@test DataAPI.metadata(tm, "a", style=true) == ("100", :note)
@test DataAPI.metadata(tm, style=true) == Dict("a" => ("100", :note))
DataAPI.deletemetadata!(tm, "a")
@test isempty(DataAPI.metadatakeys(tm))
@test DataAPI.metadata!(tm, "a", "100", style=:note) == tm
Expand All @@ -306,6 +313,7 @@ end

@test DataAPI.colmetadatakeys(tm) == ()
@test DataAPI.colmetadatakeys(tm, :col) == ()
@test DataAPI.colmetadata(tm) == Dict()
@test DataAPI.colmetadata!(tm, :col, "a", "100", style=:note) == tm
@test [k => collect(v) for (k, v) in DataAPI.colmetadatakeys(tm)] == [:col => ["a"]]
@test collect(DataAPI.colmetadatakeys(tm, :col)) == ["a"]
Expand All @@ -316,7 +324,11 @@ end
@test_throws KeyError DataAPI.colmetadata(tm, :col2, "a")
@test_throws KeyError DataAPI.colmetadata(tm, :col2, "a", style=true)
@test DataAPI.colmetadata(tm, :col, "a") == "100"
@test DataAPI.colmetadata(tm, :col) == Dict("a" => "100")
@test DataAPI.colmetadata(tm) == Dict(:col => Dict("a" => "100"))
@test DataAPI.colmetadata(tm, :col, "a", style=true) == ("100", :note)
@test DataAPI.colmetadata(tm, :col, style=true) == Dict("a" => ("100", :note))
@test DataAPI.colmetadata(tm, style=true) == Dict(:col => Dict("a" => ("100", :note)))
DataAPI.deletecolmetadata!(tm, :col, "a")
@test isempty(DataAPI.colmetadatakeys(tm, :col))
@test DataAPI.colmetadata!(tm, :col, "a", "100", style=:note) == tm
Expand Down

2 comments on commit 69313ee

@bkamins
Copy link
Member Author

@bkamins bkamins commented on 69313ee Nov 9, 2022

Choose a reason for hiding this comment

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

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

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

Registration pull request created: JuliaRegistries/General/71942

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v1.13.0 -m "<description of version>" 69313eea87d3214d09560bd05439ebf935f25bf2
git push origin v1.13.0

Please sign in to comment.