Skip to content

Commit

Permalink
Handling of Tables.schema returning nothing or `Schema{names, not…
Browse files Browse the repository at this point in the history
…hing}`
  • Loading branch information
mathieu17g committed Oct 12, 2021
1 parent 843155d commit d8849e4
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 17 deletions.
51 changes: 37 additions & 14 deletions src/tables.jl
Original file line number Diff line number Diff line change
Expand Up @@ -101,29 +101,25 @@ function _convert_coltype_to_AGtype(
end
end

function IFeatureLayer(table::T)::IFeatureLayer where {T}
# Check tables interface's conformance
!Tables.istable(table) &&
throw(DomainError(table, "$table has not a Table interface"))
# Extract table data
rows = Tables.rows(table)
schema = Tables.schema(table)
schema === nothing && error("$table has no Schema")
names = string.(schema.names)
types = schema.types
# TODO consider the case where names == nothing or types == nothing
function _fromtable(
sch::Tables.Schema{names,types},
rows,
)::IFeatureLayer where {names,types}
# TODO maybe constrain `names` and `types` types
strnames = string.(sch.names)

# Convert types and split types/names between geometries and fields
AG_types = collect(_convert_coltype_to_AGtype.(types, names))
AG_types = collect(_convert_coltype_to_AGtype.(sch.types, strnames))

# Split names and types: between geometry type columns and field type columns
geomindices = isa.(AG_types, OGRwkbGeometryType)
!any(geomindices) && error("No column convertible to geometry")
geomtypes = AG_types[geomindices] # TODO consider to use a view
geomnames = names[geomindices]
geomnames = strnames[geomindices]

fieldindices = isa.(AG_types, Tuple{OGRFieldType,OGRFieldSubType})
fieldtypes = AG_types[fieldindices] # TODO consider to use a view
fieldnames = names[fieldindices]
fieldnames = strnames[fieldindices]

# Create layer
layer = createlayer(geom = first(geomtypes))
Expand Down Expand Up @@ -173,3 +169,30 @@ function IFeatureLayer(table::T)::IFeatureLayer where {T}

return layer
end

function _fromtable(
::Tables.Schema{names,nothing},
rows,
)::IFeatureLayer where {names}
cols = Tables.columns(rows)
types = (eltype(collect(col)) for col in cols)
return _fromtable(Tables.Schema(names, types), rows)
end

function _fromtable(::Nothing, rows)::IFeatureLayer
state = iterate(rows)
state === nothing && return IFeatureLayer()
row, _ = state
names = Tables.columnnames(row)
return _fromtable(Tables.Schema(names, nothing), rows)
end

function IFeatureLayer(table)::IFeatureLayer
# Check tables interface's conformance
!Tables.istable(table) &&
throw(DomainError(table, "$table has not a Table interface"))
# Extract table data
rows = Tables.rows(table)
schema = Tables.schema(table)
return _fromtable(schema, rows)
end
19 changes: 16 additions & 3 deletions test/test_tables.jl
Original file line number Diff line number Diff line change
Expand Up @@ -810,9 +810,20 @@ using Tables
function columntablevalues_toWKT(x)
return Tuple(toWKT_withmissings.(x[i]) for i in 1:length(x))
end
function nt2layer2nt_equals_nt(nt::NamedTuple)::Bool
(ct_in, ct_out) =
Tables.columntable.((nt, AG.IFeatureLayer(nt)))
function nt2layer2nt_equals_nt(
nt::NamedTuple;
force_no_schema::Bool = false,
)::Bool
if force_no_schema
(ct_in, ct_out) =
Tables.columntable.((
nt,
AG._fromtable(nothing, Tables.rows(nt)),
))
else
(ct_in, ct_out) =
Tables.columntable.((nt, AG.IFeatureLayer(nt)))
end
(ctv_in, ctv_out) =
columntablevalues_toWKT.(values.((ct_in, ct_out)))
(spidx_in, spidx_out) =
Expand Down Expand Up @@ -908,6 +919,7 @@ using Tables
]),
],
])
@test_skip nt2layer2nt_equals_nt(nt; force_no_schema = true)
@test_skip nt2layer2nt_equals_nt(nt)

# Test with `missing` values
Expand Down Expand Up @@ -955,6 +967,7 @@ using Tables
]),
],
])
@test nt2layer2nt_equals_nt(nt; force_no_schema = true)
@test nt2layer2nt_equals_nt(nt)
end
end
Expand Down

0 comments on commit d8849e4

Please sign in to comment.