1use crate::api::{err::Error, Result};
2use crate::sql::{self, Array, Edges, Id, Object, Table, Thing, Value};
3use crate::syn;
4use std::ops::{self, Bound};
5
6#[derive(Debug)]
8pub enum Resource {
9 Table(Table),
11 RecordId(Thing),
13 Object(Object),
15 Array(Array),
17 Edges(Edges),
19}
20
21impl Resource {
22 pub(crate) fn with_range(self, range: Range<Id>) -> Result<sql::Range> {
23 match self {
24 Resource::Table(Table(table)) => Ok(sql::Range {
25 tb: table,
26 beg: range.start,
27 end: range.end,
28 }),
29 Resource::RecordId(record_id) => Err(Error::RangeOnRecordId(record_id).into()),
30 Resource::Object(object) => Err(Error::RangeOnObject(object).into()),
31 Resource::Array(array) => Err(Error::RangeOnArray(array).into()),
32 Resource::Edges(edges) => Err(Error::RangeOnEdges(edges).into()),
33 }
34 }
35}
36
37impl From<Table> for Resource {
38 fn from(table: Table) -> Self {
39 Self::Table(table)
40 }
41}
42
43impl From<&Table> for Resource {
44 fn from(table: &Table) -> Self {
45 Self::Table(table.clone())
46 }
47}
48
49impl From<Thing> for Resource {
50 fn from(thing: Thing) -> Self {
51 Self::RecordId(thing)
52 }
53}
54
55impl From<&Thing> for Resource {
56 fn from(thing: &Thing) -> Self {
57 Self::RecordId(thing.clone())
58 }
59}
60
61impl From<Object> for Resource {
62 fn from(object: Object) -> Self {
63 Self::Object(object)
64 }
65}
66
67impl From<&Object> for Resource {
68 fn from(object: &Object) -> Self {
69 Self::Object(object.clone())
70 }
71}
72
73impl From<Array> for Resource {
74 fn from(array: Array) -> Self {
75 Self::Array(array)
76 }
77}
78
79impl From<&Array> for Resource {
80 fn from(array: &Array) -> Self {
81 Self::Array(array.clone())
82 }
83}
84
85impl From<Edges> for Resource {
86 fn from(edges: Edges) -> Self {
87 Self::Edges(edges)
88 }
89}
90
91impl From<&Edges> for Resource {
92 fn from(edges: &Edges) -> Self {
93 Self::Edges(edges.clone())
94 }
95}
96
97impl From<&str> for Resource {
98 fn from(s: &str) -> Self {
99 match syn::thing(s) {
100 Ok(thing) => Self::RecordId(thing),
101 Err(_) => Self::Table(s.into()),
102 }
103 }
104}
105
106impl From<&String> for Resource {
107 fn from(s: &String) -> Self {
108 Self::from(s.as_str())
109 }
110}
111
112impl From<String> for Resource {
113 fn from(s: String) -> Self {
114 match syn::thing(s.as_str()) {
115 Ok(thing) => Self::RecordId(thing),
116 Err(_) => Self::Table(s.into()),
117 }
118 }
119}
120
121impl<T, I> From<(T, I)> for Resource
122where
123 T: Into<String>,
124 I: Into<Id>,
125{
126 fn from((table, id): (T, I)) -> Self {
127 let record_id = (table.into(), id.into());
128 Self::RecordId(record_id.into())
129 }
130}
131
132impl From<Resource> for Value {
133 fn from(resource: Resource) -> Self {
134 match resource {
135 Resource::Table(resource) => resource.into(),
136 Resource::RecordId(resource) => resource.into(),
137 Resource::Object(resource) => resource.into(),
138 Resource::Array(resource) => resource.into(),
139 Resource::Edges(resource) => resource.into(),
140 }
141 }
142}
143
144pub trait IntoResource<Response>: Sized {
146 fn into_resource(self) -> Result<Resource>;
148}
149
150impl IntoResource<Value> for Resource {
151 fn into_resource(self) -> Result<Resource> {
152 Ok(self)
153 }
154}
155
156impl<R> IntoResource<Option<R>> for Object {
157 fn into_resource(self) -> Result<Resource> {
158 Ok(Resource::Object(self))
159 }
160}
161
162impl<R> IntoResource<Option<R>> for Thing {
163 fn into_resource(self) -> Result<Resource> {
164 Ok(Resource::RecordId(self))
165 }
166}
167
168impl<R> IntoResource<Option<R>> for &Thing {
169 fn into_resource(self) -> Result<Resource> {
170 Ok(Resource::RecordId(self.clone()))
171 }
172}
173
174impl<R, T, I> IntoResource<Option<R>> for (T, I)
175where
176 T: Into<String>,
177 I: Into<Id>,
178{
179 fn into_resource(self) -> Result<Resource> {
180 let (table, id) = self;
181 let record_id = (table.into(), id.into());
182 Ok(Resource::RecordId(record_id.into()))
183 }
184}
185
186impl<R> IntoResource<Vec<R>> for Array {
187 fn into_resource(self) -> Result<Resource> {
188 Ok(Resource::Array(self))
189 }
190}
191
192impl<R> IntoResource<Vec<R>> for Edges {
193 fn into_resource(self) -> Result<Resource> {
194 Ok(Resource::Edges(self))
195 }
196}
197
198impl<R> IntoResource<Vec<R>> for Table {
199 fn into_resource(self) -> Result<Resource> {
200 Ok(Resource::Table(self))
201 }
202}
203
204fn blacklist_colon(input: &str) -> Result<()> {
205 match input.contains(':') {
206 true => {
207 let (table, id) = input.split_once(':').unwrap();
209 Err(Error::TableColonId {
210 table: table.to_owned(),
211 id: id.to_owned(),
212 }
213 .into())
214 }
215 false => Ok(()),
216 }
217}
218
219impl<R> IntoResource<Vec<R>> for &str {
220 fn into_resource(self) -> Result<Resource> {
221 blacklist_colon(self)?;
222 Ok(Resource::Table(Table(self.to_owned())))
223 }
224}
225
226impl<R> IntoResource<Vec<R>> for &String {
227 fn into_resource(self) -> Result<Resource> {
228 blacklist_colon(self)?;
229 Ok(Resource::Table(Table(self.to_owned())))
230 }
231}
232
233impl<R> IntoResource<Vec<R>> for String {
234 fn into_resource(self) -> Result<Resource> {
235 blacklist_colon(&self)?;
236 Ok(Resource::Table(Table(self)))
237 }
238}
239
240#[derive(Debug)]
242pub struct Range<T> {
243 pub(crate) start: Bound<T>,
244 pub(crate) end: Bound<T>,
245}
246
247impl<T> From<(Bound<T>, Bound<T>)> for Range<Id>
248where
249 T: Into<Id>,
250{
251 fn from((start, end): (Bound<T>, Bound<T>)) -> Self {
252 Self {
253 start: match start {
254 Bound::Included(idx) => Bound::Included(idx.into()),
255 Bound::Excluded(idx) => Bound::Excluded(idx.into()),
256 Bound::Unbounded => Bound::Unbounded,
257 },
258 end: match end {
259 Bound::Included(idx) => Bound::Included(idx.into()),
260 Bound::Excluded(idx) => Bound::Excluded(idx.into()),
261 Bound::Unbounded => Bound::Unbounded,
262 },
263 }
264 }
265}
266
267impl<T> From<ops::Range<T>> for Range<Id>
268where
269 T: Into<Id>,
270{
271 fn from(
272 ops::Range {
273 start,
274 end,
275 }: ops::Range<T>,
276 ) -> Self {
277 Self {
278 start: Bound::Included(start.into()),
279 end: Bound::Excluded(end.into()),
280 }
281 }
282}
283
284impl<T> From<ops::RangeInclusive<T>> for Range<Id>
285where
286 T: Into<Id>,
287{
288 fn from(range: ops::RangeInclusive<T>) -> Self {
289 let (start, end) = range.into_inner();
290 Self {
291 start: Bound::Included(start.into()),
292 end: Bound::Included(end.into()),
293 }
294 }
295}
296
297impl<T> From<ops::RangeFrom<T>> for Range<Id>
298where
299 T: Into<Id>,
300{
301 fn from(
302 ops::RangeFrom {
303 start,
304 }: ops::RangeFrom<T>,
305 ) -> Self {
306 Self {
307 start: Bound::Included(start.into()),
308 end: Bound::Unbounded,
309 }
310 }
311}
312
313impl<T> From<ops::RangeTo<T>> for Range<Id>
314where
315 T: Into<Id>,
316{
317 fn from(
318 ops::RangeTo {
319 end,
320 }: ops::RangeTo<T>,
321 ) -> Self {
322 Self {
323 start: Bound::Unbounded,
324 end: Bound::Excluded(end.into()),
325 }
326 }
327}
328
329impl<T> From<ops::RangeToInclusive<T>> for Range<Id>
330where
331 T: Into<Id>,
332{
333 fn from(
334 ops::RangeToInclusive {
335 end,
336 }: ops::RangeToInclusive<T>,
337 ) -> Self {
338 Self {
339 start: Bound::Unbounded,
340 end: Bound::Included(end.into()),
341 }
342 }
343}
344
345impl From<ops::RangeFull> for Range<Id> {
346 fn from(_: ops::RangeFull) -> Self {
347 Self {
348 start: Bound::Unbounded,
349 end: Bound::Unbounded,
350 }
351 }
352}