Skip to content

Commit 3601a05

Browse files
committed
Expect oplog data to be a JSON string
1 parent 7b45d56 commit 3601a05

File tree

8 files changed

+14
-236
lines changed

8 files changed

+14
-236
lines changed

crates/core/src/json_writer.rs

Lines changed: 0 additions & 77 deletions
This file was deleted.

crates/core/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ mod error;
2121
mod ext;
2222
mod fix_data;
2323
mod json_merge;
24-
mod json_writer;
2524
mod kv;
2625
mod macros;
2726
mod migrations;

crates/core/src/sync/line.rs

Lines changed: 9 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,7 @@
1-
use core::assert_matches::debug_assert_matches;
2-
31
use alloc::borrow::Cow;
4-
use alloc::string::{String, ToString};
52
use alloc::vec::Vec;
6-
use serde::{
7-
de::{DeserializeSeed, Error, Visitor},
8-
Deserialize,
9-
};
10-
use serde_json::value::RawValue;
3+
use serde::Deserialize;
114

12-
use crate::json_writer::JsonWriter;
135
use crate::util::{deserialize_optional_string_to_i64, deserialize_string_to_i64};
146

157
use super::bucket_priority::BucketPriority;
@@ -123,7 +115,8 @@ pub struct OplogEntry<'a> {
123115

124116
#[derive(Debug)]
125117
pub enum OplogData<'a> {
126-
JsonString { data: Cow<'a, str> },
118+
/// A string encoding a well-formed JSON object representing values of the row.
119+
Json { data: Cow<'a, str> },
127120
// BsonDocument { data: Cow<'a, [u8]> },
128121
}
129122

@@ -154,147 +147,12 @@ impl<'a, 'de: 'a> Deserialize<'de> for OplogData<'a> {
154147
where
155148
D: serde::Deserializer<'de>,
156149
{
157-
struct ReadFromBsonVisitor;
158-
159-
impl<'de> Visitor<'de> for ReadFromBsonVisitor {
160-
type Value = OplogData<'de>;
161-
162-
fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
163-
formatter.write_str("a string or an object")
164-
}
165-
166-
fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
167-
where
168-
E: serde::de::Error,
169-
{
170-
// Sync service sent data as JSON string. We will save that same string into
171-
// ps_oplog without any transformations.
172-
Ok(OplogData::JsonString {
173-
data: Cow::Borrowed(v),
174-
})
175-
}
176-
177-
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
178-
where
179-
E: serde::de::Error,
180-
{
181-
// Same case, but if the deserializer doesn't let us borrow the JSON string.
182-
Ok(OplogData::JsonString {
183-
data: Cow::Owned(v.to_string()),
184-
})
185-
}
186-
187-
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
188-
where
189-
A: serde::de::MapAccess<'de>,
190-
{
191-
// Ok, we have a sub-document / JSON object. We can't save that as-is, we need to
192-
// serialize it. serde_json's Serializer is std-only because they don't want to
193-
// expose their custom no_std Write trait. So we have to use our own writer impl
194-
// here.
195-
196-
let mut writer = JsonWriter::new();
197-
198-
struct PendingKey<'a, 'de> {
199-
key: &'de str,
200-
writer: &'a mut JsonWriter,
201-
}
202-
203-
impl<'a, 'de> Visitor<'de> for PendingKey<'a, 'de> {
204-
type Value = ();
205-
206-
fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
207-
formatter.write_str("SQLite-compatible value")
208-
}
209-
210-
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
211-
where
212-
E: serde::de::Error,
213-
{
214-
self.writer.write_str(self.key, v);
215-
Ok(())
216-
}
217-
218-
fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
219-
where
220-
E: serde::de::Error,
221-
{
222-
self.writer.write_f64(self.key, v);
223-
Ok(())
224-
}
225-
226-
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
227-
where
228-
E: serde::de::Error,
229-
{
230-
self.writer.write_i64(self.key, v as i64);
231-
Ok(())
232-
}
233-
234-
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
235-
where
236-
E: serde::de::Error,
237-
{
238-
self.writer.write_i64(self.key, v);
239-
Ok(())
240-
}
241-
}
242-
243-
impl<'a, 'de> DeserializeSeed<'de> for PendingKey<'a, 'de> {
244-
type Value = ();
245-
246-
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
247-
where
248-
D: serde::Deserializer<'de>,
249-
{
250-
deserializer.deserialize_any(self)
251-
}
252-
}
253-
254-
while let Some(key) = map.next_key::<&'de str>()? {
255-
let pending = PendingKey {
256-
key,
257-
writer: &mut writer,
258-
};
259-
map.next_value_seed(pending)?;
260-
}
261-
262-
Ok(OplogData::JsonString {
263-
data: Cow::Owned(writer.finish()),
264-
})
265-
}
266-
}
267-
268-
// Regardless of whether we're deserializing JSON or BSON, oplog data is represented either
269-
// as a string (representing a JSON-encoded object) or an object (representing the values
270-
// directly).
271-
272-
let is_from_bson = !deserializer.is_human_readable();
273-
if is_from_bson {
274-
deserializer.deserialize_any(ReadFromBsonVisitor)
275-
} else {
276-
// We're already coming from JSON, so we either have a JSON string or a JSON object.
277-
// Let's take a look at the serialized JSON string.
278-
let data: &'de RawValue = Deserialize::deserialize(deserializer)?;
279-
let str = data.get();
280-
281-
if matches!(str.chars().nth(0), Some('"')) {
282-
// We have a JSON object serialized into a string. We'll have to deserialize once
283-
// so that we have the JSON form of the object itself to forward to the database.
284-
// This turns `"{\"foo\"": 1}"` into `{"foo": 1}`
285-
let content: String = serde_json::from_str(str)
286-
.map_err(|_| D::Error::custom("could not deserialize json string"))?;
287-
Ok(OplogData::JsonString {
288-
data: content.into(),
289-
})
290-
} else {
291-
debug_assert_matches!(str.chars().nth(0), Some('{'));
292-
293-
// It's an embedded object that we now have as a string. How convenient, we'll save
294-
// that into the database without further modifications.
295-
Ok(OplogData::JsonString { data: str.into() })
296-
}
297-
}
150+
// For now, we will always get oplog data as a string. In the future, there may be the
151+
// option of the sync service sending BSON-encoded data lines too, but that's not relevant
152+
// for now.
153+
return Ok(OplogData::Json {
154+
data: Deserialize::deserialize(deserializer)?,
155+
});
298156
}
299157
}
300158

crates/core/src/sync/operations.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ INSERT OR IGNORE INTO ps_updated_rows(row_type, row_id) VALUES(?1, ?2)",
136136
}
137137

138138
match data.data {
139-
Some(OplogData::JsonString { ref data }) => {
139+
Some(OplogData::Json { ref data }) => {
140140
insert_statement.bind_text(6, data.as_ref(), sqlite::Destructor::STATIC)?
141141
}
142142
// Some(OplogData::BsonDocument { ref data }) => {

dart/test/goldens/simple_iteration.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,7 @@
8787
"object_type": "items",
8888
"object_id": "1",
8989
"checksum": 0,
90-
"data": {
91-
"col": "hi"
92-
}
90+
"data": "{\"col\":\"hi\"}"
9391
}
9492
]
9593
}

dart/test/js_key_encoding_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ void main() {
4343
'object_id': '1',
4444
'subkey': json.encode('subkey'),
4545
'checksum': 0,
46-
'data': {'col': 'a'},
46+
'data': json.encode({'col': 'a'}),
4747
}
4848
],
4949
}

dart/test/legacy_sync_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ void main() {
5353
'object_type': 'items',
5454
'object_id': rowId,
5555
'checksum': 0,
56-
'data': data,
56+
'data': json.encode(data),
5757
}
5858
],
5959
}

dart/test/sync_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ void _syncTests<T>({
106106
'object_type': 'items',
107107
'object_id': rowId,
108108
'checksum': checksum,
109-
'data': data,
109+
'data': json.encode(data),
110110
}
111111
],
112112
},

0 commit comments

Comments
 (0)