From 677033b41af424b730d9f4cf401aaee6289b1a0c Mon Sep 17 00:00:00 2001 From: David Dal Busco Date: Sat, 24 Aug 2024 11:41:10 +0200 Subject: [PATCH 1/3] feat: (new) count docs and assets Signed-off-by: David Dal Busco --- src/libs/satellite/src/db/store.rs | 28 +++++++++++++++ src/libs/satellite/src/lib.rs | 36 ++++++++++++------- src/libs/satellite/src/satellite.rs | 35 +++++++++++++++---- src/libs/satellite/src/storage/store.rs | 46 +++++++++++++++++++++++++ src/orbiter/src/assert/config.rs | 30 ++++++++++++---- src/orbiter/src/lib.rs | 14 +++++--- src/orbiter/src/msg.rs | 3 +- src/orbiter/src/upgrade/impls.rs | 14 +++++--- src/orbiter/src/upgrade/types.rs | 6 ++-- 9 files changed, 173 insertions(+), 39 deletions(-) diff --git a/src/libs/satellite/src/db/store.rs b/src/libs/satellite/src/db/store.rs index 87512afba..8dc62b6a8 100644 --- a/src/libs/satellite/src/db/store.rs +++ b/src/libs/satellite/src/db/store.rs @@ -246,6 +246,34 @@ pub fn list_docs_store( secure_get_docs(caller, &controllers, collection, filter) } +/// Count documents in a collection. +/// +/// This function retrieves the count of documents from a collection's store based on the specified parameters. +/// It returns a `Result` where `Ok(usize)` contains the count of documents matching the filter criteria, +/// or an error message as `Err(String)` if the operation encounters issues. +/// +/// # Parameters +/// - `caller`: The `Principal` representing the caller initiating the operation. If used in serverless functions, you can use `ic_cdk::id()` to pass an administrator controller. +/// - `collection`: A `CollectionKey` representing the collection from which to count the documents. +/// - `filter`: A reference to `ListParams` containing the filter criteria for counting the documents. +/// +/// # Returns +/// - `Ok(usize)`: Contains the count of documents matching the filter criteria. +/// - `Err(String)`: An error message if the operation fails. +/// +/// This function counts documents in a Juno collection's store by listing them and then determining the length of the result set. +/// +/// # Note +/// This implementation can be improved, as it currently relies on `list_docs_store` underneath, meaning that all documents matching the filter criteria are still read from the store. This might lead to unnecessary overhead, especially for large collections. Optimizing this function to count documents directly without retrieving them could enhance performance. +pub fn count_docs_store( + caller: Principal, + collection: CollectionKey, + filter: &ListParams, +) -> Result { + let results = list_docs_store(caller, collection, filter)?; + Ok(results.items_length) +} + fn secure_get_docs( caller: Principal, controllers: &Controllers, diff --git a/src/libs/satellite/src/lib.rs b/src/libs/satellite/src/lib.rs index dd4fac14b..34dd5eac7 100644 --- a/src/libs/satellite/src/lib.rs +++ b/src/libs/satellite/src/lib.rs @@ -37,8 +37,8 @@ use junobuild_storage::types::interface::{ // Re-export types pub use crate::db::store::{ - count_collection_docs_store, delete_doc_store, delete_docs_store, get_doc_store, list_docs_store, - set_doc_store, + count_collection_docs_store, count_docs_store, delete_doc_store, delete_docs_store, + get_doc_store, list_docs_store, set_doc_store, }; use crate::db::types::config::DbConfig; pub use crate::db::types::interface::{DelDoc, SetDoc}; @@ -50,8 +50,8 @@ pub use crate::logs::loggers::{ pub use crate::logs::types::logs::{Log, LogLevel}; pub use crate::storage::handlers::set_asset_handler; pub use crate::storage::store::{ - count_collection_assets_store, delete_asset_store, delete_assets_store, get_asset_store, - get_content_chunks_store, list_assets_store, + count_assets_store, count_collection_assets_store, delete_asset_store, delete_assets_store, + get_asset_store, get_content_chunks_store, list_assets_store, }; pub use crate::types::hooks::{ AssertDeleteAssetContext, AssertDeleteDocContext, AssertSetDocContext, @@ -118,6 +118,12 @@ pub fn list_docs(collection: CollectionKey, filter: ListParams) -> ListResults usize { + satellite::count_docs(collection, filter) +} + #[doc(hidden)] #[query] pub fn get_many_docs(docs: Vec<(CollectionKey, Key)>) -> Vec<(Key, Option)> { @@ -316,6 +322,12 @@ pub fn list_assets(collection: CollectionKey, filter: ListParams) -> ListResults satellite::list_assets(collection, filter) } +#[doc(hidden)] +#[query] +pub fn count_assets(collection: CollectionKey, filter: ListParams) -> usize { + satellite::count_assets(collection, filter) +} + #[doc(hidden)] #[update] pub fn del_asset(collection: CollectionKey, full_path: FullPath) { @@ -395,14 +407,14 @@ pub fn memory_size() -> MemorySize { macro_rules! include_satellite { () => { use junobuild_satellite::{ - commit_asset_upload, count_collection_assets, count_collection_docs, del_asset, del_assets, del_controllers, - del_custom_domain, del_doc, del_docs, del_many_assets, del_many_docs, del_rule, - deposit_cycles, get_asset, get_auth_config, get_config, get_db_config, get_doc, - get_many_assets, get_many_docs, get_storage_config, http_request, - http_request_streaming_callback, init, init_asset_upload, list_assets, - list_controllers, list_custom_domains, list_docs, list_rules, memory_size, - post_upgrade, pre_upgrade, set_auth_config, set_controllers, set_custom_domain, - set_db_config, set_doc, set_many_docs, set_rule, set_storage_config, + commit_asset_upload, count_assets, count_collection_assets, count_collection_docs, + count_docs, del_asset, del_assets, del_controllers, del_custom_domain, del_doc, + del_docs, del_many_assets, del_many_docs, del_rule, deposit_cycles, get_asset, + get_auth_config, get_config, get_db_config, get_doc, get_many_assets, get_many_docs, + get_storage_config, http_request, http_request_streaming_callback, init, + init_asset_upload, list_assets, list_controllers, list_custom_domains, list_docs, + list_rules, memory_size, post_upgrade, pre_upgrade, set_auth_config, set_controllers, + set_custom_domain, set_db_config, set_doc, set_many_docs, set_rule, set_storage_config, upload_asset_chunk, version, }; diff --git a/src/libs/satellite/src/satellite.rs b/src/libs/satellite/src/satellite.rs index c38f46085..53d36a68a 100644 --- a/src/libs/satellite/src/satellite.rs +++ b/src/libs/satellite/src/satellite.rs @@ -8,8 +8,9 @@ use crate::controllers::store::{ set_controllers as set_controllers_store, }; use crate::db::store::{ - count_collection_docs_store, delete_doc_store, delete_docs_store, get_config_store as get_db_config_store, - get_doc_store, list_docs_store, set_config_store as set_db_config_store, set_doc_store, + count_collection_docs_store, count_docs_store, delete_doc_store, delete_docs_store, + get_config_store as get_db_config_store, get_doc_store, list_docs_store, + set_config_store as set_db_config_store, set_doc_store, }; use crate::db::types::config::DbConfig; use crate::db::types::interface::{DelDoc, SetDoc}; @@ -25,10 +26,10 @@ use crate::rules::store::{ }; use crate::storage::certified_assets::upgrade::defer_init_certified_assets; use crate::storage::store::{ - commit_batch_store, count_collection_assets_store, create_batch_store, create_chunk_store, - delete_asset_store, delete_assets_store, delete_domain_store, get_asset_store, - get_config_store as get_storage_config_store, get_custom_domains_store, list_assets_store, - set_config_store as set_storage_config_store, set_domain_store, + commit_batch_store, count_assets_store, count_collection_assets_store, create_batch_store, + create_chunk_store, delete_asset_store, delete_assets_store, delete_domain_store, + get_asset_store, get_config_store as get_storage_config_store, get_custom_domains_store, + list_assets_store, set_config_store as set_storage_config_store, set_domain_store, }; use crate::storage::strategy_impls::StorageState; use crate::types::interface::{Config, RulesType}; @@ -153,6 +154,17 @@ pub fn list_docs(collection: CollectionKey, filter: ListParams) -> ListResults usize { + let caller = caller(); + + let result = count_docs_store(caller, collection, &filter); + + match result { + Ok(value) => value, + Err(error) => trap(&error), + } +} + pub fn get_many_docs(docs: Vec<(CollectionKey, Key)>) -> Vec<(Key, Option)> { docs.iter() .map(|(collection, key)| { @@ -405,6 +417,17 @@ pub fn list_assets(collection: CollectionKey, filter: ListParams) -> ListResults } } +pub fn count_assets(collection: CollectionKey, filter: ListParams) -> usize { + let caller = caller(); + + let result = count_assets_store(caller, &collection, &filter); + + match result { + Ok(result) => result, + Err(error) => trap(&["Assets cannot be counted: ".to_string(), error].join("")), + } +} + pub fn del_asset(collection: CollectionKey, full_path: FullPath) { let caller = caller(); diff --git a/src/libs/satellite/src/storage/store.rs b/src/libs/satellite/src/storage/store.rs index 8213550f1..c0cf4c6c2 100644 --- a/src/libs/satellite/src/storage/store.rs +++ b/src/libs/satellite/src/storage/store.rs @@ -125,6 +125,24 @@ pub fn delete_assets_store(collection: &CollectionKey) -> Result<(), String> { delete_assets_impl(&full_paths, collection, &rule) } +/// List assets in a collection. +/// +/// This function retrieves a list of assets from a collection's store based on the specified parameters. +/// It returns a `Result, String>` where `Ok(ListResults)` contains the retrieved assets, +/// or an error message as `Err(String)` if the operation encounters issues. +/// +/// # Parameters +/// - `caller`: The `Principal` representing the caller initiating the operation. If used in serverless functions, you can use `ic_cdk::id()` to pass an administrator controller. +/// - `collection`: A reference to the `CollectionKey` representing the collection from which to list the assets. +/// - `filters`: A reference to `ListParams` containing the filter criteria for listing the assets. +/// +/// # Returns +/// - `Ok(ListResults)`: Contains the list of retrieved assets, without their content, matching the filter criteria. +/// - `Err(String)`: An error message if the operation fails. +/// +/// This function lists assets in a Juno collection's store, applying the specified filter criteria to retrieve the assets. +/// The returned list includes the assets without their content (`AssetNoContent`), which is useful for operations where only +/// metadata or references are needed. pub fn list_assets_store( caller: Principal, collection: &CollectionKey, @@ -135,6 +153,34 @@ pub fn list_assets_store( secure_list_assets_impl(caller, &controllers, collection, filters) } +/// Count assets in a collection. +/// +/// This function retrieves the count of assets from a collection's store based on the specified parameters. +/// It returns a `Result` where `Ok(usize)` contains the count of assets matching the filter criteria, +/// or an error message as `Err(String)` if the operation encounters issues. +/// +/// # Parameters +/// - `caller`: The `Principal` representing the caller initiating the operation. If used in serverless functions, you can use `ic_cdk::id()` to pass an administrator controller. +/// - `collection`: A reference to the `CollectionKey` representing the collection from which to count the assets. +/// - `filters`: A reference to `ListParams` containing the filter criteria for counting the assets. +/// +/// # Returns +/// - `Ok(usize)`: Contains the count of assets matching the filter criteria. +/// - `Err(String)`: An error message if the operation fails. +/// +/// This function counts assets in a Juno collection's store by listing them and then determining the length of the result set. +/// +/// # Note +/// This implementation can be improved, as it currently relies on `list_assets_store` underneath, meaning that all assets matching the filter criteria are still read from the store. This might lead to unnecessary overhead, especially for large collections. Optimizing this function to count assets directly without retrieving them could enhance performance. +pub fn count_assets_store( + caller: Principal, + collection: &CollectionKey, + filters: &ListParams, +) -> Result { + let results = list_assets_store(caller, collection, filters)?; + Ok(results.items_length) +} + /// Get an asset from a collection's store. /// /// This function retrieves an asset from a collection's store based on the specified parameters. diff --git a/src/orbiter/src/assert/config.rs b/src/orbiter/src/assert/config.rs index 5b4ca38fd..6460da142 100644 --- a/src/orbiter/src/assert/config.rs +++ b/src/orbiter/src/assert/config.rs @@ -4,9 +4,13 @@ use crate::msg::{ }; use crate::types::state::SatelliteConfig; -fn assert_feature_enabled(config: &Option, check_feature: F, error_message: &str) -> Result<(), String> - where - F: Fn(&SatelliteConfig) -> bool, +fn assert_feature_enabled( + config: &Option, + check_feature: F, + error_message: &str, +) -> Result<(), String> +where + F: Fn(&SatelliteConfig) -> bool, { if let Some(config) = config { if check_feature(config) { @@ -16,13 +20,25 @@ fn assert_feature_enabled(config: &Option, check_feature: F, Err(error_message.to_string()) } pub fn assert_page_views_enabled(config: &Option) -> Result<(), String> { - assert_feature_enabled(config, |c| c.features.as_ref().map_or(false, |f| f.page_views), ERROR_PAGE_VIEWS_FEATURE_DISABLED) + assert_feature_enabled( + config, + |c| c.features.as_ref().map_or(false, |f| f.page_views), + ERROR_PAGE_VIEWS_FEATURE_DISABLED, + ) } pub fn assert_track_events_enabled(config: &Option) -> Result<(), String> { - assert_feature_enabled(config, |c| c.features.as_ref().map_or(false, |f| f.track_events), ERROR_TRACK_EVENTS_FEATURE_DISABLED) + assert_feature_enabled( + config, + |c| c.features.as_ref().map_or(false, |f| f.track_events), + ERROR_TRACK_EVENTS_FEATURE_DISABLED, + ) } pub fn assert_performance_metrics_enabled(config: &Option) -> Result<(), String> { - assert_feature_enabled(config, |c| c.features.as_ref().map_or(false, |f| f.performance_metrics), ERROR_PERFORMANCE_METRICS_FEATURE_DISABLED) -} \ No newline at end of file + assert_feature_enabled( + config, + |c| c.features.as_ref().map_or(false, |f| f.performance_metrics), + ERROR_PERFORMANCE_METRICS_FEATURE_DISABLED, + ) +} diff --git a/src/orbiter/src/lib.rs b/src/orbiter/src/lib.rs index 346934f0e..d09a8c303 100644 --- a/src/orbiter/src/lib.rs +++ b/src/orbiter/src/lib.rs @@ -17,6 +17,9 @@ use crate::analytics::{ analytics_page_views_clients, analytics_page_views_metrics, analytics_page_views_top_10, analytics_performance_metrics_web_vitals, analytics_track_events, }; +use crate::assert::config::{ + assert_page_views_enabled, assert_performance_metrics_enabled, assert_track_events_enabled, +}; use crate::config::store::{ del_satellite_config as del_satellite_config_store, get_satellite_configs, set_satellite_config as set_satellite_config_store, @@ -41,6 +44,7 @@ use crate::types::interface::{ use crate::types::state::{ AnalyticKey, HeapState, PageView, PerformanceMetric, SatelliteConfigs, State, TrackEvent, }; +use crate::upgrade::types::upgrade::UpgradeState; use ciborium::{from_reader, into_writer}; use ic_cdk::api::call::{arg_data, ArgDecoderConfig}; use ic_cdk::trap; @@ -57,8 +61,6 @@ use junobuild_shared::types::interface::{ use junobuild_shared::types::memory::Memory; use junobuild_shared::types::state::{ControllerScope, Controllers, SatelliteId}; use junobuild_shared::upgrade::{read_post_upgrade, write_pre_upgrade}; -use crate::assert::config::{assert_page_views_enabled, assert_performance_metrics_enabled, assert_track_events_enabled}; -use crate::upgrade::types::upgrade::UpgradeState; #[init] fn init() { @@ -96,9 +98,11 @@ fn post_upgrade() { let upgrade_state: UpgradeState = from_reader(&*state_bytes) .expect("Failed to decode the state of the orbiter in post_upgrade hook."); - STATE.with(|s| *s.borrow_mut() = State { - stable: upgrade_state.stable, - heap: HeapState::from(&upgrade_state.heap), + STATE.with(|s| { + *s.borrow_mut() = State { + stable: upgrade_state.stable, + heap: HeapState::from(&upgrade_state.heap), + } }); } diff --git a/src/orbiter/src/msg.rs b/src/orbiter/src/msg.rs index 24b84b9b2..15cf8e964 100644 --- a/src/orbiter/src/msg.rs +++ b/src/orbiter/src/msg.rs @@ -1,4 +1,5 @@ pub const ERROR_PAGE_VIEWS_FEATURE_DISABLED: &str = "error_page_views_feature_disabled"; pub const ERROR_TRACK_EVENTS_FEATURE_DISABLED: &str = "error_track_events_feature_disabled"; -pub const ERROR_PERFORMANCE_METRICS_FEATURE_DISABLED: &str = "error_performance_metrics_feature_disabled"; +pub const ERROR_PERFORMANCE_METRICS_FEATURE_DISABLED: &str = + "error_performance_metrics_feature_disabled"; pub const ERROR_BOT_CALL: &str = "error_bot_call"; diff --git a/src/orbiter/src/upgrade/impls.rs b/src/orbiter/src/upgrade/impls.rs index 996c1bb9b..15e930728 100644 --- a/src/orbiter/src/upgrade/impls.rs +++ b/src/orbiter/src/upgrade/impls.rs @@ -1,20 +1,24 @@ -use std::collections::HashMap; -use junobuild_shared::types::state::{OrbiterSatelliteConfig, OrbiterSatelliteFeatures, SatelliteId}; use crate::types::state::HeapState; use crate::upgrade::types::upgrade::UpgradeHeapState; +use junobuild_shared::types::state::{ + OrbiterSatelliteConfig, OrbiterSatelliteFeatures, SatelliteId, +}; +use std::collections::HashMap; impl From<&UpgradeHeapState> for HeapState { fn from(state: &UpgradeHeapState) -> Self { - let config: HashMap = state.config.iter() + let config: HashMap = state + .config + .iter() .map(|(id, upgrade_config)| { let satellite_config = OrbiterSatelliteConfig { features: match upgrade_config.enabled { true => Some(OrbiterSatelliteFeatures { performance_metrics: true, track_events: true, - page_views: true + page_views: true, }), - false => None + false => None, }, created_at: upgrade_config.created_at, updated_at: upgrade_config.updated_at, diff --git a/src/orbiter/src/upgrade/types.rs b/src/orbiter/src/upgrade/types.rs index a94a53532..b12e538d9 100644 --- a/src/orbiter/src/upgrade/types.rs +++ b/src/orbiter/src/upgrade/types.rs @@ -1,10 +1,10 @@ pub mod upgrade { - use std::collections::HashMap; use crate::memory::init_stable_state; - use crate::types::state::{StableState}; + use crate::types::state::StableState; use candid::CandidType; - use serde::{Deserialize, Serialize}; use junobuild_shared::types::state::{Controllers, SatelliteId, Timestamp, Version}; + use serde::{Deserialize, Serialize}; + use std::collections::HashMap; #[derive(Serialize, Deserialize)] pub struct UpgradeState { From 643ada5d8aa2bea82e7bdc4e75faf814062b6866 Mon Sep 17 00:00:00 2001 From: David Dal Busco Date: Sat, 24 Aug 2024 11:47:23 +0200 Subject: [PATCH 2/3] feat: did Signed-off-by: David Dal Busco --- src/declarations/satellite/satellite.did.d.ts | 2 + .../satellite/satellite.factory.did.js | 58 ++++++++++--------- .../satellite/satellite.factory.did.mjs | 58 ++++++++++--------- src/libs/satellite/satellite.did | 2 + src/satellite/satellite.did | 2 + 5 files changed, 66 insertions(+), 56 deletions(-) diff --git a/src/declarations/satellite/satellite.did.d.ts b/src/declarations/satellite/satellite.did.d.ts index 37d1df983..b9a930a5a 100644 --- a/src/declarations/satellite/satellite.did.d.ts +++ b/src/declarations/satellite/satellite.did.d.ts @@ -234,8 +234,10 @@ export interface UploadChunkResult { export interface _SERVICE { build_version: ActorMethod<[], string>; commit_asset_upload: ActorMethod<[CommitBatch], undefined>; + count_assets: ActorMethod<[string, ListParams], bigint>; count_collection_assets: ActorMethod<[string], bigint>; count_collection_docs: ActorMethod<[string], bigint>; + count_docs: ActorMethod<[string, ListParams], bigint>; del_asset: ActorMethod<[string, string], undefined>; del_assets: ActorMethod<[string], undefined>; del_controllers: ActorMethod<[DeleteControllersArgs], Array<[Principal, Controller]>>; diff --git a/src/declarations/satellite/satellite.factory.did.js b/src/declarations/satellite/satellite.factory.did.js index 23f7b9e5e..eecdc6795 100644 --- a/src/declarations/satellite/satellite.factory.did.js +++ b/src/declarations/satellite/satellite.factory.did.js @@ -5,6 +5,34 @@ export const idlFactory = ({ IDL }) => { headers: IDL.Vec(IDL.Tuple(IDL.Text, IDL.Text)), chunk_ids: IDL.Vec(IDL.Nat) }); + const ListOrderField = IDL.Variant({ + UpdatedAt: IDL.Null, + Keys: IDL.Null, + CreatedAt: IDL.Null + }); + const ListOrder = IDL.Record({ field: ListOrderField, desc: IDL.Bool }); + const TimestampMatcher = IDL.Variant({ + Equal: IDL.Nat64, + Between: IDL.Tuple(IDL.Nat64, IDL.Nat64), + GreaterThan: IDL.Nat64, + LessThan: IDL.Nat64 + }); + const ListMatcher = IDL.Record({ + key: IDL.Opt(IDL.Text), + updated_at: IDL.Opt(TimestampMatcher), + description: IDL.Opt(IDL.Text), + created_at: IDL.Opt(TimestampMatcher) + }); + const ListPaginate = IDL.Record({ + start_after: IDL.Opt(IDL.Text), + limit: IDL.Opt(IDL.Nat64) + }); + const ListParams = IDL.Record({ + order: IDL.Opt(ListOrder), + owner: IDL.Opt(IDL.Principal), + matcher: IDL.Opt(ListMatcher), + paginate: IDL.Opt(ListPaginate) + }); const DeleteControllersArgs = IDL.Record({ controllers: IDL.Vec(IDL.Principal) }); @@ -136,34 +164,6 @@ export const idlFactory = ({ IDL }) => { full_path: IDL.Text }); const InitUploadResult = IDL.Record({ batch_id: IDL.Nat }); - const ListOrderField = IDL.Variant({ - UpdatedAt: IDL.Null, - Keys: IDL.Null, - CreatedAt: IDL.Null - }); - const ListOrder = IDL.Record({ field: ListOrderField, desc: IDL.Bool }); - const TimestampMatcher = IDL.Variant({ - Equal: IDL.Nat64, - Between: IDL.Tuple(IDL.Nat64, IDL.Nat64), - GreaterThan: IDL.Nat64, - LessThan: IDL.Nat64 - }); - const ListMatcher = IDL.Record({ - key: IDL.Opt(IDL.Text), - updated_at: IDL.Opt(TimestampMatcher), - description: IDL.Opt(IDL.Text), - created_at: IDL.Opt(TimestampMatcher) - }); - const ListPaginate = IDL.Record({ - start_after: IDL.Opt(IDL.Text), - limit: IDL.Opt(IDL.Nat64) - }); - const ListParams = IDL.Record({ - order: IDL.Opt(ListOrder), - owner: IDL.Opt(IDL.Principal), - matcher: IDL.Opt(ListMatcher), - paginate: IDL.Opt(ListPaginate) - }); const ListResults = IDL.Record({ matches_pages: IDL.Opt(IDL.Nat64), matches_length: IDL.Nat64, @@ -234,8 +234,10 @@ export const idlFactory = ({ IDL }) => { return IDL.Service({ build_version: IDL.Func([], [IDL.Text], ['query']), commit_asset_upload: IDL.Func([CommitBatch], [], []), + count_assets: IDL.Func([IDL.Text, ListParams], [IDL.Nat64], ['query']), count_collection_assets: IDL.Func([IDL.Text], [IDL.Nat64], ['query']), count_collection_docs: IDL.Func([IDL.Text], [IDL.Nat64], ['query']), + count_docs: IDL.Func([IDL.Text, ListParams], [IDL.Nat64], ['query']), del_asset: IDL.Func([IDL.Text, IDL.Text], [], []), del_assets: IDL.Func([IDL.Text], [], []), del_controllers: IDL.Func( diff --git a/src/declarations/satellite/satellite.factory.did.mjs b/src/declarations/satellite/satellite.factory.did.mjs index 23f7b9e5e..eecdc6795 100644 --- a/src/declarations/satellite/satellite.factory.did.mjs +++ b/src/declarations/satellite/satellite.factory.did.mjs @@ -5,6 +5,34 @@ export const idlFactory = ({ IDL }) => { headers: IDL.Vec(IDL.Tuple(IDL.Text, IDL.Text)), chunk_ids: IDL.Vec(IDL.Nat) }); + const ListOrderField = IDL.Variant({ + UpdatedAt: IDL.Null, + Keys: IDL.Null, + CreatedAt: IDL.Null + }); + const ListOrder = IDL.Record({ field: ListOrderField, desc: IDL.Bool }); + const TimestampMatcher = IDL.Variant({ + Equal: IDL.Nat64, + Between: IDL.Tuple(IDL.Nat64, IDL.Nat64), + GreaterThan: IDL.Nat64, + LessThan: IDL.Nat64 + }); + const ListMatcher = IDL.Record({ + key: IDL.Opt(IDL.Text), + updated_at: IDL.Opt(TimestampMatcher), + description: IDL.Opt(IDL.Text), + created_at: IDL.Opt(TimestampMatcher) + }); + const ListPaginate = IDL.Record({ + start_after: IDL.Opt(IDL.Text), + limit: IDL.Opt(IDL.Nat64) + }); + const ListParams = IDL.Record({ + order: IDL.Opt(ListOrder), + owner: IDL.Opt(IDL.Principal), + matcher: IDL.Opt(ListMatcher), + paginate: IDL.Opt(ListPaginate) + }); const DeleteControllersArgs = IDL.Record({ controllers: IDL.Vec(IDL.Principal) }); @@ -136,34 +164,6 @@ export const idlFactory = ({ IDL }) => { full_path: IDL.Text }); const InitUploadResult = IDL.Record({ batch_id: IDL.Nat }); - const ListOrderField = IDL.Variant({ - UpdatedAt: IDL.Null, - Keys: IDL.Null, - CreatedAt: IDL.Null - }); - const ListOrder = IDL.Record({ field: ListOrderField, desc: IDL.Bool }); - const TimestampMatcher = IDL.Variant({ - Equal: IDL.Nat64, - Between: IDL.Tuple(IDL.Nat64, IDL.Nat64), - GreaterThan: IDL.Nat64, - LessThan: IDL.Nat64 - }); - const ListMatcher = IDL.Record({ - key: IDL.Opt(IDL.Text), - updated_at: IDL.Opt(TimestampMatcher), - description: IDL.Opt(IDL.Text), - created_at: IDL.Opt(TimestampMatcher) - }); - const ListPaginate = IDL.Record({ - start_after: IDL.Opt(IDL.Text), - limit: IDL.Opt(IDL.Nat64) - }); - const ListParams = IDL.Record({ - order: IDL.Opt(ListOrder), - owner: IDL.Opt(IDL.Principal), - matcher: IDL.Opt(ListMatcher), - paginate: IDL.Opt(ListPaginate) - }); const ListResults = IDL.Record({ matches_pages: IDL.Opt(IDL.Nat64), matches_length: IDL.Nat64, @@ -234,8 +234,10 @@ export const idlFactory = ({ IDL }) => { return IDL.Service({ build_version: IDL.Func([], [IDL.Text], ['query']), commit_asset_upload: IDL.Func([CommitBatch], [], []), + count_assets: IDL.Func([IDL.Text, ListParams], [IDL.Nat64], ['query']), count_collection_assets: IDL.Func([IDL.Text], [IDL.Nat64], ['query']), count_collection_docs: IDL.Func([IDL.Text], [IDL.Nat64], ['query']), + count_docs: IDL.Func([IDL.Text, ListParams], [IDL.Nat64], ['query']), del_asset: IDL.Func([IDL.Text, IDL.Text], [], []), del_assets: IDL.Func([IDL.Text], [], []), del_controllers: IDL.Func( diff --git a/src/libs/satellite/satellite.did b/src/libs/satellite/satellite.did index f78fbfb3a..8bbe66a43 100644 --- a/src/libs/satellite/satellite.did +++ b/src/libs/satellite/satellite.did @@ -196,8 +196,10 @@ type UploadChunk = record { type UploadChunkResult = record { chunk_id : nat }; service : () -> { commit_asset_upload : (CommitBatch) -> (); + count_assets : (text, ListParams) -> (nat64) query; count_collection_assets : (text) -> (nat64) query; count_collection_docs : (text) -> (nat64) query; + count_docs : (text, ListParams) -> (nat64) query; del_asset : (text, text) -> (); del_assets : (text) -> (); del_controllers : (DeleteControllersArgs) -> ( diff --git a/src/satellite/satellite.did b/src/satellite/satellite.did index d4af035ad..817a99b22 100644 --- a/src/satellite/satellite.did +++ b/src/satellite/satellite.did @@ -198,8 +198,10 @@ type UploadChunk = record { type UploadChunkResult = record { chunk_id : nat }; service : () -> { commit_asset_upload : (CommitBatch) -> (); + count_assets : (text, ListParams) -> (nat64) query; count_collection_assets : (text) -> (nat64) query; count_collection_docs : (text) -> (nat64) query; + count_docs : (text, ListParams) -> (nat64) query; del_asset : (text, text) -> (); del_assets : (text) -> (); del_controllers : (DeleteControllersArgs) -> ( From b56b8ad0c7c7ffd505691b90654d09d2d11e8ee4 Mon Sep 17 00:00:00 2001 From: David Dal Busco Date: Sat, 24 Aug 2024 12:07:43 +0200 Subject: [PATCH 3/3] test: counts Signed-off-by: David Dal Busco --- src/tests/satellite.datastore.spec.ts | 81 +++++++++++++++++++++------ src/tests/satellite.storage.spec.ts | 81 +++++++++++++++++++++------ 2 files changed, 126 insertions(+), 36 deletions(-) diff --git a/src/tests/satellite.datastore.spec.ts b/src/tests/satellite.datastore.spec.ts index 38d0c6382..3220fe754 100644 --- a/src/tests/satellite.datastore.spec.ts +++ b/src/tests/satellite.datastore.spec.ts @@ -1,5 +1,6 @@ import type { DbConfig, + ListParams, _SERVICE as SatelliteActor, SetRule } from '$declarations/satellite/satellite.did'; @@ -237,9 +238,9 @@ describe.each([{ memory: { Heap: null } }, { memory: { Stable: null } }])( }); it('should list documents according created_at timestamps', async () => { - const { list_docs } = actor; + const { list_docs, count_docs } = actor; - const { items_length, items } = await list_docs(TEST_COLLECTION, { + const paramsCreatedAt: ListParams = { matcher: toNullable(), order: toNullable({ desc: false, @@ -247,11 +248,15 @@ describe.each([{ memory: { Heap: null } }, { memory: { Stable: null } }])( }), owner: toNullable(), paginate: toNullable() - }); + }; + const { items_length, items } = await list_docs(TEST_COLLECTION, paramsCreatedAt); expect(items_length).toBe(10n); - const { items_length: items_length_from } = await list_docs(TEST_COLLECTION, { + const countCreatedAt = await count_docs(TEST_COLLECTION, paramsCreatedAt); + expect(countCreatedAt).toBe(10n); + + const paramsGreaterThan: ListParams = { matcher: toNullable({ key: toNullable(), description: toNullable(), @@ -263,11 +268,18 @@ describe.each([{ memory: { Heap: null } }, { memory: { Stable: null } }])( order: toNullable(), owner: toNullable(), paginate: toNullable() - }); + }; + const { items_length: items_length_from } = await list_docs( + TEST_COLLECTION, + paramsGreaterThan + ); expect(items_length_from).toBe(5n); - const { items_length: items_length_to } = await list_docs(TEST_COLLECTION, { + const countGreaterThan = await count_docs(TEST_COLLECTION, paramsGreaterThan); + expect(countGreaterThan).toBe(5n); + + const paramsLessThen: ListParams = { matcher: toNullable({ key: toNullable(), description: toNullable(), @@ -279,11 +291,15 @@ describe.each([{ memory: { Heap: null } }, { memory: { Stable: null } }])( order: toNullable(), owner: toNullable(), paginate: toNullable() - }); + }; + const { items_length: items_length_to } = await list_docs(TEST_COLLECTION, paramsLessThen); expect(items_length_to).toBe(4n); - const { items_length: items_length_between } = await list_docs(TEST_COLLECTION, { + const countLessThan = await count_docs(TEST_COLLECTION, paramsLessThen); + expect(countLessThan).toBe(4n); + + const paramsBetween: ListParams = { matcher: toNullable({ key: toNullable(), description: toNullable(), @@ -295,15 +311,22 @@ describe.each([{ memory: { Heap: null } }, { memory: { Stable: null } }])( order: toNullable(), owner: toNullable(), paginate: toNullable() - }); + }; + const { items_length: items_length_between } = await list_docs( + TEST_COLLECTION, + paramsBetween + ); expect(items_length_between).toBe(5n); + + const countBetween = await count_docs(TEST_COLLECTION, paramsBetween); + expect(countBetween).toBe(5n); }); it('should list documents according updated_at timestamps', async () => { - const { list_docs } = actor; + const { list_docs, count_docs } = actor; - const { items_length, items } = await list_docs(TEST_COLLECTION, { + const paramsUpdatedAt: ListParams = { matcher: toNullable(), order: toNullable({ desc: false, @@ -311,11 +334,15 @@ describe.each([{ memory: { Heap: null } }, { memory: { Stable: null } }])( }), owner: toNullable(), paginate: toNullable() - }); + }; + const { items_length, items } = await list_docs(TEST_COLLECTION, paramsUpdatedAt); expect(items_length).toBe(10n); - const { items_length: items_length_from } = await list_docs(TEST_COLLECTION, { + const countUpdatedAt = await count_docs(TEST_COLLECTION, paramsUpdatedAt); + expect(countUpdatedAt).toBe(10n); + + const paramsGreaterThan: ListParams = { matcher: toNullable({ key: toNullable(), description: toNullable(), @@ -327,11 +354,18 @@ describe.each([{ memory: { Heap: null } }, { memory: { Stable: null } }])( order: toNullable(), owner: toNullable(), paginate: toNullable() - }); + }; + const { items_length: items_length_from } = await list_docs( + TEST_COLLECTION, + paramsGreaterThan + ); expect(items_length_from).toBe(5n); - const { items_length: items_length_to } = await list_docs(TEST_COLLECTION, { + const countGreaterThan = await count_docs(TEST_COLLECTION, paramsGreaterThan); + expect(countGreaterThan).toBe(5n); + + const paramsLessThan: ListParams = { matcher: toNullable({ key: toNullable(), description: toNullable(), @@ -343,11 +377,15 @@ describe.each([{ memory: { Heap: null } }, { memory: { Stable: null } }])( order: toNullable(), owner: toNullable(), paginate: toNullable() - }); + }; + const { items_length: items_length_to } = await list_docs(TEST_COLLECTION, paramsLessThan); expect(items_length_to).toBe(4n); - const { items_length: items_length_between } = await list_docs(TEST_COLLECTION, { + const countLessThan = await count_docs(TEST_COLLECTION, paramsLessThan); + expect(countLessThan).toBe(4n); + + const paramsBetween: ListParams = { matcher: toNullable({ key: toNullable(), description: toNullable(), @@ -359,9 +397,16 @@ describe.each([{ memory: { Heap: null } }, { memory: { Stable: null } }])( order: toNullable(), owner: toNullable(), paginate: toNullable() - }); + }; + const { items_length: items_length_between } = await list_docs( + TEST_COLLECTION, + paramsBetween + ); expect(items_length_between).toBe(5n); + + const countBetween = await count_docs(TEST_COLLECTION, paramsBetween); + expect(countBetween).toBe(5n); }); }); diff --git a/src/tests/satellite.storage.spec.ts b/src/tests/satellite.storage.spec.ts index 0200781d4..d6b79b673 100644 --- a/src/tests/satellite.storage.spec.ts +++ b/src/tests/satellite.storage.spec.ts @@ -1,4 +1,5 @@ import type { + ListParams, _SERVICE as SatelliteActor, SetRule, StorageConfig @@ -774,9 +775,9 @@ describe('Satellite storage', () => { }); it('should list assets according created_at timestamps', async () => { - const { list_assets } = actor; + const { list_assets, count_assets } = actor; - const { items_length, items } = await list_assets(collection, { + const paramsCreatedAt: ListParams = { matcher: toNullable(), order: toNullable({ desc: false, @@ -784,11 +785,15 @@ describe('Satellite storage', () => { }), owner: toNullable(), paginate: toNullable() - }); + }; + const { items_length, items } = await list_assets(collection, paramsCreatedAt); expect(items_length).toBe(10n); - const { items_length: items_length_from } = await list_assets(collection, { + const countCreatedAt = await count_assets(collection, paramsCreatedAt); + expect(countCreatedAt).toBe(10n); + + const paramsGreaterThan: ListParams = { matcher: toNullable({ key: toNullable(), description: toNullable(), @@ -800,11 +805,18 @@ describe('Satellite storage', () => { order: toNullable(), owner: toNullable(), paginate: toNullable() - }); + }; + const { items_length: items_length_from } = await list_assets( + collection, + paramsGreaterThan + ); expect(items_length_from).toBe(5n); - const { items_length: items_length_to } = await list_assets(collection, { + const countGreaterThan = await count_assets(collection, paramsGreaterThan); + expect(countGreaterThan).toBe(5n); + + const paramsLessThan: ListParams = { matcher: toNullable({ key: toNullable(), description: toNullable(), @@ -816,11 +828,15 @@ describe('Satellite storage', () => { order: toNullable(), owner: toNullable(), paginate: toNullable() - }); + }; + const { items_length: items_length_to } = await list_assets(collection, paramsLessThan); expect(items_length_to).toBe(4n); - const { items_length: items_length_between } = await list_assets(collection, { + const countLessThan = await count_assets(collection, paramsLessThan); + expect(countLessThan).toBe(4n); + + const paramsBetween: ListParams = { matcher: toNullable({ key: toNullable(), description: toNullable(), @@ -832,15 +848,22 @@ describe('Satellite storage', () => { order: toNullable(), owner: toNullable(), paginate: toNullable() - }); + }; + const { items_length: items_length_between } = await list_assets( + collection, + paramsBetween + ); expect(items_length_between).toBe(5n); + + const countBetween = await count_assets(collection, paramsBetween); + expect(countBetween).toBe(5n); }); it('should list assets according updated_at timestamps', async () => { - const { list_assets } = actor; + const { list_assets, count_assets } = actor; - const { items_length, items } = await list_assets(collection, { + const paramsUpdatedAt: ListParams = { matcher: toNullable(), order: toNullable({ desc: false, @@ -848,11 +871,15 @@ describe('Satellite storage', () => { }), owner: toNullable(), paginate: toNullable() - }); + }; + const { items_length, items } = await list_assets(collection, paramsUpdatedAt); expect(items_length).toBe(10n); - const { items_length: items_length_from } = await list_assets(collection, { + const countUpdatedAt = await count_assets(collection, paramsUpdatedAt); + expect(countUpdatedAt).toBe(10n); + + const paramsGreaterThan: ListParams = { matcher: toNullable({ key: toNullable(), description: toNullable(), @@ -864,11 +891,18 @@ describe('Satellite storage', () => { order: toNullable(), owner: toNullable(), paginate: toNullable() - }); + }; + const { items_length: items_length_from } = await list_assets( + collection, + paramsGreaterThan + ); expect(items_length_from).toBe(5n); - const { items_length: items_length_to } = await list_assets(collection, { + const countGreaterThan = await count_assets(collection, paramsGreaterThan); + expect(countGreaterThan).toBe(5n); + + const paramsLessThan: ListParams = { matcher: toNullable({ key: toNullable(), description: toNullable(), @@ -880,11 +914,15 @@ describe('Satellite storage', () => { order: toNullable(), owner: toNullable(), paginate: toNullable() - }); + }; + const { items_length: items_length_to } = await list_assets(collection, paramsLessThan); expect(items_length_to).toBe(4n); - const { items_length: items_length_between } = await list_assets(collection, { + const countLessThan = await count_assets(collection, paramsLessThan); + expect(countLessThan).toBe(4n); + + const paramsBetween: ListParams = { matcher: toNullable({ key: toNullable(), description: toNullable(), @@ -896,9 +934,16 @@ describe('Satellite storage', () => { order: toNullable(), owner: toNullable(), paginate: toNullable() - }); + }; + const { items_length: items_length_between } = await list_assets( + collection, + paramsBetween + ); expect(items_length_between).toBe(5n); + + const countBetween = await count_assets(collection, paramsBetween); + expect(countBetween).toBe(5n); }); }); }