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
111pub fn ndjson_item_reader(reader: impl BufRead) -> impl Iterator<Item = Result<Item>> {
124 reader.lines().filter_map(|line| match line {
125 Ok(line) if line.is_empty() => None,
126 Ok(line) => Some(serde_json::from_str(&line).map_err(Error::from)),
127 Err(err) => Some(Err(Error::from(err))),
128 })
129}
130
131impl ToNdjsonPath for serde_json::Value {
132 fn to_ndjson_path(&self, path: impl AsRef<Path>) -> Result<()> {
133 let file = File::create(path)?;
134 self.to_ndjson_writer(file)?;
135 Ok(())
136 }
137}
138
139#[cfg(test)]
140mod tests {
141 use super::FromNdjsonPath;
142 use stac::{ItemCollection, SelfHref, Value};
143
144 #[test]
145 fn item_collection_read() {
146 let item_collection = ItemCollection::from_ndjson_path("data/items.ndjson").unwrap();
147 assert_eq!(item_collection.items.len(), 2);
148 assert!(
149 item_collection
150 .self_href()
151 .unwrap()
152 .ends_with("data/items.ndjson")
153 );
154 }
155
156 #[test]
157 fn value_read() {
158 let _ = Value::from_ndjson_path("data/items.ndjson").unwrap();
159 }
160}