1use crate::{Error, FromJsonPath, Result};
2use stac::{Catalog, Collection, FromNdjson, Item, ItemCollection, SelfHref, ToNdjson, Value};
3use std::{
4 fs::File,
5 io::{BufRead, BufReader, BufWriter},
6 path::Path,
7};
8
9pub trait FromNdjsonPath: FromNdjson + FromJsonPath + SelfHref {
11 fn from_ndjson_path(path: impl AsRef<Path>) -> Result<Self> {
22 Self::from_json_path(path)
23 }
24}
25
26pub trait ToNdjsonPath: ToNdjson {
28 fn to_ndjson_path(&self, path: impl AsRef<Path>) -> Result<()> {
40 let file = File::create(path)?;
41 self.to_ndjson_writer(file)?;
42 Ok(())
43 }
44}
45
46impl FromNdjsonPath for Item {}
47impl FromNdjsonPath for Catalog {}
48impl FromNdjsonPath for Collection {}
49impl FromNdjsonPath for ItemCollection {
50 fn from_ndjson_path(path: impl AsRef<Path>) -> Result<Self> {
51 let path = path.as_ref();
52 let reader = BufReader::new(File::open(path)?);
53 let mut items = Vec::new();
54 for line in reader.lines() {
55 items.push(serde_json::from_str(&line?)?);
56 }
57 let mut item_collection = ItemCollection::from(items);
58 item_collection.set_self_href(path.to_string_lossy());
59 Ok(item_collection)
60 }
61}
62impl FromNdjsonPath for Value {
63 fn from_ndjson_path(path: impl AsRef<Path>) -> Result<Self> {
64 let path = path.as_ref();
65 let reader = BufReader::new(File::open(path)?);
66 let mut values: Vec<Value> = Vec::new();
67 for line in reader.lines() {
68 values.push(serde_json::from_str(&line?)?);
69 }
70 vec_into_value(values)
71 }
72}
73
74fn vec_into_value(mut values: Vec<Value>) -> Result<Value> {
75 if values.len() == 1 {
76 Ok(values.pop().unwrap())
77 } else {
78 Ok(ItemCollection::from(
79 values
80 .into_iter()
81 .map(|v| Item::try_from(v).map_err(Error::from))
82 .collect::<Result<Vec<_>>>()?,
83 )
84 .into())
85 }
86}
87
88impl ToNdjsonPath for Item {}
89impl ToNdjsonPath for Catalog {}
90impl ToNdjsonPath for Collection {}
91
92impl ToNdjsonPath for ItemCollection {
93 fn to_ndjson_path(&self, path: impl AsRef<Path>) -> Result<()> {
94 let file = BufWriter::new(File::create(path)?);
95 self.to_ndjson_writer(file)?;
96 Ok(())
97 }
98}
99
100impl ToNdjsonPath for Value {
101 fn to_ndjson_path(&self, path: impl AsRef<Path>) -> Result<()> {
102 match self {
103 Value::Item(item) => item.to_ndjson_path(path),
104 Value::Catalog(catalog) => catalog.to_ndjson_path(path),
105 Value::Collection(collection) => collection.to_ndjson_path(path),
106 Value::ItemCollection(item_collection) => item_collection.to_ndjson_path(path),
107 }
108 }
109}
110
111impl ToNdjsonPath for serde_json::Value {
112 fn to_ndjson_path(&self, path: impl AsRef<Path>) -> Result<()> {
113 let file = File::create(path)?;
114 self.to_ndjson_writer(file)?;
115 Ok(())
116 }
117}
118
119#[cfg(test)]
120mod tests {
121 use super::FromNdjsonPath;
122 use stac::{ItemCollection, SelfHref, Value};
123
124 #[test]
125 fn item_collection_read() {
126 let item_collection = ItemCollection::from_ndjson_path("data/items.ndjson").unwrap();
127 assert_eq!(item_collection.items.len(), 2);
128 assert!(
129 item_collection
130 .self_href()
131 .unwrap()
132 .ends_with("data/items.ndjson")
133 );
134 }
135
136 #[test]
137 fn value_read() {
138 let _ = Value::from_ndjson_path("data/items.ndjson").unwrap();
139 }
140}