Skip to content

Commit b5c19b4

Browse files
committed
feat: generate actual json in `encode function
BREAKING_CHANGE: `encode_geojson` function was generating `dynamic.Dynamic` which is pretty useless from consumer standpoint. Now it is refactored to generate `Json` type which can be stringified with `json.to_string`. Note: currently intentionally left encoding arbitrary `Feature` properties unimplemented. Signed-off-by: Aleksei Gurianov <[email protected]>
1 parent 7a022ea commit b5c19b4

13 files changed

+219
-215
lines changed

README.md

+14-3
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,27 @@ pub fn main() {
3434
case result {
3535
Ok(geojson) -> {
3636
// Successfully decoded GeoJSON
37-
let encoded = gleojson.encode_geojson(geojson)
38-
// encoded is now a Dynamic representation of the GeoJSON object
39-
// You can use it for further processing or encoding back to JSON
4037
}
4138
Error(errors) -> {
4239
todo
4340
// Handle decoding errors
4441
// errors contains information about what went wrong during decoding
4542
}
4643
}
44+
45+
// Construct GeoJSON from types
46+
let geojson = gleojson.GeoJSONFeatureCollection(
47+
gleojson.FeatureCollection([
48+
gleojson.Feature(
49+
geometry: option.Some(gleojson.Point([1.0, 2.0])),
50+
properties: option.None,
51+
id: option.Some(gleojson.StringId("feature-id")),
52+
),
53+
]),
54+
)
55+
56+
// Encode to JSON string
57+
gleojson.encode_geojson(geojson) |> json.to_string
4758
}
4859
```
4960

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
version: 1.2.3
3+
title: feature_encode_decode
4+
---
5+
{"id":"feature-id","type":"Feature","geometry":{"type":"Point","coordinates":[1.0,2.0]},"properties":null}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
version: 1.2.3
3+
title: featurecollection_encode_decode
4+
---
5+
{"type":"FeatureCollection","features":[{"id":"feature-id","type":"Feature","geometry":{"type":"Point","coordinates":[1.0,2.0]},"properties":null}]}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
version: 1.2.3
3+
title: geometrycollection_encode_decode
4+
---
5+
{"type":"GeometryCollection","geometries":[{"type":"Point","coordinates":[1.0,2.0]},{"type":"LineString","coordinates":[[3.0,4.0],[5.0,6.0]]}]}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
version: 1.2.3
3+
title: linestring_encode_decode
4+
---
5+
{"type":"LineString","coordinates":[[1.0,2.0],[3.0,4.0]]}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
version: 1.2.3
3+
title: multipoint_encode_decode
4+
---
5+
{"type":"MultiPoint","coordinates":[[1.0,2.0],[3.0,4.0]]}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
version: 1.2.3
3+
title: multipolygon_encode_decode
4+
---
5+
{"type":"MultiPolygon","coordinates":[[[[1.0,2.0],[3.0,4.0],[5.0,6.0],[1.0,2.0]]],[[[7.0,8.0],[9.0,10.0],[11.0,12.0],[7.0,8.0]]]]}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
version: 1.2.3
3+
title: point_encode_decode
4+
---
5+
{"type":"Point","coordinates":[1.0,2.0]}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
version: 1.2.3
3+
title: polygon_encode_decode
4+
---
5+
{"type":"Polygon","coordinates":[[[1.0,2.0],[3.0,4.0],[5.0,6.0],[1.0,2.0]]]}

gleam.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ links = [{ title = "RFC7946", href = "https://datatracker.ietf.org/doc/html/rfc7
88

99
[dependencies]
1010
gleam_stdlib = ">= 0.34.0 and < 2.0.0"
11+
gleam_json = ">= 2.0.0 and < 3.0.0"
1112

1213
[dev-dependencies]
1314
gleeunit = ">= 1.0.0 and < 2.0.0"
14-
gleam_json = ">= 2.0.0 and < 3.0.0"
15+
birdie = ">= 1.2.3 and < 2.0.0"

manifest.toml

+14
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,26 @@
22
# You typically do not need to edit this file
33

44
packages = [
5+
{ name = "argv", version = "1.0.2", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D" },
6+
{ name = "birdie", version = "1.2.3", build_tools = ["gleam"], requirements = ["argv", "edit_distance", "filepath", "glance", "gleam_community_ansi", "gleam_erlang", "gleam_stdlib", "justin", "rank", "simplifile", "trie_again"], otp_app = "birdie", source = "hex", outer_checksum = "AE1207210E9CC8F4170BCE3FB3C23932F314C352C3FD1BCEA44CF4BF8CF60F93" },
7+
{ name = "edit_distance", version = "2.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "edit_distance", source = "hex", outer_checksum = "A1E485C69A70210223E46E63985FA1008B8B2DDA9848B7897469171B29020C05" },
8+
{ name = "filepath", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "EFB6FF65C98B2A16378ABC3EE2B14124168C0CE5201553DE652E2644DCFDB594" },
9+
{ name = "glance", version = "0.11.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "glexer"], otp_app = "glance", source = "hex", outer_checksum = "8F3314D27773B7C3B9FB58D8C02C634290422CE531988C0394FA0DF8676B964D" },
10+
{ name = "gleam_community_ansi", version = "1.4.1", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "4CD513FC62523053E62ED7BAC2F36136EC17D6A8942728250A9A00A15E340E4B" },
11+
{ name = "gleam_community_colour", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "A49A5E3AE8B637A5ACBA80ECB9B1AFE89FD3D5351FF6410A42B84F666D40D7D5" },
12+
{ name = "gleam_erlang", version = "0.27.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "DE468F676D71B313C6C8C5334425CFCF827837333F8AB47B64D8A6D7AA40185D" },
513
{ name = "gleam_json", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "CB10B0E7BF44282FB25162F1A24C1A025F6B93E777CCF238C4017E4EEF2CDE97" },
614
{ name = "gleam_stdlib", version = "0.40.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "86606B75A600BBD05E539EB59FABC6E307EEEA7B1E5865AFB6D980A93BCB2181" },
715
{ name = "gleeunit", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "F7A7228925D3EE7D0813C922E062BFD6D7E9310F0BEE585D3A42F3307E3CFD13" },
16+
{ name = "glexer", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glexer", source = "hex", outer_checksum = "BD477AD657C2B637FEF75F2405FAEFFA533F277A74EF1A5E17B55B1178C228FB" },
17+
{ name = "justin", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "justin", source = "hex", outer_checksum = "7FA0C6DB78640C6DC5FBFD59BF3456009F3F8B485BF6825E97E1EB44E9A1E2CD" },
18+
{ name = "rank", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "rank", source = "hex", outer_checksum = "5660E361F0E49CBB714CC57CC4C89C63415D8986F05B2DA0C719D5642FAD91C9" },
19+
{ name = "simplifile", version = "2.2.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "0DFABEF7DC7A9E2FF4BB27B108034E60C81BEBFCB7AB816B9E7E18ED4503ACD8" },
20+
{ name = "trie_again", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "trie_again", source = "hex", outer_checksum = "5B19176F52B1BD98831B57FDC97BD1F88C8A403D6D8C63471407E78598E27184" },
821
]
922

1023
[requirements]
24+
birdie = { version = ">= 1.2.3 and < 2.0.0" }
1125
gleam_json = { version = ">= 2.0.0 and < 3.0.0" }
1226
gleam_stdlib = { version = ">= 0.34.0 and < 2.0.0" }
1327
gleeunit = { version = ">= 1.0.0 and < 2.0.0" }

src/gleojson.gleam

+74-52
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
import gleam/dict
1818
import gleam/dynamic
19-
import gleam/list
19+
import gleam/json
2020
import gleam/option
2121
import gleam/result
2222

@@ -64,90 +64,112 @@ pub type GeoJSON {
6464

6565
// Encoding Functions
6666

67-
/// Encodes a geometry into a dynamic value.
68-
fn encode_geometry(geometry: Geometry) -> dynamic.Dynamic {
67+
/// Encodes a geometry into a JSON object.
68+
fn encode_geometry(geometry: Geometry) -> json.Json {
6969
case geometry {
7070
Point(coordinates) -> {
71-
dict.from_list([
72-
#("type", dynamic.from("Point")),
73-
#("coordinates", dynamic.from(coordinates)),
71+
json.object([
72+
#("type", json.string("Point")),
73+
#("coordinates", json.array(coordinates, of: json.float)),
7474
])
7575
}
7676
MultiPoint(multipoint) -> {
77-
dict.from_list([
78-
#("type", dynamic.from("MultiPoint")),
79-
#("coordinates", dynamic.from(multipoint)),
77+
json.object([
78+
#("type", json.string("MultiPoint")),
79+
#(
80+
"coordinates",
81+
json.array(multipoint, of: json.array(_, of: json.float)),
82+
),
8083
])
8184
}
8285
LineString(linestring) -> {
83-
dict.from_list([
84-
#("type", dynamic.from("LineString")),
85-
#("coordinates", dynamic.from(linestring)),
86+
json.object([
87+
#("type", json.string("LineString")),
88+
#(
89+
"coordinates",
90+
json.array(linestring, of: json.array(_, of: json.float)),
91+
),
8692
])
8793
}
8894
MultiLineString(multilinestring) -> {
89-
dict.from_list([
90-
#("type", dynamic.from("MultiLineString")),
91-
#("coordinates", dynamic.from(multilinestring)),
95+
json.object([
96+
#("type", json.string("MultiLineString")),
97+
#(
98+
"coordinates",
99+
json.array(multilinestring, of: json.array(_, of: json.array(
100+
_,
101+
of: json.float,
102+
))),
103+
),
92104
])
93105
}
94106
Polygon(polygon) -> {
95-
dict.from_list([
96-
#("type", dynamic.from("Polygon")),
97-
#("coordinates", dynamic.from(polygon)),
107+
json.object([
108+
#("type", json.string("Polygon")),
109+
#(
110+
"coordinates",
111+
json.array(polygon, of: json.array(_, of: json.array(
112+
_,
113+
of: json.float,
114+
))),
115+
),
98116
])
99117
}
100118
MultiPolygon(multipolygon) -> {
101-
dict.from_list([
102-
#("type", dynamic.from("MultiPolygon")),
103-
#("coordinates", dynamic.from(multipolygon)),
119+
json.object([
120+
#("type", json.string("MultiPolygon")),
121+
#(
122+
"coordinates",
123+
json.array(
124+
multipolygon,
125+
of: json.array(_, of: json.array(_, of: json.array(
126+
_,
127+
of: json.float,
128+
))),
129+
),
130+
),
104131
])
105132
}
106133
GeometryCollection(collection) -> {
107-
let geometries_dyn_list = list.map(collection, encode_geometry)
108-
dict.from_list([
109-
#("type", dynamic.from("GeometryCollection")),
110-
#("geometries", dynamic.from(geometries_dyn_list)),
134+
json.object([
135+
#("type", json.string("GeometryCollection")),
136+
#("geometries", json.array(collection, of: encode_geometry)),
111137
])
112138
}
113139
}
114-
|> dynamic.from
115140
}
116141

117-
/// Encodes a feature into a dynamic value.
118-
fn encode_feature(feature: Feature) -> dynamic.Dynamic {
119-
let Feature(geometry_opt, properties_opt, id_opt) = feature
120-
let geometry_dyn = case geometry_opt {
142+
/// Encodes a feature into a JSON object.
143+
fn encode_feature(feature: Feature) -> json.Json {
144+
let Feature(geometry_opt, _properties_opt, id_opt) = feature
145+
let geometry_json = case geometry_opt {
121146
option.Some(geometry) -> encode_geometry(geometry)
122-
option.None -> dynamic.from(Nil)
123-
}
124-
let properties_dyn = case properties_opt {
125-
option.Some(props) -> dynamic.from(props)
126-
option.None -> dynamic.from(Nil)
147+
option.None -> json.null()
127148
}
128-
let base_obj =
129-
dict.from_list([
130-
#("type", dynamic.from("Feature")),
131-
#("geometry", geometry_dyn),
132-
#("properties", properties_dyn),
133-
])
149+
// let properties_json = case properties_opt {
150+
// option.Some(props) -> json.object(props)
151+
// option.None -> json.object([])
152+
// }
153+
let base_obj = [
154+
#("type", json.string("Feature")),
155+
#("geometry", geometry_json),
156+
#("properties", json.null()),
157+
]
134158
case id_opt {
135-
option.Some(StringId(id)) -> dict.insert(base_obj, "id", dynamic.from(id))
136-
option.Some(NumberId(id)) -> dict.insert(base_obj, "id", dynamic.from(id))
159+
option.Some(StringId(id)) -> [#("id", json.string(id)), ..base_obj]
160+
option.Some(NumberId(id)) -> [#("id", json.float(id)), ..base_obj]
137161
option.None -> base_obj
138162
}
139-
|> dynamic.from
163+
|> json.object
140164
}
141165

142-
/// Encodes a feature collection into a dynamic value.
143-
fn encode_featurecollection(collection: FeatureCollection) -> dynamic.Dynamic {
166+
/// Encodes a feature collection into a JSON object.
167+
fn encode_featurecollection(collection: FeatureCollection) -> json.Json {
144168
let FeatureCollection(features) = collection
145-
let features_dyn_list = list.map(features, encode_feature)
146-
dict.from_list([
147-
#("type", dynamic.from("FeatureCollection")),
148-
#("features", dynamic.from(features_dyn_list)),
169+
json.object([
170+
#("type", json.string("FeatureCollection")),
171+
#("features", json.array(features, of: encode_feature)),
149172
])
150-
|> dynamic.from
151173
}
152174

153175
/// Encodes a GeoJSON object into a dynamic value.
@@ -159,7 +181,7 @@ fn encode_featurecollection(collection: FeatureCollection) -> dynamic.Dynamic {
159181
/// let encoded = encode_geojson(point)
160182
/// // encoded will be a dynamic representation of the GeoJSON object
161183
/// ```
162-
pub fn encode_geojson(geojson: GeoJSON) -> dynamic.Dynamic {
184+
pub fn encode_geojson(geojson: GeoJSON) -> json.Json {
163185
case geojson {
164186
GeoJSONGeometry(geometry) -> encode_geometry(geometry)
165187
GeoJSONFeature(feature) -> encode_feature(feature)

0 commit comments

Comments
 (0)