Skip to content

Commit dfbe97f

Browse files
authored
Add counter to collection and map views (#4616)
## Motivation Add some missing APIs + improve GraphQL code for collections ## Proposal * support count() for collections * make SetView similar to MapView (**GraphQL API breaking change**) * (nit) remove unnecessary Clone bounds ## Test Plan CI + tested manually ## Release Plan These changes should be backported to the latest `testnet` branch, then be released in a new SDK. (Note that the SDK will be breaking certain queries but that's ok)
1 parent 820e412 commit dfbe97f

File tree

8 files changed

+110
-51
lines changed

8 files changed

+110
-51
lines changed

linera-service-graphql-client/gql/service_schema.graphql

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,10 +229,12 @@ A block height to identify blocks in a chain
229229
scalar BlockHeight
230230

231231
type BucketQueueView_BlockHeight_e824a938 {
232+
count: Int!
232233
entries(count: Int): [BlockHeight!]!
233234
}
234235

235236
type BucketQueueView_TimestampedBundleInInbox_5a630c55 {
237+
count: Int!
236238
entries(count: Int): [TimestampedBundleInInbox!]!
237239
}
238240

@@ -368,7 +370,7 @@ type ChainStateExtendedView {
368370
"""
369371
Unskippable bundles that have been removed but are still in the queue.
370372
"""
371-
removedUnskippableBundles: [BundleInInbox!]!
373+
removedUnskippableBundles: SetView_BundleInInbox_092a4377!
372374
"""
373375
The heights of previous blocks that sent messages to the same recipients.
374376
"""
@@ -658,10 +660,12 @@ A scalar that can represent any JSON Object value.
658660
scalar JSONObject
659661

660662
type LogView_ChainAndHeight_7af83576 {
663+
count: Int!
661664
entries(start: Int, end: Int): [ChainAndHeight!]!
662665
}
663666

664667
type LogView_CryptoHash_87fbb60c {
668+
count: Int!
665669
entries(start: Int, end: Int): [CryptoHash!]!
666670
}
667671

@@ -707,42 +711,49 @@ input MapInput_StreamIdInput_b7c3909d {
707711

708712
type MapView_AccountOwner_Amount_11ef1379 {
709713
keys(count: Int): [AccountOwner!]!
714+
count: Int!
710715
entry(key: AccountOwner!): Entry_AccountOwner_Amount_aaf96548!
711716
entries(input: MapInput_AccountOwner_d6668c53): [Entry_AccountOwner_Amount_aaf96548!]!
712717
}
713718

714719
type MapView_BlobId_Blob_3711e760 {
715720
keys(count: Int): [BlobId!]!
721+
count: Int!
716722
entry(key: BlobId!): Entry_BlobId_Blob_9f0b41f3!
717723
entries(input: MapInput_BlobId_4d2a0555): [Entry_BlobId_Blob_9f0b41f3!]!
718724
}
719725

720726
type MapView_BlobId_Blob_9f0b41f3 {
721727
keys(count: Int): [BlobId!]!
728+
count: Int!
722729
entry(key: BlobId!): Entry_BlobId_Blob_50b95aa1!
723730
entries(input: MapInput_BlobId_4d2a0555): [Entry_BlobId_Blob_50b95aa1!]!
724731
}
725732

726733
type MapView_BlockHeight_CryptoHash_1bae6d76 {
727734
keys(count: Int): [BlockHeight!]!
735+
count: Int!
728736
entry(key: BlockHeight!): Entry_BlockHeight_CryptoHash_74e16b71!
729737
entries(input: MapInput_BlockHeight_e824a938): [Entry_BlockHeight_CryptoHash_74e16b71!]!
730738
}
731739

732740
type MapView_ChainId_BlockHeight_f2e56e12 {
733741
keys(count: Int): [ChainId!]!
742+
count: Int!
734743
entry(key: ChainId!): Entry_ChainId_BlockHeight_2fe78645!
735744
entries(input: MapInput_ChainId_37f83aa9): [Entry_ChainId_BlockHeight_2fe78645!]!
736745
}
737746

738747
type MapView_StreamId_BlockHeight_e6657ad9 {
739748
keys(count: Int): [StreamId!]!
749+
count: Int!
740750
entry(key: StreamIdInput!): Entry_StreamId_BlockHeight_50cd702e!
741751
entries(input: MapInput_StreamIdInput_b7c3909d): [Entry_StreamId_BlockHeight_50cd702e!]!
742752
}
743753

744754
type MapView_StreamId_Int_3d7f5335 {
745755
keys(count: Int): [StreamId!]!
756+
count: Int!
746757
entry(key: StreamIdInput!): Entry_StreamId_Int_459c4ec3!
747758
entries(input: MapInput_StreamIdInput_b7c3909d): [Entry_StreamId_Int_459c4ec3!]!
748759
}
@@ -1249,23 +1260,27 @@ type QueryRoot {
12491260
}
12501261

12511262
type QueueView_MessageBundle_f4399f0b {
1263+
count: Int!
12521264
entries(count: Int): [MessageBundle!]!
12531265
}
12541266

12551267
type ReentrantCollectionView_AccountOwner_PendingBlobsView_d58d342d {
12561268
keys: [AccountOwner!]!
1269+
count: Int!
12571270
entry(key: AccountOwner!): Entry_AccountOwner_PendingBlobsView_5d91edcf!
12581271
entries(input: MapInput_AccountOwner_d6668c53): [Entry_AccountOwner_PendingBlobsView_5d91edcf!]!
12591272
}
12601273

12611274
type ReentrantCollectionView_ChainId_InboxStateView_466640be {
12621275
keys: [ChainId!]!
1276+
count: Int!
12631277
entry(key: ChainId!): Entry_ChainId_InboxStateView_a9e4d828!
12641278
entries(input: MapInput_ChainId_37f83aa9): [Entry_ChainId_InboxStateView_a9e4d828!]!
12651279
}
12661280

12671281
type ReentrantCollectionView_ChainId_OutboxStateView_06c2376d {
12681282
keys: [ChainId!]!
1283+
count: Int!
12691284
entry(key: ChainId!): Entry_ChainId_OutboxStateView_855dcf53!
12701285
entries(input: MapInput_ChainId_37f83aa9): [Entry_ChainId_OutboxStateView_855dcf53!]!
12711286
}
@@ -1280,6 +1295,11 @@ A number to identify successive attempts to decide a value in a consensus protoc
12801295
"""
12811296
scalar Round
12821297

1298+
type SetView_BundleInInbox_092a4377 {
1299+
elements(count: Int): [BundleInInbox!]!
1300+
count: Int!
1301+
}
1302+
12831303
"""
12841304
An event stream ID.
12851305
"""

linera-views/src/views/bucket_queue_view.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,11 @@ mod graphql {
746746
C: Send + Sync,
747747
T: serde::ser::Serialize + serde::de::DeserializeOwned + Clone + Send + Sync,
748748
{
749+
#[graphql(derived(name = "count"))]
750+
async fn count_(&self) -> Result<u32, async_graphql::Error> {
751+
Ok(self.count() as u32)
752+
}
753+
749754
async fn entries(&self, count: Option<usize>) -> async_graphql::Result<Vec<T>> {
750755
Ok(self
751756
.read_front(count.unwrap_or_else(|| self.count()))

linera-views/src/views/collection_view.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1152,7 +1152,7 @@ impl<I: DeserializeOwned, W: View> CollectionView<W::Context, I, W> {
11521152

11531153
impl<I, W: HashableView> HashableView for CollectionView<W::Context, I, W>
11541154
where
1155-
I: Clone + Send + Sync + Serialize + DeserializeOwned,
1155+
I: Send + Sync + Serialize + DeserializeOwned,
11561156
{
11571157
type Hasher = sha3::Sha3_256;
11581158

@@ -1615,6 +1615,11 @@ mod graphql {
16151615
Ok(self.indices().await?)
16161616
}
16171617

1618+
#[graphql(derived(name = "count"))]
1619+
async fn count_(&self) -> Result<u32, async_graphql::Error> {
1620+
Ok(self.count().await? as u32)
1621+
}
1622+
16181623
async fn entry(
16191624
&self,
16201625
key: K,
@@ -1675,6 +1680,11 @@ mod graphql {
16751680
Ok(self.indices().await?)
16761681
}
16771682

1683+
#[graphql(derived(name = "count"))]
1684+
async fn count_(&self) -> Result<u32, async_graphql::Error> {
1685+
Ok(self.count().await? as u32)
1686+
}
1687+
16781688
async fn entry(
16791689
&self,
16801690
key: K,

linera-views/src/views/log_view.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,11 @@ mod graphql {
398398
where
399399
T: serde::ser::Serialize + serde::de::DeserializeOwned + Clone + Send + Sync,
400400
{
401+
#[graphql(derived(name = "count"))]
402+
async fn count_(&self) -> Result<u32, async_graphql::Error> {
403+
Ok(self.count() as u32)
404+
}
405+
401406
async fn entries(
402407
&self,
403408
start: Option<usize>,

linera-views/src/views/map_view.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2083,6 +2083,11 @@ mod graphql {
20832083
})
20842084
}
20852085

2086+
#[graphql(derived(name = "count"))]
2087+
async fn count_(&self) -> Result<u32, async_graphql::Error> {
2088+
Ok(self.count().await? as u32)
2089+
}
2090+
20862091
async fn entry(&self, key: I) -> Result<Entry<I, Option<V>>, async_graphql::Error> {
20872092
Ok(Entry {
20882093
value: self.get(&key).await?,

linera-views/src/views/queue_view.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,11 @@ mod graphql {
503503
where
504504
T: serde::ser::Serialize + serde::de::DeserializeOwned + Clone + Send + Sync,
505505
{
506+
#[graphql(derived(name = "count"))]
507+
async fn count_(&self) -> Result<u32, async_graphql::Error> {
508+
Ok(self.count() as u32)
509+
}
510+
506511
async fn entries(&self, count: Option<usize>) -> async_graphql::Result<Vec<T>> {
507512
Ok(self
508513
.read_front(count.unwrap_or_else(|| self.count()))

linera-views/src/views/reentrant_collection_view.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2122,6 +2122,11 @@ mod graphql {
21222122
Ok(self.indices().await?)
21232123
}
21242124

2125+
#[graphql(derived(name = "count"))]
2126+
async fn count_(&self) -> Result<u32, async_graphql::Error> {
2127+
Ok(self.count().await? as u32)
2128+
}
2129+
21252130
async fn entry(
21262131
&self,
21272132
key: K,

linera-views/src/views/set_view.rs

Lines changed: 53 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -795,7 +795,7 @@ where
795795
impl<C, I> CustomSetView<C, I>
796796
where
797797
C: Context,
798-
I: Sync + Clone + Send + CustomSerialize,
798+
I: Sync + Send + CustomSerialize,
799799
{
800800
/// Returns the list of indices in the set. The order is determined by the custom
801801
/// serialization.
@@ -939,70 +939,74 @@ pub type HashedCustomSetView<C, I> =
939939
mod graphql {
940940
use std::borrow::Cow;
941941

942+
use serde::{de::DeserializeOwned, Serialize};
943+
942944
use super::{CustomSetView, SetView};
943-
use crate::context::Context;
945+
use crate::{
946+
common::CustomSerialize,
947+
context::Context,
948+
graphql::{hash_name, mangle},
949+
};
944950

945-
impl<C: Context, I: async_graphql::OutputType> async_graphql::OutputType for SetView<C, I>
946-
where
947-
I: serde::ser::Serialize + serde::de::DeserializeOwned + Clone + Send + Sync,
948-
{
951+
impl<C: Send + Sync, I: async_graphql::OutputType> async_graphql::TypeName for SetView<C, I> {
949952
fn type_name() -> Cow<'static, str> {
950-
format!("[{}]", I::qualified_type_name()).into()
953+
format!(
954+
"SetView_{}_{:08x}",
955+
mangle(I::type_name()),
956+
hash_name::<I>(),
957+
)
958+
.into()
951959
}
960+
}
952961

953-
fn qualified_type_name() -> String {
954-
format!("[{}]!", I::qualified_type_name())
962+
#[async_graphql::Object(cache_control(no_cache), name_type)]
963+
impl<C, I> SetView<C, I>
964+
where
965+
C: Context,
966+
I: Send + Sync + Serialize + DeserializeOwned + async_graphql::OutputType,
967+
{
968+
async fn elements(&self, count: Option<usize>) -> Result<Vec<I>, async_graphql::Error> {
969+
let mut indices = self.indices().await?;
970+
if let Some(count) = count {
971+
indices.truncate(count);
972+
}
973+
Ok(indices)
955974
}
956975

957-
fn create_type_info(registry: &mut async_graphql::registry::Registry) -> String {
958-
I::create_type_info(registry);
959-
Self::qualified_type_name()
976+
#[graphql(derived(name = "count"))]
977+
async fn count_(&self) -> Result<u32, async_graphql::Error> {
978+
Ok(self.count().await? as u32)
960979
}
980+
}
961981

962-
async fn resolve(
963-
&self,
964-
ctx: &async_graphql::ContextSelectionSet<'_>,
965-
field: &async_graphql::Positioned<async_graphql::parser::types::Field>,
966-
) -> async_graphql::ServerResult<async_graphql::Value> {
967-
let indices = self
968-
.indices()
969-
.await
970-
.map_err(|e| async_graphql::Error::from(e).into_server_error(ctx.item.pos))?;
971-
let indices_len = indices.len();
972-
async_graphql::resolver_utils::resolve_list(ctx, field, indices, Some(indices_len))
973-
.await
982+
impl<C: Send + Sync, I: async_graphql::OutputType> async_graphql::TypeName for CustomSetView<C, I> {
983+
fn type_name() -> Cow<'static, str> {
984+
format!(
985+
"CustomSetView_{}_{:08x}",
986+
mangle(I::type_name()),
987+
hash_name::<I>(),
988+
)
989+
.into()
974990
}
975991
}
976992

977-
impl<C: Context, I: async_graphql::OutputType> async_graphql::OutputType for CustomSetView<C, I>
993+
#[async_graphql::Object(cache_control(no_cache), name_type)]
994+
impl<C, I> CustomSetView<C, I>
978995
where
979-
I: crate::common::CustomSerialize + Clone + Send + Sync,
996+
C: Context,
997+
I: Send + Sync + CustomSerialize + async_graphql::OutputType,
980998
{
981-
fn type_name() -> Cow<'static, str> {
982-
format!("[{}]", I::qualified_type_name()).into()
983-
}
984-
985-
fn qualified_type_name() -> String {
986-
format!("[{}]!", I::qualified_type_name())
987-
}
988-
989-
fn create_type_info(registry: &mut async_graphql::registry::Registry) -> String {
990-
I::create_type_info(registry);
991-
Self::qualified_type_name()
999+
async fn elements(&self, count: Option<usize>) -> Result<Vec<I>, async_graphql::Error> {
1000+
let mut indices = self.indices().await?;
1001+
if let Some(count) = count {
1002+
indices.truncate(count);
1003+
}
1004+
Ok(indices)
9921005
}
9931006

994-
async fn resolve(
995-
&self,
996-
ctx: &async_graphql::ContextSelectionSet<'_>,
997-
field: &async_graphql::Positioned<async_graphql::parser::types::Field>,
998-
) -> async_graphql::ServerResult<async_graphql::Value> {
999-
let indices = self
1000-
.indices()
1001-
.await
1002-
.map_err(|e| async_graphql::Error::from(e).into_server_error(ctx.item.pos))?;
1003-
let indices_len = indices.len();
1004-
async_graphql::resolver_utils::resolve_list(ctx, field, indices, Some(indices_len))
1005-
.await
1007+
#[graphql(derived(name = "count"))]
1008+
async fn count_(&self) -> Result<u32, async_graphql::Error> {
1009+
Ok(self.count().await? as u32)
10061010
}
10071011
}
10081012
}

0 commit comments

Comments
 (0)