surrealdb_core/sql/value/
into_json.rs

1use crate::sql;
2use crate::sql::constant::ConstantValue;
3use crate::sql::Number;
4use crate::sql::Value;
5use serde::Serialize;
6use serde_json::json;
7use serde_json::Map;
8use serde_json::Value as JsonValue;
9
10impl From<Value> for serde_json::Value {
11	fn from(value: Value) -> Self {
12		match value {
13			// These value types are simple values which
14			// can be used in query responses sent to
15			// the client.
16			Value::None | Value::Null => JsonValue::Null,
17			Value::Bool(boolean) => boolean.into(),
18			Value::Number(number) => match number {
19				Number::Int(int) => int.into(),
20				Number::Float(float) => float.into(),
21				Number::Decimal(decimal) => json!(decimal),
22			},
23			Value::Strand(strand) => strand.0.into(),
24			Value::Duration(duration) => duration.to_raw().into(),
25			Value::Datetime(datetime) => json!(datetime.0),
26			Value::Uuid(uuid) => json!(uuid.0),
27			Value::Array(array) => JsonValue::Array(Array::from(array).0),
28			Value::Object(object) => JsonValue::Object(Object::from(object).0),
29			Value::Geometry(geo) => Geometry::from(geo).0,
30			Value::Bytes(bytes) => json!(bytes.0),
31			Value::Thing(thing) => thing.to_string().into(),
32			// These Value types are un-computed values
33			// and are not used in query responses sent
34			// to the client.
35			Value::Param(param) => json!(param),
36			Value::Idiom(idiom) => json!(idiom),
37			Value::Table(table) => json!(table),
38			Value::Mock(mock) => json!(mock),
39			Value::Regex(regex) => json!(regex),
40			Value::Block(block) => json!(block),
41			Value::Range(range) => json!(range),
42			Value::Edges(edges) => json!(edges),
43			Value::Future(future) => json!(future),
44			Value::Constant(constant) => match constant.value() {
45				ConstantValue::Datetime(datetime) => json!(datetime.0),
46				ConstantValue::Float(float) => float.into(),
47				ConstantValue::Duration(duration) => duration.to_string().into(),
48			},
49			Value::Cast(cast) => json!(cast),
50			Value::Function(function) => json!(function),
51			Value::Model(model) => json!(model),
52			Value::Query(query) => json!(query),
53			Value::Subquery(subquery) => json!(subquery),
54			Value::Expression(expression) => json!(expression),
55			Value::Closure(closure) => json!(closure),
56			Value::Refs(_) => json!(sql::Array::new()),
57		}
58	}
59}
60
61#[derive(Serialize)]
62struct Array(Vec<JsonValue>);
63
64impl From<sql::Array> for Array {
65	fn from(arr: sql::Array) -> Self {
66		let mut vec = Vec::with_capacity(arr.len());
67		for value in arr {
68			vec.push(value.into());
69		}
70		Self(vec)
71	}
72}
73
74#[derive(Serialize)]
75struct Object(Map<String, JsonValue>);
76
77impl From<sql::Object> for Object {
78	fn from(obj: sql::Object) -> Self {
79		let mut map = Map::with_capacity(obj.len());
80		for (key, value) in obj {
81			map.insert(key.to_owned(), value.into());
82		}
83		Self(map)
84	}
85}
86
87#[derive(Serialize)]
88enum CoordinatesType {
89	Point,
90	LineString,
91	Polygon,
92	MultiPoint,
93	MultiLineString,
94	MultiPolygon,
95}
96
97#[derive(Serialize)]
98struct Coordinates {
99	#[serde(rename = "type")]
100	typ: CoordinatesType,
101	coordinates: JsonValue,
102}
103
104struct GeometryCollection;
105
106impl Serialize for GeometryCollection {
107	fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
108	where
109		S: serde::Serializer,
110	{
111		s.serialize_str("GeometryCollection")
112	}
113}
114
115#[derive(Serialize)]
116struct Geometries {
117	#[serde(rename = "type")]
118	typ: GeometryCollection,
119	geometries: Vec<JsonValue>,
120}
121
122#[derive(Serialize)]
123struct Geometry(JsonValue);
124
125impl From<sql::Geometry> for Geometry {
126	fn from(geo: sql::Geometry) -> Self {
127		Self(match geo {
128			sql::Geometry::Point(v) => json!(Coordinates {
129				typ: CoordinatesType::Point,
130				coordinates: vec![json!(v.x()), json!(v.y())].into(),
131			}),
132			sql::Geometry::Line(v) => json!(Coordinates {
133				typ: CoordinatesType::LineString,
134				coordinates: v
135					.points()
136					.map(|p| vec![json!(p.x()), json!(p.y())].into())
137					.collect::<Vec<JsonValue>>()
138					.into(),
139			}),
140			sql::Geometry::Polygon(v) => json!(Coordinates {
141				typ: CoordinatesType::Polygon,
142				coordinates: vec![v
143					.exterior()
144					.points()
145					.map(|p| vec![json!(p.x()), json!(p.y())].into())
146					.collect::<Vec<JsonValue>>()]
147				.into_iter()
148				.chain(
149					v.interiors()
150						.iter()
151						.map(|i| {
152							i.points()
153								.map(|p| vec![json!(p.x()), json!(p.y())].into())
154								.collect::<Vec<JsonValue>>()
155						})
156						.collect::<Vec<Vec<JsonValue>>>(),
157				)
158				.collect::<Vec<Vec<JsonValue>>>()
159				.into(),
160			}),
161			sql::Geometry::MultiPoint(v) => json!(Coordinates {
162				typ: CoordinatesType::MultiPoint,
163				coordinates: v
164					.0
165					.iter()
166					.map(|v| vec![json!(v.x()), json!(v.y())].into())
167					.collect::<Vec<JsonValue>>()
168					.into()
169			}),
170			sql::Geometry::MultiLine(v) => json!(Coordinates {
171				typ: CoordinatesType::MultiLineString,
172				coordinates: v
173					.0
174					.iter()
175					.map(|v| {
176						v.points()
177							.map(|v| vec![json!(v.x()), json!(v.y())].into())
178							.collect::<Vec<JsonValue>>()
179					})
180					.collect::<Vec<Vec<JsonValue>>>()
181					.into()
182			}),
183			sql::Geometry::MultiPolygon(v) => json!(Coordinates {
184				typ: CoordinatesType::MultiPolygon,
185				coordinates: v
186					.0
187					.iter()
188					.map(|v| {
189						vec![v
190							.exterior()
191							.points()
192							.map(|p| vec![json!(p.x()), json!(p.y())].into())
193							.collect::<Vec<JsonValue>>()]
194						.into_iter()
195						.chain(
196							v.interiors()
197								.iter()
198								.map(|i| {
199									i.points()
200										.map(|p| vec![json!(p.x()), json!(p.y())].into())
201										.collect::<Vec<JsonValue>>()
202								})
203								.collect::<Vec<Vec<JsonValue>>>(),
204						)
205						.collect::<Vec<Vec<JsonValue>>>()
206					})
207					.collect::<Vec<Vec<Vec<JsonValue>>>>()
208					.into(),
209			}),
210			sql::Geometry::Collection(v) => json!(Geometries {
211				typ: GeometryCollection,
212				geometries: v.into_iter().map(Geometry::from).map(|x| x.0).collect(),
213			}),
214		})
215	}
216}
217
218#[cfg(test)]
219mod tests {
220	mod into_json {
221		use crate::sql;
222		use crate::sql::from_value;
223		use crate::sql::Value;
224		use chrono::DateTime;
225		use chrono::Utc;
226		use geo::line_string;
227		use geo::point;
228		use geo::polygon;
229		use geo::LineString;
230		use geo::MultiLineString;
231		use geo::MultiPoint;
232		use geo::MultiPolygon;
233		use geo::Point;
234		use geo::Polygon;
235		use rust_decimal::Decimal;
236		use serde_json::json;
237		use serde_json::Value as Json;
238		use std::collections::BTreeMap;
239		use std::time::Duration;
240		use uuid::Uuid;
241
242		#[test]
243		fn none_or_null() {
244			for value in [Value::None, Value::Null] {
245				let simple_json = Json::from(value.clone());
246				assert_eq!(simple_json, json!(null));
247
248				let response: Option<String> = from_value(value).unwrap();
249				assert_eq!(response, None);
250			}
251		}
252
253		#[test]
254		fn bool() {
255			for boolean in [true, false] {
256				let value = Value::Bool(boolean);
257
258				let simple_json = Json::from(value.clone());
259				assert_eq!(simple_json, json!(boolean));
260
261				let response: bool = from_value(value).unwrap();
262				assert_eq!(response, boolean);
263			}
264		}
265
266		#[test]
267		fn number_int() {
268			for num in [i64::MIN, 0, i64::MAX] {
269				let value = Value::Number(sql::Number::Int(num));
270
271				let simple_json = Json::from(value.clone());
272				assert_eq!(simple_json, json!(num));
273
274				let response: i64 = from_value(value).unwrap();
275				assert_eq!(response, num);
276			}
277		}
278
279		#[test]
280		fn number_float() {
281			for num in [f64::NEG_INFINITY, f64::MIN, 0.0, f64::MAX, f64::INFINITY, f64::NAN] {
282				let value = Value::Number(sql::Number::Float(num));
283
284				let simple_json = Json::from(value.clone());
285				assert_eq!(simple_json, json!(num));
286
287				let response: f64 = from_value(value).unwrap();
288				if response.is_finite() {
289					// Infinity numbers are not comparable
290					assert_eq!(response, num);
291				}
292			}
293		}
294
295		#[test]
296		fn number_decimal() {
297			for num in [i64::MIN, 0, i64::MAX] {
298				let num = Decimal::new(num, 0);
299				let value = Value::Number(sql::Number::Decimal(num));
300
301				let simple_json = Json::from(value.clone());
302				assert_eq!(simple_json, json!(num.to_string()));
303
304				let response: Decimal = from_value(value).unwrap();
305				assert_eq!(response, num);
306			}
307		}
308
309		#[test]
310		fn strand() {
311			for str in ["", "foo"] {
312				let value = Value::Strand(str.into());
313
314				let simple_json = Json::from(value.clone());
315				assert_eq!(simple_json, json!(str));
316
317				let response: String = from_value(value).unwrap();
318				assert_eq!(response, str);
319			}
320		}
321
322		#[test]
323		fn duration() {
324			for duration in [Duration::ZERO, Duration::MAX] {
325				let value = Value::Duration(duration.into());
326
327				let simple_json = Json::from(value.clone());
328				assert_eq!(simple_json, json!(sql::Duration(duration).to_raw()));
329
330				let response: Duration = from_value(value).unwrap();
331				assert_eq!(response, duration);
332			}
333		}
334
335		#[test]
336		fn datetime() {
337			for datetime in [DateTime::<Utc>::MIN_UTC, DateTime::<Utc>::MAX_UTC] {
338				let value = Value::Datetime(datetime.into());
339
340				let simple_json = Json::from(value.clone());
341				assert_eq!(simple_json, json!(datetime));
342
343				let response: DateTime<Utc> = from_value(value).unwrap();
344				assert_eq!(response, datetime);
345			}
346		}
347
348		#[test]
349		fn uuid() {
350			for uuid in [Uuid::nil(), Uuid::max()] {
351				let value = Value::Uuid(uuid.into());
352
353				let simple_json = Json::from(value.clone());
354				assert_eq!(simple_json, json!(uuid));
355
356				let response: Uuid = from_value(value).unwrap();
357				assert_eq!(response, uuid);
358			}
359		}
360
361		#[test]
362		fn array() {
363			for vec in [vec![], vec![true, false]] {
364				let value =
365					Value::Array(sql::Array(vec.iter().copied().map(Value::from).collect()));
366
367				let simple_json = Json::from(value.clone());
368				assert_eq!(simple_json, json!(vec));
369
370				let response: Vec<bool> = from_value(value).unwrap();
371				assert_eq!(response, vec);
372			}
373		}
374
375		#[test]
376		fn object() {
377			for map in [BTreeMap::new(), map!("done".to_owned() => true)] {
378				let value = Value::Object(sql::Object(
379					map.iter().map(|(key, value)| (key.clone(), Value::from(*value))).collect(),
380				));
381
382				let simple_json = Json::from(value.clone());
383				assert_eq!(simple_json, json!(map));
384
385				let response: BTreeMap<String, bool> = from_value(value).unwrap();
386				assert_eq!(response, map);
387			}
388		}
389
390		#[test]
391		fn geometry_point() {
392			let point = point! { x: 10., y: 20. };
393			let value = Value::Geometry(sql::Geometry::Point(point));
394
395			let simple_json = Json::from(value.clone());
396			assert_eq!(simple_json, json!({ "type": "Point", "coordinates": [10., 20.]}));
397
398			let response: Point = from_value(value).unwrap();
399			assert_eq!(response, point);
400		}
401
402		#[test]
403		fn geometry_line() {
404			let line_string = line_string![
405				( x: 0., y: 0. ),
406				( x: 10., y: 0. ),
407			];
408			let value = Value::Geometry(sql::Geometry::Line(line_string.clone()));
409
410			let simple_json = Json::from(value.clone());
411			assert_eq!(
412				simple_json,
413				json!({ "type": "LineString", "coordinates": [[0., 0.], [10., 0.]]})
414			);
415
416			let response: LineString = from_value(value).unwrap();
417			assert_eq!(response, line_string);
418		}
419
420		#[test]
421		fn geometry_polygon() {
422			let polygon = polygon![
423				(x: -111., y: 45.),
424				(x: -111., y: 41.),
425				(x: -104., y: 41.),
426				(x: -104., y: 45.),
427			];
428			let value = Value::Geometry(sql::Geometry::Polygon(polygon.clone()));
429
430			let simple_json = Json::from(value.clone());
431			assert_eq!(
432				simple_json,
433				json!({ "type": "Polygon", "coordinates": [[
434					[-111., 45.],
435					[-111., 41.],
436					[-104., 41.],
437					[-104., 45.],
438					[-111., 45.],
439				]]})
440			);
441
442			let response: Polygon = from_value(value).unwrap();
443			assert_eq!(response, polygon);
444		}
445
446		#[test]
447		fn geometry_multi_point() {
448			let multi_point: MultiPoint =
449				vec![point! { x: 0., y: 0. }, point! { x: 1., y: 2. }].into();
450			let value = Value::Geometry(sql::Geometry::MultiPoint(multi_point.clone()));
451
452			let simple_json = Json::from(value.clone());
453			assert_eq!(
454				simple_json,
455				json!({ "type": "MultiPoint", "coordinates": [[0., 0.], [1., 2.]]})
456			);
457
458			let response: MultiPoint = from_value(value).unwrap();
459			assert_eq!(response, multi_point);
460		}
461
462		#[test]
463		fn geometry_multi_line() {
464			let multi_line = MultiLineString::new(vec![line_string![
465					( x: 0., y: 0. ),
466					( x: 1., y: 2. ),
467			]]);
468			let value = Value::Geometry(sql::Geometry::MultiLine(multi_line.clone()));
469
470			let simple_json = Json::from(value.clone());
471			assert_eq!(
472				simple_json,
473				json!({ "type": "MultiLineString", "coordinates": [[[0., 0.], [1., 2.]]]})
474			);
475
476			let response: MultiLineString = from_value(value).unwrap();
477			assert_eq!(response, multi_line);
478		}
479
480		#[test]
481		fn geometry_multi_polygon() {
482			let multi_polygon: MultiPolygon = vec![polygon![
483				(x: -111., y: 45.),
484				(x: -111., y: 41.),
485				(x: -104., y: 41.),
486				(x: -104., y: 45.),
487			]]
488			.into();
489			let value = Value::Geometry(sql::Geometry::MultiPolygon(multi_polygon.clone()));
490
491			let simple_json = Json::from(value.clone());
492			assert_eq!(
493				simple_json,
494				json!({ "type": "MultiPolygon", "coordinates": [[[
495					[-111., 45.],
496					[-111., 41.],
497					[-104., 41.],
498					[-104., 45.],
499					[-111., 45.],
500				]]]})
501			);
502
503			let response: MultiPolygon = from_value(value).unwrap();
504			assert_eq!(response, multi_polygon);
505		}
506
507		#[test]
508		fn geometry_collection() {
509			for geometries in [vec![], vec![sql::Geometry::Point(point! { x: 10., y: 20. })]] {
510				let value = Value::Geometry(geometries.clone().into());
511
512				let simple_json = Json::from(value.clone());
513				assert_eq!(
514					simple_json,
515					json!({
516						"type": "GeometryCollection",
517						"geometries": geometries.clone().into_iter().map(|geo| Json::from(Value::from(geo))).collect::<Vec<_>>(),
518					})
519				);
520
521				let response: Vec<sql::Geometry> = from_value(value).unwrap();
522				assert_eq!(response, geometries);
523			}
524		}
525
526		#[test]
527		fn bytes() {
528			for bytes in [vec![], b"foo".to_vec()] {
529				let value = Value::Bytes(sql::Bytes(bytes.clone()));
530
531				let simple_json = Json::from(value.clone());
532				assert_eq!(simple_json, json!(bytes));
533
534				let sql::Bytes(response) = from_value(value).unwrap();
535				assert_eq!(response, bytes);
536			}
537		}
538
539		#[test]
540		fn thing() {
541			let record_id = "foo:bar";
542			let thing = sql::thing(record_id).unwrap();
543			let value = Value::Thing(thing.clone());
544
545			let simple_json = Json::from(value.clone());
546			assert_eq!(simple_json, json!(record_id));
547
548			let response: sql::Thing = from_value(value).unwrap();
549			assert_eq!(response, thing);
550		}
551	}
552}