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