Skip to content

Commit

Permalink
Add method to list manifests from a workspace
Browse files Browse the repository at this point in the history
  • Loading branch information
FirelightFlagboy committed Jul 31, 2024
1 parent b9539ea commit 8463923
Show file tree
Hide file tree
Showing 8 changed files with 171 additions and 1 deletion.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion libparsec/crates/platform_storage/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ libsqlite3-sys = { workspace = true, features = ["bundled"] }
sqlx = { workspace = true, features = ["sqlite", "runtime-tokio", "macros"] }

[target.'cfg(target_arch = "wasm32")'.dependencies]
indexed_db_futures = { workspace = true, features = ["indices"] }
indexed_db_futures = { workspace = true, features = ["indices", "cursors"] }
js-sys = { workspace = true }
web-sys = { workspace = true, features = ["IdbKeyRange"] }
serde = { workspace = true }
serde-wasm-bindgen = { workspace = true }

Expand Down
33 changes: 33 additions & 0 deletions libparsec/crates/platform_storage/src/native/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
// validation work and takes care of handling concurrency issues.
// Hence no unique violation should occur under normal circumstances here.

use libparsec_platform_async::stream::{StreamExt, TryStreamExt};
use sqlx::{
sqlite::{SqliteConnectOptions, SqliteJournalMode, SqliteSynchronous},
ConnectOptions, Connection, Row, SqliteConnection,
Expand Down Expand Up @@ -199,6 +200,14 @@ impl PlatformWorkspaceStorage {
db_get_manifest(&mut self.conn, entry_id).await
}

pub async fn list_manifests(
&mut self,
offset: u32,
limit: u32,
) -> anyhow::Result<Vec<RawEncryptedManifest>> {
db_list_manifests(&mut self.conn, offset, limit).await
}

pub async fn get_chunk(&mut self, chunk_id: ChunkID) -> anyhow::Result<Option<Vec<u8>>> {
db_get_chunk(&mut self.conn, chunk_id).await
}
Expand Down Expand Up @@ -641,6 +650,30 @@ async fn db_get_manifest(
}
}

async fn db_list_manifests(
executor: impl sqlx::Executor<'_, Database = sqlx::Sqlite>,
offset: u32,
limit: u32,
) -> anyhow::Result<Vec<RawEncryptedManifest>> {
let rows = sqlx::query("SELECT blob FROM vlobs LIMIT ?1 OFFSET ?2")
.bind(limit)
.bind(offset)
.fetch_many(executor);

let res: anyhow::Result<Vec<RawEncryptedManifest>> = rows
.filter_map(|row_res| async {
match row_res {
Ok(sqlx::Either::Left(_res)) => None,
Ok(sqlx::Either::Right(row)) => Some(row.try_get(0).map_err(anyhow::Error::from)),
Err(e) => Some(Err(e.into())),
}
})
.try_collect()
.await;

res
}

pub async fn db_get_chunk(
executor: impl sqlx::Executor<'_, Database = sqlx::Sqlite>,
chunk_id: ChunkID,
Expand Down
53 changes: 53 additions & 0 deletions libparsec/crates/platform_storage/src/web/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,59 @@ where
.map_err(|e| anyhow::anyhow!("{e:?}"))
}

pub(super) async fn list<V>(
tx: &IdbTransaction<'_>,
store: &str,
offset: u32,
limit: u32,
) -> anyhow::Result<Vec<V>>
where
V: DeserializeOwned,
{
use js_sys::Number;
use web_sys::IdbKeyRange;

// Index start at 1
let start = offset + 1;
let end = start + limit;

let range = IdbKeyRange::bound_with_lower_open_and_upper_open(
&Number::from(start),
&Number::from(end),
false,
true,
)
.map_err(|e| anyhow::anyhow!("{e:?}"))?;

let store = tx
.object_store(store)
.map_err(|e| anyhow::anyhow!("{e:?}"))?;

let Some(cursor) = store
.open_cursor_with_range_owned(range)
.map_err(|e| anyhow::anyhow!("{e:?}"))?
.await
.map_err(|e| anyhow::anyhow!("{e:?}"))?
else {
return Ok(Vec::new());
};

cursor
.into_vec(0)
.await
.map_err(|e| anyhow::anyhow!("{e:?}"))
.and_then(|v: Vec<_>| {
v.into_iter()
.map(|key_val|
// TODO: Sad that KeyVal does not provide it's internal value without a reference.
// That reference force us to clone the value, which is not optimal.
// Could be improved if https://github.com/Alorel/rust-indexed-db/issues/39 is fixed
serde_wasm_bindgen::from_value(key_val.value().clone())
.map_err(|e| anyhow::anyhow!("{e:?}")))
.collect::<anyhow::Result<Vec<V>>>()
})
}

pub(super) async fn count(
tx: &IdbTransaction<'_>,
store: &str,
Expand Down
9 changes: 9 additions & 0 deletions libparsec/crates/platform_storage/src/web/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,15 @@ impl Vlob {
super::db::get_all(&tx, Self::STORE).await
}

pub(super) async fn list(
conn: &IdbDatabase,
offset: u32,
limit: u32,
) -> anyhow::Result<Vec<Self>> {
let tx = Self::read(conn)?;
super::db::list(&tx, Self::STORE, offset, limit).await
}

pub(super) async fn remove(tx: &IdbTransaction<'_>, vlob_id: &Bytes) -> anyhow::Result<()> {
let vlob_id =
serde_wasm_bindgen::to_value(vlob_id).map_err(|e| anyhow::anyhow!("{e:?}"))?;
Expand Down
13 changes: 13 additions & 0 deletions libparsec/crates/platform_storage/src/web/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,19 @@ impl PlatformWorkspaceStorage {
)
}

pub async fn list_manifests(
&mut self,
offset: u32,
limit: u32,
) -> anyhow::Result<Vec<RawEncryptedManifest>> {
Vlob::list(&self.conn, offset, limit).await.map(|vlobs| {
vlobs
.into_iter()
.map(|vlob| RawEncryptedManifest::from(vlob.blob))
.collect()
})
}

pub async fn get_chunk(&mut self, chunk_id: ChunkID) -> anyhow::Result<Option<Vec<u8>>> {
let transaction = super::model::Chunk::read(&self.conn)?;
db_get_chunk(&transaction, chunk_id).await
Expand Down
8 changes: 8 additions & 0 deletions libparsec/crates/platform_storage/src/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,14 @@ impl WorkspaceStorage {
self.platform.get_manifest(entry_id).await
}

pub async fn list_manifests(
&mut self,
offset: u32,
limit: u32,
) -> anyhow::Result<Vec<RawEncryptedManifest>> {
self.platform.list_manifests(offset, limit).await
}

pub async fn populate_manifest(
&mut self,
manifest: &UpdateManifestData,
Expand Down
52 changes: 52 additions & 0 deletions libparsec/crates/platform_storage/tests/unit/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,58 @@ async fn get_and_update_manifest(env: &TestbedEnv) {
);
}

#[parsec_test(testbed = "minimal")]
async fn list_manifests(env: &TestbedEnv) {
let realm_id = VlobID::from_hex("aa0000000000000000000000000000ee").unwrap();
let entry1_id = VlobID::from_hex("aa0000000000000000000000000000f1").unwrap();
let entry2_id = VlobID::from_hex("aa0000000000000000000000000000f2").unwrap();
let alice = env.local_device("alice@dev1");

let mut workspace_storage =
WorkspaceStorage::start(&env.discriminant_dir, &alice, realm_id, u64::MAX)
.await
.unwrap();

workspace_storage
.update_manifests(
[
UpdateManifestData {
entry_id: entry1_id,
encrypted: b"<manifest1_v1>".to_vec(),
need_sync: true,
base_version: 1,
},
UpdateManifestData {
entry_id: entry2_id,
encrypted: b"<manifest2_v2>".to_vec(),
need_sync: false,
base_version: 2,
},
]
.into_iter(),
)
.await
.unwrap();

p_assert_eq!(
workspace_storage.list_manifests(0, 1).await.unwrap(),
[b"<manifest1_v1>"]
);
p_assert_eq!(
workspace_storage.list_manifests(1, 1).await.unwrap(),
[b"<manifest2_v2>"]
);

p_assert_eq!(
workspace_storage.list_manifests(0, 10).await.unwrap(),
[b"<manifest1_v1>", b"<manifest2_v2>"]
);
p_assert_eq!(
workspace_storage.list_manifests(2, 10).await.unwrap(),
[] as [&[u8]; 0]
);
}

#[parsec_test(testbed = "minimal")]
async fn update_manifests(env: &TestbedEnv) {
let realm_id = VlobID::from_hex("aa0000000000000000000000000000ee").unwrap();
Expand Down

0 comments on commit 8463923

Please sign in to comment.