Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MIGRATING.md update / examples for type safe bounds #640

Merged
merged 6 commits into from
Feb 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 41 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,48 @@
# Changelog

# Changelog

## [Unreleased](https://github.com/CosmWasm/cw-plus/tree/HEAD)

[Full Changelog](https://github.com/CosmWasm/cw-plus/compare/v0.11.1...HEAD)
[Full Changelog](https://github.com/CosmWasm/cw-plus/compare/v0.12.0-alpha1...HEAD)

**Closed issues:**

- Incorrect Cw4ExecuteMsg used during remove\_hook [\#637](https://github.com/CosmWasm/cw-plus/issues/637)
- Make `Bound`s type safe [\#462](https://github.com/CosmWasm/cw-plus/issues/462)

**Merged pull requests:**

- Fix benchmarks \(after 1.58.1 update\) [\#639](https://github.com/CosmWasm/cw-plus/pull/639) ([maurolacy](https://github.com/maurolacy))
- Fix `remove_hook` helper [\#638](https://github.com/CosmWasm/cw-plus/pull/638) ([maurolacy](https://github.com/maurolacy))
- Type safe bounds [\#627](https://github.com/CosmWasm/cw-plus/pull/627) ([maurolacy](https://github.com/maurolacy))

## [v0.12.0-alpha1](https://github.com/CosmWasm/cw-plus/tree/v0.12.0-alpha1) (2022-01-27)

[Full Changelog](https://github.com/CosmWasm/cw-plus/compare/v0.11.1...v0.12.0-alpha1)

**Deprecated:**

- Remove `IntKey` with surrounding implementation [\#570](https://github.com/CosmWasm/cw-plus/issues/570)

**Closed issues:**

- Move all cw20 examples to new repo [\#578](https://github.com/CosmWasm/cw-plus/issues/578)
- Add more debug output from multi-test [\#575](https://github.com/CosmWasm/cw-plus/issues/575)

**Merged pull requests:**

- Update Rust to v1.54.0 in CI [\#636](https://github.com/CosmWasm/cw-plus/pull/636) ([maurolacy](https://github.com/maurolacy))
- Refactor cw2 spec readme [\#635](https://github.com/CosmWasm/cw-plus/pull/635) ([orkunkl](https://github.com/orkunkl))
- Fix tag consolidation for matching CHANGELOG entries [\#634](https://github.com/CosmWasm/cw-plus/pull/634) ([maurolacy](https://github.com/maurolacy))
- Ics20 contract rollback [\#633](https://github.com/CosmWasm/cw-plus/pull/633) ([ethanfrey](https://github.com/ethanfrey))
- Fix typo in README.md [\#632](https://github.com/CosmWasm/cw-plus/pull/632) ([josefrichter](https://github.com/josefrichter))
- Update ics20 contract [\#631](https://github.com/CosmWasm/cw-plus/pull/631) ([ethanfrey](https://github.com/ethanfrey))
- Publish snapshot map changelog [\#622](https://github.com/CosmWasm/cw-plus/pull/622) ([maurolacy](https://github.com/maurolacy))
- Remove `IntKey` and `TimestampKey` [\#620](https://github.com/CosmWasm/cw-plus/pull/620) ([ueco-jb](https://github.com/ueco-jb))
- Signed int key benchmarks [\#619](https://github.com/CosmWasm/cw-plus/pull/619) ([maurolacy](https://github.com/maurolacy))
- fix readme update coralnet to sandynet-1 [\#617](https://github.com/CosmWasm/cw-plus/pull/617) ([yubrew](https://github.com/yubrew))
- Publish `PrefixBound` [\#616](https://github.com/CosmWasm/cw-plus/pull/616) ([maurolacy](https://github.com/maurolacy))
- Move contracts to cw-tokens [\#613](https://github.com/CosmWasm/cw-plus/pull/613) ([ethanfrey](https://github.com/ethanfrey))
- Add context to multitest execution errors [\#597](https://github.com/CosmWasm/cw-plus/pull/597) ([uint](https://github.com/uint))

## [v0.11.1](https://github.com/CosmWasm/cw-plus/tree/v0.11.1) (2021-12-28)

Expand Down
52 changes: 52 additions & 0 deletions MIGRATING.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,58 @@

This guide lists API changes between *cw-plus* major releases.

## v0.11.0 -> v0.12.0

### Breaking Issues / PRs

- Type safe `Bound`s [\#462](https://github.com/CosmWasm/cw-plus/issues/462)

Bounds are now type-safe. That means the bound type must match the key / sub-key you are ranging over.

Migration code example:

```diff
fn list_allowed(
deps: Deps,
start_after: Option<String>,
limit: Option<u32>,
) -> StdResult<ListAllowedResponse> {
let limit = limit.unwrap_or(DEFAULT_LIMIT).min(MAX_LIMIT) as usize;
- let start = match start_after {
- Some(x) => Some(Bound::exclusive(deps.api.addr_validate(&x)?.into_string())),
- None => None,
- };
+ let addr = maybe_addr(deps.api, start_after)?;
+ let start = addr.as_ref().map(Bound::exclusive);

let allow = ALLOW_LIST
.range(deps.storage, start, None, Order::Ascending)
```
Here the `ALLOW_LIST` key is of type `&Addr`. That's why we use `as_ref()` before the `map()` that builds the bound.
maurolacy marked this conversation as resolved.
Show resolved Hide resolved
Notice also that this "forces" you to use `addr_validate()`, in order to build a bound over the proper type.

You can still use untyped bounds, with the `ExclusiveRaw` and `InclusiveRaw` enum types.
Migration code example, in case you want to keep your raw bounds:

```diff
pub fn query_all_allowances(
deps: Deps,
env: Env,
start_after: Option<String>,
limit: Option<u32>,
) -> StdResult<AllAllowancesResponse> {
let limit = calc_limit(limit);
// we use raw addresses here....
- let start = start_after.map(Bound::exclusive);
+ let start = start_after.map(|s| Bound::ExclusiveRaw(s.into()));

let allowances = ALLOWANCES
.range(deps.storage, start, None, Order::Ascending)
```
Notice that here we build a bound for an address, and using a raw bound allows us to skip address validation / build up.

See storage-plus [README.md](./packages/storage-plus/README.md#Bound) for more information on `Bound`.

## v0.10.3 -> v0.11.0

### Breaking Issues / PRs
Expand Down
2 changes: 1 addition & 1 deletion contracts/cw20-base/src/enumerable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pub fn query_all_allowances(
) -> StdResult<AllAllowancesResponse> {
let owner_addr = deps.api.addr_validate(&owner)?;
let limit = limit.unwrap_or(DEFAULT_LIMIT).min(MAX_LIMIT) as usize;
let start = start_after.map(|s| Bound::ExclusiveRaw(s.as_bytes().into()));
let start = start_after.map(|s| Bound::ExclusiveRaw(s.into_bytes()));
maurolacy marked this conversation as resolved.
Show resolved Hide resolved

let allowances = ALLOWANCES
.prefix(&owner_addr)
Expand Down
43 changes: 25 additions & 18 deletions packages/storage-plus/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -314,29 +314,36 @@ fn demo() -> StdResult<()> {

In addition to getting one particular item out of a map, we can iterate over the map
(or a subset of the map). This let us answer questions like "show me all tokens",
and we provide some nice `Bound`s helpers to easily allow pagination or custom ranges.
and we provide some nice [`Bound`](#Bound) helpers to easily allow pagination or custom ranges.

The general format is to get a `Prefix` by calling `map.prefix(k)`, where `k` is exactly
one less item than the normal key (If `map.key()` took `(&[u8], &[u8])`, then `map.prefix()` takes `&[u8]`.
If `map.key()` took `&[u8]`, `map.prefix()` takes `()`). Once we have a prefix space, we can iterate
over all items with `range(store, min, max, order)`. It supports `Order::Ascending` or `Order::Descending`.
`min` is the lower bound and `max` is the higher bound.

If the `min` and `max` bounds are `None`, `range` will return all items under the prefix. You can use `.take(n)` to
limit the results to `n` items and start doing pagination. You can also set the `min` bound to
eg. `Bound::exclusive(last_value)` to start iterating over all items *after* the last value. Combined with
`take`, we easily have pagination support. You can also use `Bound::inclusive(x)` when you want to include any
perfect matches.

### Bound

`Bound` is a helper to build type-safe bounds on the keys or sub-keys you want to iterate over.
It also supports a raw (`Vec<u8>`) bounds specification, for the cases you don't want or can't use typed bounds.

```rust
#[derive(Copy, Clone, Debug)]
pub enum Bound {
Inclusive(Vec<u8>),
Exclusive(Vec<u8>),
None,
#[derive(Clone, Debug)]
pub enum Bound<'a, K: PrimaryKey<'a>> {
Inclusive((K, PhantomData<&'a bool>)),
Exclusive((K, PhantomData<&'a bool>)),
InclusiveRaw(Vec<u8>),
ExclusiveRaw(Vec<u8>),
}
```

If the `min` and `max` bounds, it will return all items under this prefix. You can use `.take(n)` to
limit the results to `n` items and start doing pagination. You can also set the `min` bound to
eg. `Bound::Exclusive(last_value)` to start iterating over all items *after* the last value. Combined with
`take`, we easily have pagination support. You can also use `Bound::Inclusive(x)` when you want to include any
perfect matches. To better understand the API, please read the following example:

To better understand the API, please read the following example:
```rust
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
struct Data {
Expand All @@ -358,7 +365,7 @@ fn demo() -> StdResult<()> {

// iterate over them all
let all: StdResult<Vec<_>> = PEOPLE
.range(&store, Bound::None, Bound::None, Order::Ascending)
.range(&store, None, None, Order::Ascending)
.collect();
assert_eq!(
all?,
Expand All @@ -369,8 +376,8 @@ fn demo() -> StdResult<()> {
let all: StdResult<Vec<_>> = PEOPLE
.range(
&store,
Bound::Exclusive("jim"),
Bound::None,
Some(Bound::exclusive("jim")),
None,
Order::Ascending,
)
.collect();
Expand All @@ -384,7 +391,7 @@ fn demo() -> StdResult<()> {
// get all under one key
let all: StdResult<Vec<_>> = ALLOWANCE
.prefix("owner")
.range(&store, Bound::None, Bound::None, Order::Ascending)
.range(&store, None, None, Order::Ascending)
.collect();
assert_eq!(
all?,
Expand All @@ -396,8 +403,8 @@ fn demo() -> StdResult<()> {
.prefix("owner")
.range(
&store,
Bound::Exclusive("spender1"),
Bound::Inclusive("spender2"),
Some(Bound::exclusive("spender1")),
Some(Bound::inclusive("spender2")),
Order::Descending,
)
.collect();
Expand Down