Skip to content
Draft
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,17 @@ version = "1.3.6"
Extents = "411431e0-e8b7-467b-b5e0-f676ba4f2910"
GeoFormatTypes = "68eda718-8dee-11e9-39e7-89f7f65f511f"

[weakdeps]
Tables = "bd369af6-aec1-5ad0-b16a-f7cc5008161c"

[extensions]
GeoInterfaceTablesExt = "Tables"

[compat]
Extents = "0.1.1"
GeoFormatTypes = "0.4"
julia = "1"
Tables = "1"
julia = "1.9"

[extras]
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
Expand Down
129 changes: 129 additions & 0 deletions ext/GeoInterfaceTablesExt.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
module GeoInterfaceTablesExt

using GeoInterface
using GeoInterface.Wrappers
using Tables

# This module is meant to extend the Tables.jl interface to features and feature collections, such that they can be used with Tables.jl.
# This enables the use of the Tables.jl ecosystem with GeoInterface wrapper geometries.

# First, define the Tables interface

Tables.istable(::Type{<: Wrappers.FeatureCollection}) = true
Tables.isrowtable(::Type{<: Wrappers.FeatureCollection}) = true
Tables.rowaccess(::Type{<: Wrappers.FeatureCollection}) = true
Tables.rows(fc::Wrappers.FeatureCollection{P, C, E}) where {P <: Union{AbstractArray{<: Wrappers.Feature}, Tuple{Vararg{<: Wrappers.Feature}}}, C, E} = GeoInterface.getfeature(fc)
Tables.rows(fc::Wrappers.FeatureCollection) = Iterators.map(Wrappers.Feature, GeoInterface.getfeature(fc))
Tables.schema(fc::Wrappers.FeatureCollection) = property_schema(GeoInterface.getfeature(fc))

Check warning on line 17 in ext/GeoInterfaceTablesExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/GeoInterfaceTablesExt.jl#L12-L17

Added lines #L12 - L17 were not covered by tests

# Define the row access interface for feature wrappers
function Tables.getcolumn(row::Wrappers.Feature, i::Int)
if i == 1
return GeoInterface.geometry(row)

Check warning on line 22 in ext/GeoInterfaceTablesExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/GeoInterfaceTablesExt.jl#L20-L22

Added lines #L20 - L22 were not covered by tests
else
return GeoInterface.properties(row)[i-1]

Check warning on line 24 in ext/GeoInterfaceTablesExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/GeoInterfaceTablesExt.jl#L24

Added line #L24 was not covered by tests
end
end
Tables.getcolumn(row::Wrappers.Feature, nm::Symbol) = nm === :geometry ? GeoInterface.geometry(row) : Tables.getcolumn(GeoInterface.properties(row), nm)
Tables.columnnames(row::Wrappers.Feature) = (:geometry, propertynames(GeoInterface.properties(row))...)

Check warning on line 28 in ext/GeoInterfaceTablesExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/GeoInterfaceTablesExt.jl#L27-L28

Added lines #L27 - L28 were not covered by tests

# Copied from GeoJSON.jl
# Credit to [Rafael Schouten](@rafaqz)
# Adapted from JSONTables.jl jsontable method
# We cannot simply use their method as we have concrete types and need the key/value pairs
# of the properties field, rather than the main object
# TODO: Is `missT` required?
# TODO: The `getfield` is probably required once
missT(::Type{Nothing}) = Missing
missT(::Type{T}) where {T} = T

Check warning on line 38 in ext/GeoInterfaceTablesExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/GeoInterfaceTablesExt.jl#L37-L38

Added lines #L37 - L38 were not covered by tests

function property_schema(features)

Check warning on line 40 in ext/GeoInterfaceTablesExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/GeoInterfaceTablesExt.jl#L40

Added line #L40 was not covered by tests
# Otherwise find the shared names
names = Set{Symbol}()
types = Dict{Symbol,Type}()
for feature in features
props = GeoInterface.properties(feature)
isnothing(props) && continue
if isempty(names)
for k in keys(props)
k === :geometry && continue
push!(names, k)
types[k] = missT(typeof(props[k]))
end
push!(names, :geometry)
types[:geometry] = missT(typeof(GeoInterface.geometry(feature)))

Check warning on line 54 in ext/GeoInterfaceTablesExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/GeoInterfaceTablesExt.jl#L42-L54

Added lines #L42 - L54 were not covered by tests
else
for nm in names
T = types[nm]
if haskey(props, nm)
v = props[nm]
if !(missT(typeof(v)) <: T)
types[nm] = Union{T,missT(typeof(v))}

Check warning on line 61 in ext/GeoInterfaceTablesExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/GeoInterfaceTablesExt.jl#L56-L61

Added lines #L56 - L61 were not covered by tests
end
elseif hasfield(typeof(feature), nm)
v = getfield(feature, nm)
if !(missT(typeof(v)) <: T)
types[nm] = Union{T,missT(typeof(v))}

Check warning on line 66 in ext/GeoInterfaceTablesExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/GeoInterfaceTablesExt.jl#L63-L66

Added lines #L63 - L66 were not covered by tests
end
elseif !(T isa Union && T.a === Missing)
types[nm] = Union{Missing,types[nm]}

Check warning on line 69 in ext/GeoInterfaceTablesExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/GeoInterfaceTablesExt.jl#L68-L69

Added lines #L68 - L69 were not covered by tests
end
end
for (k, v) in pairs(props)
k === :geometry && continue
if !(k in names)
push!(names, k)
types[k] = Union{Missing,missT(typeof(v))}

Check warning on line 76 in ext/GeoInterfaceTablesExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/GeoInterfaceTablesExt.jl#L71-L76

Added lines #L71 - L76 were not covered by tests
end
end

Check warning on line 78 in ext/GeoInterfaceTablesExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/GeoInterfaceTablesExt.jl#L78

Added line #L78 was not covered by tests
end
end
return collect(names), types

Check warning on line 81 in ext/GeoInterfaceTablesExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/GeoInterfaceTablesExt.jl#L80-L81

Added lines #L80 - L81 were not covered by tests
end



# Finally, define the metadata interface. FeatureCollection wrappers have no metadata, so we simply specify geometry columns and CRS.

Tables.DataAPI.metadatasupport(::Type{<: Wrappers.FeatureCollection}) = (; read = true, write = false)
Tables.DataAPI.metadatakeys(::Wrappers.FeatureCollection) = ("GEOINTERFACE:geometrycolumns", "GEOINTERFACE:crs")
function Tables.DataAPI.metadata(fc::Wrappers.FeatureCollection, key::AbstractString; style = false)
result = if key == "GEOINTERFACE:geometrycolumns"
(:geometry,)
elseif key == "GEOINTERFACE:crs"
if isnothing(GeoInterface.crs(fc))
nothing

Check warning on line 95 in ext/GeoInterfaceTablesExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/GeoInterfaceTablesExt.jl#L88-L95

Added lines #L88 - L95 were not covered by tests
# or
#=
GeoFormatTypes.ESRIWellKnownText(
"""
ENGCRS["Undefined Cartesian SRS with unknown unit",
EDATUM["Unknown engineering datum"],
CS[Cartesian,2],
AXIS["X",unspecified,
ORDER[1],
LENGTHUNIT["unknown",0]],
AXIS["Y",unspecified,
ORDER[2],
LENGTHUNIT["unknown",0]]]
"""
)
=#
else
GeoInterface.crs(fc)

Check warning on line 113 in ext/GeoInterfaceTablesExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/GeoInterfaceTablesExt.jl#L113

Added line #L113 was not covered by tests
end
else
throw(KeyError(key))

Check warning on line 116 in ext/GeoInterfaceTablesExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/GeoInterfaceTablesExt.jl#L116

Added line #L116 was not covered by tests
end

if style
return (result, :note)

Check warning on line 120 in ext/GeoInterfaceTablesExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/GeoInterfaceTablesExt.jl#L119-L120

Added lines #L119 - L120 were not covered by tests
else
return result

Check warning on line 122 in ext/GeoInterfaceTablesExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/GeoInterfaceTablesExt.jl#L122

Added line #L122 was not covered by tests
end
end




end # module
Loading