Skip to content

storage-plus: Need better docs and examples for IndexedMap #327

@orkunkl

Description

@orkunkl

I am testing out IndexedMap as workshop and article content.
I found Index and prefixes under documented and not enough tests to understand as a noobie.

For example here is a sample code I written to show an CompositeKey example.

Tokens are secondary indexed by (admin, ticker) composite key.

pub const TOKEN_COUNT: Item<u64> = Item::new("num_tokens");

pub fn num_tokens(storage: &dyn Storage) -> StdResult<u64> {
    Ok(TOKEN_COUNT.may_load(storage)?.unwrap_or_default())
}

pub fn increment_tokens(storage: &mut dyn Storage) -> StdResult<u64> {
    let val = num_tokens(storage)? + 1;
    TOKEN_COUNT.save(storage, &val)?;
    Ok(val)
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct Token {
    pub admin: Addr,
    pub ticker: String
}

pub struct TokenIndexes<'a> {
    // indexed by admin_ticker composite key
    // last U64Key is the primary key which is auto incremented token counter
    pub admin_ticker: MultiIndex<'a, (Vec<u8>, Vec<u8>, Vec<u8>), Token>,
}

// this may become macro, not important just boilerplate, builds the list of indexes for later use
impl<'a> IndexList<Token> for TokenIndexes<'a> {
    fn get_indexes(&'_ self) -> Box<dyn Iterator<Item = &'_ dyn Index<Token>> + '_> {
        let v: Vec<&dyn Index<Token>> = vec![&self.admin_ticker];
        Box::new(v.into_iter())
    }
}

const TOKEN_NAMESPACE: &str = "tokens";

pub fn tokens<'a>() -> IndexedMap<'a, &'a [u8], Token, TokenIndexes<'a>> {
    let indexes = TokenIndexes {
        admin_ticker: MultiIndex::new(
            |d, k| (index_string(d.admin.as_ref()), index_string(&d.ticker), k),
            TOKEN_NAMESPACE,
            "tokens__admin_ticker",
        )
    };
    IndexedMap::new(TOKEN_NAMESPACE, indexes)
}

Here are some tests to show what I want to achieve.

    #[test]
    fn test_tokens() {
        let mut store = MockStorage::new();

        let admin1 = Addr::unchecked("addr1");
        let ticker1 = "TOKEN1".to_string();
        let token1 = Token {
            admin: admin1,
            ticker: ticker1
        };

        let token_id = increment_tokens(store.borrow_mut()).unwrap();
        tokens().save(store.borrow_mut(), &U64Key::from(token_id).joined_key(), &token1).unwrap();

        // want to load token using admin1 and ticker1
        tokens().idx.admin_ticker.?
    }

Can you help me understand this case with few examples maybe?

Metadata

Metadata

Assignees

Labels

documentationImprovements or additions to documentation

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions