surrealdb_core/fnc/script/
into.rs1use super::classes;
2use crate::sql::geometry::Geometry;
3use crate::sql::number::Number;
4use crate::sql::value::Value;
5use js::Array;
6use js::BigInt;
7use js::Class;
8use js::Ctx;
9use js::Error;
10use js::Exception;
11use js::FromIteratorJs as _;
12use js::IntoJs;
13use js::Null;
14use js::Object;
15use js::TypedArray;
16use js::Undefined;
17use rust_decimal::prelude::ToPrimitive;
18
19const F64_INT_MAX: i64 = ((1u64 << f64::MANTISSA_DIGITS) - 1) as i64;
20const F64_INT_MIN: i64 = -F64_INT_MAX - 1;
21
22impl<'js> IntoJs<'js> for Value {
23 fn into_js(self, ctx: &Ctx<'js>) -> Result<js::Value<'js>, Error> {
24 (&self).into_js(ctx)
25 }
26}
27
28impl<'js> IntoJs<'js> for &Value {
29 fn into_js(self, ctx: &Ctx<'js>) -> Result<js::Value<'js>, Error> {
30 match *self {
31 Value::Null => Null.into_js(ctx),
32 Value::None => Undefined.into_js(ctx),
33 Value::Bool(boolean) => Ok(js::Value::new_bool(ctx.clone(), boolean)),
34 Value::Strand(ref v) => js::String::from_str(ctx.clone(), v)?.into_js(ctx),
35 Value::Number(Number::Int(v)) => {
36 if ((i32::MIN as i64)..=(i32::MAX as i64)).contains(&v) {
37 Ok(js::Value::new_int(ctx.clone(), v as i32))
38 } else if (F64_INT_MIN..=F64_INT_MAX).contains(&v) {
39 Ok(js::Value::new_float(ctx.clone(), v as f64))
40 } else {
41 Ok(js::Value::from(BigInt::from_i64(ctx.clone(), v)?))
42 }
43 }
44 Value::Number(Number::Float(v)) => Ok(js::Value::new_float(ctx.clone(), v)),
45 Value::Number(Number::Decimal(v)) => {
46 if v.is_integer() {
47 if let Some(v) = v.to_i64() {
48 if ((i32::MIN as i64)..=(i32::MAX as i64)).contains(&v) {
49 Ok(js::Value::new_int(ctx.clone(), v as i32))
50 } else if (F64_INT_MIN..=F64_INT_MAX).contains(&v) {
51 Ok(js::Value::new_float(ctx.clone(), v as f64))
52 } else {
53 Ok(js::Value::from(BigInt::from_i64(ctx.clone(), v)?))
54 }
55 } else {
56 Err(Exception::from_message(
57 ctx.clone(),
58 "Couldn't convert SurrealQL Decimal to JavaScript number",
59 )?
60 .throw())
61 }
62 } else if let Ok(v) = v.try_into() {
63 Ok(js::Value::new_float(ctx.clone(), v))
64 } else {
65 Err(Exception::from_message(
67 ctx.clone(),
68 "Couldn't convert SurrealQL Decimal to a JavaScript number",
69 )?
70 .throw())
71 }
72 }
73 Value::Datetime(ref v) => {
74 let date: js::function::Constructor = ctx.globals().get("Date")?;
75 date.construct((v.0.timestamp_millis(),))
76 }
77 Value::Thing(ref v) => Ok(Class::<classes::record::Record>::instance(
78 ctx.clone(),
79 classes::record::Record {
80 value: v.to_owned(),
81 },
82 )?
83 .into_value()),
84 Value::Duration(ref v) => Ok(Class::<classes::duration::Duration>::instance(
85 ctx.clone(),
86 classes::duration::Duration {
87 value: Some(v.to_owned()),
88 },
89 )?
90 .into_value()),
91 Value::Uuid(ref v) => Ok(Class::<classes::uuid::Uuid>::instance(
92 ctx.clone(),
93 classes::uuid::Uuid {
94 value: Some(v.to_owned()),
95 },
96 )?
97 .into_value()),
98 Value::Array(ref v) => {
99 let x = Array::new(ctx.clone())?;
100 for (i, v) in v.iter().enumerate() {
101 x.set(i, v)?;
102 }
103 x.into_js(ctx)
104 }
105 Value::Object(ref v) => {
106 let x = Object::new(ctx.clone())?;
107 for (k, v) in v.iter() {
108 x.set(k, v)?;
109 }
110 x.into_js(ctx)
111 }
112 Value::Bytes(ref v) => TypedArray::new_copy(ctx.clone(), v.0.as_slice())?.into_js(ctx),
113 Value::Geometry(ref v) => v.into_js(ctx),
114 _ => Undefined.into_js(ctx),
115 }
116 }
117}
118
119impl<'js> IntoJs<'js> for &Geometry {
120 fn into_js(self, ctx: &Ctx<'js>) -> js::Result<js::Value<'js>> {
121 let (ty, coords) = match self {
122 Geometry::Point(x) => {
123 ("Point".into_js(ctx)?, Array::from_iter_js(ctx, [x.0.x, x.0.y])?)
124 }
125 Geometry::Line(x) => {
126 let array = Array::new(ctx.clone())?;
127 for (idx, c) in x.0.iter().enumerate() {
128 let coord = Array::from_iter_js(ctx, [c.x, c.y])?;
129 array.set(idx, coord)?;
130 }
131 ("LineString".into_js(ctx)?, array)
132 }
133 Geometry::Polygon(x) => {
134 let coords = Array::new(ctx.clone())?;
135
136 let string = Array::new(ctx.clone())?;
137 for (idx, c) in x.exterior().0.iter().enumerate() {
138 let coord = Array::from_iter_js(ctx, [c.x, c.y])?;
139 string.set(idx, coord)?;
140 }
141
142 coords.set(0, string)?;
143
144 for (idx, int) in x.interiors().iter().enumerate() {
145 let string = Array::new(ctx.clone())?;
146 for (idx, c) in int.0.iter().enumerate() {
147 let coord = Array::from_iter_js(ctx, [c.x, c.y])?;
148 string.set(idx, coord)?;
149 }
150 coords.set(idx + 1, string)?;
151 }
152
153 ("Polygon".into_js(ctx)?, coords)
154 }
155 Geometry::MultiPoint(x) => {
156 let array = Array::new(ctx.clone())?;
157 for (idx, c) in x.0.iter().enumerate() {
158 let coord = Array::from_iter_js(ctx, [c.x(), c.y()])?;
159 array.set(idx, coord)?;
160 }
161 ("MultiPoint".into_js(ctx)?, array)
162 }
163 Geometry::MultiLine(x) => {
164 let lines = Array::new(ctx.clone())?;
165 for (idx, l) in x.0.iter().enumerate() {
166 let array = Array::new(ctx.clone())?;
167 for (idx, c) in l.0.iter().enumerate() {
168 let coord = Array::from_iter_js(ctx, [c.x, c.y])?;
169 array.set(idx, coord)?;
170 }
171 lines.set(idx, array)?
172 }
173 ("MultiLineString".into_js(ctx)?, lines)
174 }
175 Geometry::MultiPolygon(x) => {
176 let polygons = Array::new(ctx.clone())?;
177
178 for (idx, p) in x.0.iter().enumerate() {
179 let coords = Array::new(ctx.clone())?;
180
181 let string = Array::new(ctx.clone())?;
182 for (idx, c) in p.exterior().0.iter().enumerate() {
183 let coord = Array::from_iter_js(ctx, [c.x, c.y])?;
184 string.set(idx, coord)?;
185 }
186
187 coords.set(0, string)?;
188
189 for (idx, int) in p.interiors().iter().enumerate() {
190 let string = Array::new(ctx.clone())?;
191 for (idx, c) in int.0.iter().enumerate() {
192 let coord = Array::from_iter_js(ctx, [c.x, c.y])?;
193 string.set(idx, coord)?;
194 }
195 coords.set(idx + 1, string)?;
196 }
197
198 polygons.set(idx, coords)?;
199 }
200 ("MultiPolygon".into_js(ctx)?, polygons)
201 }
202 Geometry::Collection(x) => {
203 let geoms = Array::new(ctx.clone())?;
204
205 for (idx, g) in x.iter().enumerate() {
206 let g = g.into_js(ctx)?;
207 geoms.set(idx, g)?;
208 }
209
210 let object = Object::new(ctx.clone())?;
211 object.set("type", "GeometryCollection")?;
212 object.set("geometries", geoms)?;
213 return Ok(object.into_value());
214 }
215 };
216 let object = Object::new(ctx.clone())?;
217 object.set("type", ty)?;
218 object.set("coordinates", coords)?;
219 Ok(object.into_value())
220 }
221}