Skip to content

Commit 01415b6

Browse files
committed
Extract JsonValue in mod js_value
Signed-off-by: Didier Wenzek <[email protected]>
1 parent 338a481 commit 01415b6

File tree

5 files changed

+173
-168
lines changed

5 files changed

+173
-168
lines changed

crates/extensions/tedge_flows/src/js_lib/console.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::js_script::JsonValue;
1+
use crate::js_value::JsonValue;
22
use rquickjs::class::Trace;
33
use rquickjs::function::Rest;
44
use rquickjs::Ctx;

crates/extensions/tedge_flows/src/js_runtime.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::js_lib;
22
use crate::js_script::JsScript;
3-
use crate::js_script::JsonValue;
3+
use crate::js_value::JsonValue;
44
use crate::LoadError;
55
use anyhow::anyhow;
66
use rquickjs::module::Evaluated;

crates/extensions/tedge_flows/src/js_script.rs

Lines changed: 1 addition & 166 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,7 @@ use crate::flow::DateTime;
33
use crate::flow::FlowError;
44
use crate::flow::Message;
55
use crate::js_runtime::JsRuntime;
6-
use anyhow::Context;
7-
use rquickjs::Ctx;
8-
use rquickjs::FromJs;
9-
use rquickjs::IntoJs;
10-
use rquickjs::Value;
6+
use crate::js_value::JsonValue;
117
use std::path::Path;
128
use std::path::PathBuf;
139
use tracing::debug;
@@ -23,15 +19,6 @@ pub struct JsScript {
2319
pub no_js_on_interval_fun: bool,
2420
}
2521

26-
#[derive(Clone, Debug)]
27-
pub struct JsonValue(serde_json::Value);
28-
29-
impl Default for JsonValue {
30-
fn default() -> Self {
31-
JsonValue(serde_json::Value::Object(Default::default()))
32-
}
33-
}
34-
3522
impl JsScript {
3623
pub fn new(flow: PathBuf, index: usize, path: PathBuf) -> Self {
3724
let module_name = format!("{}|{}|{}", flow.display(), index, path.display());
@@ -159,158 +146,6 @@ impl JsScript {
159146
}
160147
}
161148

162-
impl From<Message> for JsonValue {
163-
fn from(value: Message) -> Self {
164-
JsonValue(value.json())
165-
}
166-
}
167-
168-
impl From<DateTime> for JsonValue {
169-
fn from(value: DateTime) -> Self {
170-
JsonValue(value.json())
171-
}
172-
}
173-
174-
impl TryFrom<serde_json::Value> for Message {
175-
type Error = FlowError;
176-
177-
fn try_from(value: serde_json::Value) -> Result<Self, Self::Error> {
178-
let message = serde_json::from_value(value)
179-
.with_context(|| "Couldn't extract message payload and topic")?;
180-
Ok(message)
181-
}
182-
}
183-
184-
impl TryFrom<JsonValue> for Message {
185-
type Error = FlowError;
186-
187-
fn try_from(value: JsonValue) -> Result<Self, Self::Error> {
188-
Message::try_from(value.0)
189-
}
190-
}
191-
192-
impl TryFrom<JsonValue> for Vec<Message> {
193-
type Error = FlowError;
194-
195-
fn try_from(value: JsonValue) -> Result<Self, Self::Error> {
196-
match value.0 {
197-
serde_json::Value::Array(array) => array.into_iter().map(Message::try_from).collect(),
198-
serde_json::Value::Object(map) => {
199-
Message::try_from(serde_json::Value::Object(map)).map(|message| vec![message])
200-
}
201-
serde_json::Value::Null => Ok(vec![]),
202-
_ => Err(
203-
anyhow::anyhow!("Flow scripts are expected to return an array of messages").into(),
204-
),
205-
}
206-
}
207-
}
208-
209-
struct JsonValueRef<'a>(&'a serde_json::Value);
210-
211-
impl<'js> IntoJs<'js> for JsonValue {
212-
fn into_js(self, ctx: &Ctx<'js>) -> rquickjs::Result<Value<'js>> {
213-
JsonValueRef(&self.0).into_js(ctx)
214-
}
215-
}
216-
217-
impl<'js> IntoJs<'js> for &JsonValue {
218-
fn into_js(self, ctx: &Ctx<'js>) -> rquickjs::Result<Value<'js>> {
219-
JsonValueRef(&self.0).into_js(ctx)
220-
}
221-
}
222-
223-
impl<'js> IntoJs<'js> for JsonValueRef<'_> {
224-
fn into_js(self, ctx: &Ctx<'js>) -> rquickjs::Result<Value<'js>> {
225-
match self.0 {
226-
serde_json::Value::Null => Ok(Value::new_null(ctx.clone())),
227-
serde_json::Value::Bool(value) => Ok(Value::new_bool(ctx.clone(), *value)),
228-
serde_json::Value::Number(value) => {
229-
if let Some(n) = value.as_i64() {
230-
if let Ok(n) = i32::try_from(n) {
231-
return Ok(Value::new_int(ctx.clone(), n));
232-
}
233-
}
234-
if let Some(f) = value.as_f64() {
235-
return Ok(Value::new_float(ctx.clone(), f));
236-
}
237-
let nan = rquickjs::String::from_str(ctx.clone(), "NaN")?;
238-
Ok(nan.into_value())
239-
}
240-
serde_json::Value::String(value) => {
241-
let string = rquickjs::String::from_str(ctx.clone(), value)?;
242-
Ok(string.into_value())
243-
}
244-
serde_json::Value::Array(values) => {
245-
let array = rquickjs::Array::new(ctx.clone())?;
246-
for (i, value) in values.iter().enumerate() {
247-
array.set(i, JsonValueRef(value))?;
248-
}
249-
Ok(array.into_value())
250-
}
251-
serde_json::Value::Object(values) => {
252-
let object = rquickjs::Object::new(ctx.clone())?;
253-
for (key, value) in values.into_iter() {
254-
object.set(key, JsonValueRef(value))?;
255-
}
256-
Ok(object.into_value())
257-
}
258-
}
259-
}
260-
}
261-
262-
impl<'js> FromJs<'js> for JsonValue {
263-
fn from_js(_ctx: &Ctx<'js>, value: Value<'js>) -> rquickjs::Result<Self> {
264-
JsonValue::from_js_value(value)
265-
}
266-
}
267-
268-
impl JsonValue {
269-
fn from_js_value(value: Value<'_>) -> rquickjs::Result<Self> {
270-
if let Some(promise) = value.as_promise() {
271-
// Beware checking the value is a promise must be done first
272-
// as a promise can also be used as an object
273-
return promise.finish();
274-
}
275-
if let Some(b) = value.as_bool() {
276-
return Ok(JsonValue(serde_json::Value::Bool(b)));
277-
}
278-
if let Some(n) = value.as_int() {
279-
return Ok(JsonValue(serde_json::Value::Number(n.into())));
280-
}
281-
if let Some(n) = value.as_float() {
282-
let js_n = serde_json::Number::from_f64(n)
283-
.map(serde_json::Value::Number)
284-
.unwrap_or(serde_json::Value::Null);
285-
return Ok(JsonValue(js_n));
286-
}
287-
if let Some(string) = value.as_string() {
288-
return Ok(JsonValue(serde_json::Value::String(string.to_string()?)));
289-
}
290-
if let Some(array) = value.as_array() {
291-
let array: rquickjs::Result<Vec<JsonValue>> = array.iter().collect();
292-
let array = array?.into_iter().map(|v| v.0).collect();
293-
return Ok(JsonValue(serde_json::Value::Array(array)));
294-
}
295-
if let Some(object) = value.as_object() {
296-
let mut js_object = serde_json::Map::new();
297-
for key in object.keys::<String>().flatten() {
298-
if let Ok(JsonValue(v)) = object.get(&key) {
299-
js_object.insert(key, v.clone());
300-
}
301-
}
302-
return Ok(JsonValue(serde_json::Value::Object(js_object)));
303-
}
304-
305-
Ok(JsonValue(serde_json::Value::Null))
306-
}
307-
308-
pub(crate) fn display(value: Value<'_>) -> String {
309-
let json = JsonValue::from_js_value(value).unwrap_or_default();
310-
serde_json::to_string_pretty(&json.0).unwrap()
311-
}
312-
}
313-
314149
#[cfg(test)]
315150
mod tests {
316151
use super::*;
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
use crate::flow::DateTime;
2+
use crate::flow::FlowError;
3+
use crate::flow::Message;
4+
use anyhow::Context;
5+
use rquickjs::Ctx;
6+
use rquickjs::FromJs;
7+
use rquickjs::IntoJs;
8+
use rquickjs::Value;
9+
10+
#[derive(Clone, Debug)]
11+
pub struct JsonValue(pub serde_json::Value);
12+
13+
impl Default for JsonValue {
14+
fn default() -> Self {
15+
JsonValue(serde_json::Value::Object(Default::default()))
16+
}
17+
}
18+
19+
impl From<Message> for JsonValue {
20+
fn from(value: Message) -> Self {
21+
JsonValue(value.json())
22+
}
23+
}
24+
25+
impl From<DateTime> for JsonValue {
26+
fn from(value: DateTime) -> Self {
27+
JsonValue(value.json())
28+
}
29+
}
30+
31+
impl TryFrom<serde_json::Value> for Message {
32+
type Error = FlowError;
33+
34+
fn try_from(value: serde_json::Value) -> Result<Self, Self::Error> {
35+
let message = serde_json::from_value(value)
36+
.with_context(|| "Couldn't extract message payload and topic")?;
37+
Ok(message)
38+
}
39+
}
40+
41+
impl TryFrom<JsonValue> for Message {
42+
type Error = FlowError;
43+
44+
fn try_from(value: JsonValue) -> Result<Self, Self::Error> {
45+
Message::try_from(value.0)
46+
}
47+
}
48+
49+
impl TryFrom<JsonValue> for Vec<Message> {
50+
type Error = FlowError;
51+
52+
fn try_from(value: JsonValue) -> Result<Self, Self::Error> {
53+
match value.0 {
54+
serde_json::Value::Array(array) => array.into_iter().map(Message::try_from).collect(),
55+
serde_json::Value::Object(map) => {
56+
Message::try_from(serde_json::Value::Object(map)).map(|message| vec![message])
57+
}
58+
serde_json::Value::Null => Ok(vec![]),
59+
_ => Err(
60+
anyhow::anyhow!("Flow scripts are expected to return an array of messages").into(),
61+
),
62+
}
63+
}
64+
}
65+
66+
struct JsonValueRef<'a>(&'a serde_json::Value);
67+
68+
impl<'js> IntoJs<'js> for JsonValue {
69+
fn into_js(self, ctx: &Ctx<'js>) -> rquickjs::Result<Value<'js>> {
70+
JsonValueRef(&self.0).into_js(ctx)
71+
}
72+
}
73+
74+
impl<'js> IntoJs<'js> for &JsonValue {
75+
fn into_js(self, ctx: &Ctx<'js>) -> rquickjs::Result<Value<'js>> {
76+
JsonValueRef(&self.0).into_js(ctx)
77+
}
78+
}
79+
80+
impl<'js> IntoJs<'js> for JsonValueRef<'_> {
81+
fn into_js(self, ctx: &Ctx<'js>) -> rquickjs::Result<Value<'js>> {
82+
match self.0 {
83+
serde_json::Value::Null => Ok(Value::new_null(ctx.clone())),
84+
serde_json::Value::Bool(value) => Ok(Value::new_bool(ctx.clone(), *value)),
85+
serde_json::Value::Number(value) => {
86+
if let Some(n) = value.as_i64() {
87+
if let Ok(n) = i32::try_from(n) {
88+
return Ok(Value::new_int(ctx.clone(), n));
89+
}
90+
}
91+
if let Some(f) = value.as_f64() {
92+
return Ok(Value::new_float(ctx.clone(), f));
93+
}
94+
let nan = rquickjs::String::from_str(ctx.clone(), "NaN")?;
95+
Ok(nan.into_value())
96+
}
97+
serde_json::Value::String(value) => {
98+
let string = rquickjs::String::from_str(ctx.clone(), value)?;
99+
Ok(string.into_value())
100+
}
101+
serde_json::Value::Array(values) => {
102+
let array = rquickjs::Array::new(ctx.clone())?;
103+
for (i, value) in values.iter().enumerate() {
104+
array.set(i, JsonValueRef(value))?;
105+
}
106+
Ok(array.into_value())
107+
}
108+
serde_json::Value::Object(values) => {
109+
let object = rquickjs::Object::new(ctx.clone())?;
110+
for (key, value) in values.into_iter() {
111+
object.set(key, JsonValueRef(value))?;
112+
}
113+
Ok(object.into_value())
114+
}
115+
}
116+
}
117+
}
118+
119+
impl<'js> FromJs<'js> for JsonValue {
120+
fn from_js(_ctx: &Ctx<'js>, value: Value<'js>) -> rquickjs::Result<Self> {
121+
JsonValue::from_js_value(value)
122+
}
123+
}
124+
125+
impl JsonValue {
126+
fn from_js_value(value: Value<'_>) -> rquickjs::Result<Self> {
127+
if let Some(promise) = value.as_promise() {
128+
// Beware checking the value is a promise must be done first
129+
// as a promise can also be used as an object
130+
return promise.finish();
131+
}
132+
if let Some(b) = value.as_bool() {
133+
return Ok(JsonValue(serde_json::Value::Bool(b)));
134+
}
135+
if let Some(n) = value.as_int() {
136+
return Ok(JsonValue(serde_json::Value::Number(n.into())));
137+
}
138+
if let Some(n) = value.as_float() {
139+
let js_n = serde_json::Number::from_f64(n)
140+
.map(serde_json::Value::Number)
141+
.unwrap_or(serde_json::Value::Null);
142+
return Ok(JsonValue(js_n));
143+
}
144+
if let Some(string) = value.as_string() {
145+
return Ok(JsonValue(serde_json::Value::String(string.to_string()?)));
146+
}
147+
if let Some(array) = value.as_array() {
148+
let array: rquickjs::Result<Vec<JsonValue>> = array.iter().collect();
149+
let array = array?.into_iter().map(|v| v.0).collect();
150+
return Ok(JsonValue(serde_json::Value::Array(array)));
151+
}
152+
if let Some(object) = value.as_object() {
153+
let mut js_object = serde_json::Map::new();
154+
for key in object.keys::<String>().flatten() {
155+
if let Ok(JsonValue(v)) = object.get(&key) {
156+
js_object.insert(key, v.clone());
157+
}
158+
}
159+
return Ok(JsonValue(serde_json::Value::Object(js_object)));
160+
}
161+
162+
Ok(JsonValue(serde_json::Value::Null))
163+
}
164+
165+
pub(crate) fn display(value: Value<'_>) -> String {
166+
let json = JsonValue::from_js_value(value).unwrap_or_default();
167+
serde_json::to_string_pretty(&json.0).unwrap()
168+
}
169+
}

crates/extensions/tedge_flows/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ pub mod flow;
44
mod js_lib;
55
mod js_runtime;
66
mod js_script;
7+
mod js_value;
78
mod runtime;
89
mod stats;
910

0 commit comments

Comments
 (0)