Skip to content

Commit 61c6d75

Browse files
authored
refactor: parameterize types and add NoData type for dataset handling (#12)
1 parent cdaddf1 commit 61c6d75

File tree

8 files changed

+59
-53
lines changed

8 files changed

+59
-53
lines changed

src/dataset.jl

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
44
A concrete dataset with a name, data (parameters), and metadata.
55
"""
6-
@kwdef struct DataSet{T, MD} <: AbstractDataSet
6+
@kwdef struct DataSet{D, MD} <: AbstractDataSet
77
name::String = ""
8-
data::T = Dict()
8+
data::D = NoData()
99
metadata::MD = NoMetadata()
1010
end
1111

@@ -49,18 +49,11 @@ ds = DataSet(lds; probe=1, data_rate="fast", data_type="des")
4949
The format string and variable patterns use placeholders like `{probe}`, `{data_rate}`,
5050
which are replaced with actual values when creating a concrete `DataSet`.
5151
"""
52-
@kwdef struct LDataSet{MD} <: AbstractDataSet
52+
@kwdef struct LDataSet{D, MD} <: AbstractDataSet
5353
name::String = ""
54-
format::String = ""
55-
data::Dict{String,String} = Dict()
54+
data::D = NoData()
5655
metadata::MD = NoMetadata()
57-
end
58-
59-
"Construct a `LDataSet` from a dictionary."
60-
function LDataSet(d::Dict)
61-
dict = symbolify(d)
62-
rename!(dict, :parameters, :data)
63-
LDataSet(; dict...)
56+
format::String = ""
6457
end
6558

6659
"""
@@ -83,11 +76,5 @@ for f in (:getindex, :iterate, :size, :length, :keys)
8376
@eval Base.$f(var::AbstractDataSet, args...) = $f(parent(var), args...)
8477
end
8578

86-
# https://github.com/JuliaLang/julia/issues/54454
87-
_nth(itr, n) = begin
88-
y = iterate(Base.Iterators.drop(itr, n-1))
89-
isnothing(y) ? throw(BoundsError(itr, n)) : first(y)
90-
end
91-
9279
Base.getindex(ds::DataSet, i::Integer) = _nth(values(ds.data), i)
9380
Base.push!(ds::DataSet, v) = push!(ds.data, v)

src/metadata.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ always returns `false`.
1010
"""
1111
struct NoMetadata end
1212

13+
const NoData = NoMetadata
14+
1315
Base.keys(::NoMetadata) = ()
1416

1517
# Allow merging NoMetadata with a Dict or keyword arguments

src/product.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
struct Product{A,F} <: AbstractProduct
1+
struct Product{A,F,MD} <: AbstractProduct
22
data::A
33
transformation::F
44
name::Union{String,Symbol}
5-
metadata::Any
6-
function Product(data::A, transformation::F, name="", metadata=NoMetadata(); kwargs...) where {A,F}
5+
metadata::MD
6+
function Product(data::A, transformation::F, name="", metadata::MD=NoMetadata(); kwargs...) where {A,F,MD}
77
metadata = merge(metadata, kwargs)
8-
new{A,F}(data, transformation, name, metadata)
8+
new{A,F,MD}(data, transformation, name, metadata)
99
end
1010
end
1111

src/types.jl

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,16 @@ A representation of a project or mission containing instruments and datasets.
1717
- `instruments`: Collection of instruments
1818
- `datasets`: Collection of datasets
1919
"""
20-
mutable struct Project <: AbstractProject
20+
mutable struct Project{I, D, MD} <: AbstractProject
2121
name::String
22-
metadata::Dict
23-
instruments::Dict
24-
datasets::Dict
22+
instruments::I
23+
datasets::D
24+
metadata::MD
2525
end
2626

2727
"keyword-based constructor"
2828
function Project(; name="", instruments=Dict(), datasets=Dict(), metadata=SDict(), kwargs...)
29-
Project(name, compat_dict(metadata, kwargs), instruments, datasets)
29+
Project(name, instruments, datasets, compat_dict(metadata, kwargs))
3030
end
3131

3232
"""
@@ -37,19 +37,19 @@ end
3737
- `metadata`: Additional metadata
3838
- `datasets`: Collection of datasets
3939
"""
40-
struct Instrument <: AbstractInstrument
40+
struct Instrument{D, MD} <: AbstractInstrument
4141
name::String
42-
metadata::Dict
43-
datasets::Dict
42+
datasets::D
43+
metadata::MD
4444
end
4545

4646
"keyword-based constructor"
4747
function Instrument(; name="", metadata=SDict(), datasets=Dict(), kwargs...)
48-
Instrument(name, compat_dict(metadata, kwargs), datasets)
48+
Instrument(name, datasets, compat_dict(metadata, kwargs))
4949
end
5050

5151
"Construct an `Instrument` from a dictionary."
52-
Instrument(d::Dict) = Instrument(; symbolify(d)...)
52+
Instrument(d::AbstractDict) = Instrument(; (Symbol(k) => v for (k, v) in d)...)
5353

5454
Base.insert!(p::Project, i, v::AbstractInstrument) = (p.instruments[i] = v; p)
5555
Base.insert!(p::Union{Project,Instrument}, i, v::AbstractDataSet) = (p.datasets[i] = v; p)

src/utils.jl

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,16 @@ function _insert!(d::AbstractDict{K}, kw) where {K}
6060
return d
6161
end
6262

63+
# https://github.com/JuliaLang/julia/issues/54454
64+
_nth(itr, n) = begin
65+
y = iterate(Base.Iterators.drop(itr, n-1))
66+
isnothing(y) ? throw(BoundsError(itr, n)) : first(y)
67+
end
68+
6369
compat_dict(K::Type, m) = _insert!(Dict{K,Any}(), m)
6470
compat_dict(K::Type, m, kw) = _insert!(compat_dict(K, m), kw)
6571
compat_dict(m, kw) = compat_dict(String, m, kw)
6672

67-
symbolify(d::Dict) = Dict{Symbol,Any}(Symbol(k) => v for (k, v) in d)
68-
6973
function format_pattern(pattern; kwargs...)
7074
pairs = ("{$k}" => v for (k, v) in kwargs)
7175
return replace(pattern, pairs...)

test/Project.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
[deps]
22
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
3+
CheckConcreteStructs = "73c92db5-9da6-4938-911a-6443a7e94a58"
34
JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b"
45
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
56
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"

test/dataset.jl

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
@testitem "DataSet" begin
2+
var1 = [1, 2, 3]
3+
var2 = (4, 5, 6)
4+
dataset = DataSet("Dataset Name", [var1, var2])
5+
@test size(dataset) == (2,)
6+
@test length(dataset) == size(dataset, 1) == 2
7+
@test dataset[1] === var1
8+
@test dataset[2] === var2
9+
@test dataset[1:2] == [var1, var2]
10+
11+
dataset2 = DataSet("Dataset Name", Dict("key1" => var1, "key2" => var2))
12+
@test length(dataset2) == 2
13+
@test dataset2["key1"] === var1
14+
@test dataset2["key2"] === var2
15+
@test dataset2[2] (var1, var2)
16+
@test_throws BoundsError dataset2[3]
17+
end
18+
19+
@testitem "Loading dataset from LDataSet" begin
20+
using SpaceDataModel: LDataSet, DataSet
21+
data = Dict("numberdensity" => "mms{probe}_{data_type}_numberdensity_{data_rate}")
22+
format = "MMS{probe}_FPI_{data_rate}_L2_{data_type}-MOMS"
23+
metadata = Dict("data_rates" => ["fast", "brst"])
24+
ld = @test_nowarn LDataSet(; name = "Test", data, format, metadata)
25+
ds = @test_nowarn DataSet(ld; probe = 1, data_rate = "fast", data_type = "des")
26+
@test ds.name == "MMS1_FPI_FAST_L2_DES-MOMS"
27+
@test ds.data["numberdensity"] == "mms1_des_numberdensity_fast"
28+
end

test/runtests.jl

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@ using Test
77
@test_nowarn SpaceDataModel.workload()
88
end
99

10-
@testitem "Aqua" begin
10+
@testitem "General Checks" begin
1111
using Aqua
12+
using CheckConcreteStructs
1213
Aqua.test_all(SpaceDataModel)
14+
@test all_concrete(SpaceDataModel)
1315
end
1416

1517
@testitem "Project" begin
@@ -26,24 +28,6 @@ end
2628
@test abbr(project) == "Proj"
2729
end
2830

29-
@testitem "DataSet" begin
30-
var1 = [1, 2, 3]
31-
var2 = (4, 5, 6)
32-
dataset = DataSet("Dataset Name", [var1, var2])
33-
@test size(dataset) == (2,)
34-
@test length(dataset) == size(dataset, 1) == 2
35-
@test dataset[1] === var1
36-
@test dataset[2] === var2
37-
@test dataset[1:2] == [var1, var2]
38-
39-
dataset2 = DataSet("Dataset Name", Dict("key1" => var1, "key2" => var2))
40-
@test length(dataset2) == 2
41-
@test dataset2["key1"] === var1
42-
@test dataset2["key2"] === var2
43-
@test dataset2[2] (var1, var2)
44-
@test_throws BoundsError dataset2[3]
45-
end
46-
4731
@testitem "parse_datetime" begin
4832
using SpaceDataModel: parse_datetime
4933
using SpaceDataModel.Dates: DateTime

0 commit comments

Comments
 (0)