Value Query

When we originally introduced the StorageValue, we only exposed to you one field which you could manipulate, which is the Value type, which defines the type that will be stored.

But there are actually more ways you can configure the StorageValue to increase developer ergonomics.

Storage Value Definition

Let's look at the definition of a StorageValue:

#![allow(unused)]
fn main() {
pub struct StorageValue<
	Prefix,
	Value,
	QueryKind = OptionQuery,
	OnEmpty = GetDefault
>(_);
}

You can see the StorageValue expects 4 different generic parameters, two of which have default implementations, which means you don't need to define them unless you want to change the configuration.

Prefix

We have been able to hide the Prefix type from you so far because the #[pallet::storage] macro implements this for us auto-magically.

We won't go into detail about what exactly Prefix does, but the high level idea is that it contains metadata needed to be able to correctly, uniquely, and consistently read and write data into the merkle trie.

Those details are pretty low level, and something we can automatically implement for you with the macros. You should never need to do anything with Prefix, else you are probably doing something wrong.

Value

You already know how to use and implement Value for StorageValue, so we won't go into too much detail here.

I will note that not literally every object can be placed in storage. It must satisfy some traits, which we will learn later in the tutorial.

Query Kind

You can see the QueryKind parameter defaults to OptionQuery.

This is why when we query storage, we get an Option returned to us.

Now as we stated before, Runtime storage is ALWAYS an Option. It is always possible that some storage does not exist / is not set when we first try to query it. But as we showed in our Pallet so far, there is logic we can write to "hide" that fact from the user, like unwrap_or(0).

We can do this even more ergonomically by changing the QueryKind to ValueQuery.

#![allow(unused)]
fn main() {
#[pallet::storage]
pub(super) type CountForKitties<T: Config> = StorageValue<Value = u32, QueryKind = ValueQuery>;
}

In this case, all of our APIs change.

Now when you call get, you will directly return a value, and when you call set, you just need to pass the value, not an option.

Now you might ask: "What value do you get when you call get and there is no value stored?".

That is controlled by the OnEmpty type.

On Empty

As we noted above, the OnEmpty type defines the behavior of the QueryKind type.

When you call get, and the storage is empty, the OnEmpty configuration kicks in.

The default configuration for OnEmpty is GetDefault. This of course requires that the Value type must implement Default. But if it does, then you will get the following behavior:

#![allow(unused)]
fn main() {
assert!(CountForKitties::<T>::get() == u32::default());
}

For numbers, this value is normally zero, so simply setting QueryKind = ValueQuery gives you exactly the same behavior as what we programmed in our Pallet so far.

If your type does not implement Default, you can't use ValueQuery. A common example of this is the T::AccountId type, which purposefully has no default value, and thus is not compatible out of the box with ValueQuery.

You CAN modify OnEmpty to return a custom value, rather than Default, but we won't cover that here. Feel free to explore this idea on your own.

Your Turn

Update your CountForKitties to use QueryKind = ValueQuery.

This will affect the APIs for get and set, so also update your code to reflect those changes.

Tests

In this step we made a breaking change to our Pallet.

There are no new tests for this step, but you will need to go back through your existing tests and update your types.

Since this tutorial does not really focus on writing tests for your pallet, feel free to just copy the tests.rs file included in this step's solution and update your project with it.

#![allow(unused)]
fn main() {
use super::*;
use frame::prelude::*;

impl<T: Config> Pallet<T> {
	pub fn mint(owner: T::AccountId) -> DispatchResult {
		/* 🚧 TODO 🚧: Remove the `unwrap_or` which is not needed when using `ValueQuery`. */
		let current_count: u32 = CountForKitties::<T>::get().unwrap_or(0);
		let new_count = current_count.checked_add(1).ok_or(Error::<T>::TooManyKitties)?;
		/* 🚧 TODO 🚧: Remove the `Option` wrapper when setting the `new_count`. */
		CountForKitties::<T>::set(Some(new_count));
		Self::deposit_event(Event::<T>::Created { owner });
		Ok(())
	}
}
}
#![allow(unused)]
#![cfg_attr(not(feature = "std"), no_std)]

fn main() {
mod impls;
mod tests;

use frame::prelude::*;
pub use pallet::*;

#[frame::pallet(dev_mode)]
pub mod pallet {
	use super::*;

	#[pallet::pallet]
	pub struct Pallet<T>(core::marker::PhantomData<T>);

	#[pallet::config]
	pub trait Config: frame_system::Config {
		type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
	}

	#[pallet::storage]
	/* 🚧 TODO 🚧: Update this storage to use a `QueryKind` of `ValueQuery`. */
	pub(super) type CountForKitties<T: Config> = StorageValue<Value = u32>;

	#[pallet::event]
	#[pallet::generate_deposit(pub(super) fn deposit_event)]
	pub enum Event<T: Config> {
		Created { owner: T::AccountId },
	}

	#[pallet::error]
	pub enum Error<T> {
		TooManyKitties,
	}

	#[pallet::call]
	impl<T: Config> Pallet<T> {
		pub fn create_kitty(origin: OriginFor<T>) -> DispatchResult {
			let who = ensure_signed(origin)?;
			Self::mint(who)?;
			Ok(())
		}
	}
}
}
#![allow(unused)]
fn main() {
use super::*;
use frame::prelude::*;

impl<T: Config> Pallet<T> {
	pub fn mint(owner: T::AccountId) -> DispatchResult {
		let current_count: u32 = CountForKitties::<T>::get();
		let new_count = current_count.checked_add(1).ok_or(Error::<T>::TooManyKitties)?;
		CountForKitties::<T>::set(new_count);
		Self::deposit_event(Event::<T>::Created { owner });
		Ok(())
	}
}
}
#![allow(unused)]
#![cfg_attr(not(feature = "std"), no_std)]

fn main() {
mod impls;
mod tests;

use frame::prelude::*;
pub use pallet::*;

#[frame::pallet(dev_mode)]
pub mod pallet {
	use super::*;

	#[pallet::pallet]
	pub struct Pallet<T>(core::marker::PhantomData<T>);

	#[pallet::config]
	pub trait Config: frame_system::Config {
		type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
	}

	#[pallet::storage]
	pub(super) type CountForKitties<T: Config> = StorageValue<Value = u32, QueryKind = ValueQuery>;

	#[pallet::event]
	#[pallet::generate_deposit(pub(super) fn deposit_event)]
	pub enum Event<T: Config> {
		Created { owner: T::AccountId },
	}

	#[pallet::error]
	pub enum Error<T> {
		TooManyKitties,
	}

	#[pallet::call]
	impl<T: Config> Pallet<T> {
		pub fn create_kitty(origin: OriginFor<T>) -> DispatchResult {
			let who = ensure_signed(origin)?;
			Self::mint(who)?;
			Ok(())
		}
	}
}
}
#![allow(unused)]
fn main() {
// Tests for the Kitties Pallet.
//
// Normally this file would be split into two parts: `mock.rs` and `tests.rs`.
// The `mock.rs` file would contain all the setup code for our `TestRuntime`.
// Then `tests.rs` would only have the tests for our pallet.
// However, to minimize the project, these have been combined into this single file.
//
// Learn more about creating tests for Pallets:
// https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/guides/your_first_pallet/index.html

// This flag tells rust to only run this file when running `cargo test`.
#![cfg(test)]

use crate as pallet_kitties;
use crate::*;
use frame::deps::sp_io;
use frame::runtime::prelude::*;
use frame::testing_prelude::*;
use frame::traits::fungible::*;

type Balance = u64;
type Block = frame_system::mocking::MockBlock<TestRuntime>;

// In our "test runtime", we represent a user `AccountId` with a `u64`.
// This is just a simplification so that we don't need to generate a bunch of proper cryptographic
// public keys when writing tests. It is just easier to say "user 1 transfers to user 2".
// We create the constants `ALICE` and `BOB` to make it clear when we are representing users below.
const ALICE: u64 = 1;
const BOB: u64 = 2;

// Our blockchain tests only need 3 Pallets:
// 1. System: Which is included with every FRAME runtime.
// 2. PalletBalances: Which is manages your blockchain's native currency. (i.e. DOT on Polkadot)
// 3. PalletKitties: The pallet you are building in this tutorial!
construct_runtime! {
	pub struct TestRuntime {
		System: frame_system,
		PalletBalances: pallet_balances,
		PalletKitties: pallet_kitties,
	}
}

// Normally `System` would have many more configurations, but you can see that we use some macro
// magic to automatically configure most of the pallet for a "default test configuration".
#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
impl frame_system::Config for TestRuntime {
	type Block = Block;
	type AccountData = pallet_balances::AccountData<Balance>;
}

// Normally `pallet_balances` would have many more configurations, but you can see that we use some
// macro magic to automatically configure most of the pallet for a "default test configuration".
#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)]
impl pallet_balances::Config for TestRuntime {
	type AccountStore = System;
	type Balance = Balance;
}

// This is the configuration of our Pallet! If you make changes to the pallet's `trait Config`, you
// will also need to update this configuration to represent that.
impl pallet_kitties::Config for TestRuntime {
	type RuntimeEvent = RuntimeEvent;
}

// We need to run most of our tests using this function: `new_test_ext().execute_with(|| { ... });`
// It simulates the blockchain database backend for our tests.
// If you forget to include this and try to access your Pallet storage, you will get an error like:
// "`get_version_1` called outside of an Externalities-provided environment."
pub fn new_test_ext() -> sp_io::TestExternalities {
	frame_system::GenesisConfig::<TestRuntime>::default()
		.build_storage()
		.unwrap()
		.into()
}

#[test]
fn starting_template_is_sane() {
	new_test_ext().execute_with(|| {
		let event = Event::<TestRuntime>::Created { owner: ALICE };
		let _runtime_event: RuntimeEvent = event.into();
		let _call = Call::<TestRuntime>::create_kitty {};
		let result = PalletKitties::create_kitty(RuntimeOrigin::signed(BOB));
		assert_ok!(result);
	});
}

#[test]
fn system_and_balances_work() {
	// This test will just sanity check that we can access `System` and `PalletBalances`.
	new_test_ext().execute_with(|| {
		// We often need to set `System` to block 1 so that we can see events.
		System::set_block_number(1);
		// We often need to add some balance to a user to test features which needs tokens.
		assert_ok!(PalletBalances::mint_into(&ALICE, 100));
		assert_ok!(PalletBalances::mint_into(&BOB, 100));
	});
}

#[test]
fn create_kitty_checks_signed() {
	new_test_ext().execute_with(|| {
		// The `create_kitty` extrinsic should work when being called by a user.
		assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(ALICE)));
		// The `create_kitty` extrinsic should fail when being called by an unsigned message.
		assert_noop!(PalletKitties::create_kitty(RuntimeOrigin::none()), DispatchError::BadOrigin);
	})
}

#[test]
fn create_kitty_emits_event() {
	new_test_ext().execute_with(|| {
		// We need to set block number to 1 to view events.
		System::set_block_number(1);
		// Execute our call, and ensure it is successful.
		assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(ALICE)));
		// Assert the last event by our blockchain is the `Created` event with the correct owner.
		System::assert_last_event(Event::<TestRuntime>::Created { owner: 1 }.into());
	})
}

#[test]
fn count_for_kitties_created_correctly() {
	new_test_ext().execute_with(|| {
		// Querying storage before anything is set will return `0`.
		assert_eq!(CountForKitties::<TestRuntime>::get(), 0);
		// You can `set` the value using an `u32`.
		CountForKitties::<TestRuntime>::set(1337u32);
		// You can `put` the value directly with a `u32`.
		CountForKitties::<TestRuntime>::put(1337u32);
	})
}

#[test]
fn mint_increments_count_for_kitty() {
	new_test_ext().execute_with(|| {
		// Querying storage before anything is set will return `0`.
		assert_eq!(CountForKitties::<TestRuntime>::get(), 0);
		// Call `create_kitty` which will call `mint`.
		assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(ALICE)));
		// Now the storage should be `1`
		assert_eq!(CountForKitties::<TestRuntime>::get(), 1);
	})
}

#[test]
fn mint_errors_when_overflow() {
	new_test_ext().execute_with(|| {
		// Set the count to the largest value possible.
		CountForKitties::<TestRuntime>::set(u32::MAX);
		// `create_kitty` should not succeed because of safe math.
		assert_noop!(
			PalletKitties::create_kitty(RuntimeOrigin::signed(1)),
			Error::<TestRuntime>::TooManyKitties
		);
	})
}
}
diff --git a/src/impls.rs b/src/impls.rs
index 7277e36..b9b5548 100644
--- a/src/impls.rs
+++ b/src/impls.rs
@@ -3,8 +3,10 @@ use frame::prelude::*;
 
 impl<T: Config> Pallet<T> {
 	pub fn mint(owner: T::AccountId) -> DispatchResult {
+		/* 🚧 TODO 🚧: Remove the `unwrap_or` which is not needed when using `ValueQuery`. */
 		let current_count: u32 = CountForKitties::<T>::get().unwrap_or(0);
 		let new_count = current_count.checked_add(1).ok_or(Error::<T>::TooManyKitties)?;
+		/* 🚧 TODO 🚧: Remove the `Option` wrapper when setting the `new_count`. */
 		CountForKitties::<T>::set(Some(new_count));
 		Self::deposit_event(Event::<T>::Created { owner });
 		Ok(())
diff --git a/src/lib.rs b/src/lib.rs
index 2c11f46..eeb9724 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -19,6 +19,7 @@ pub mod pallet {
 	}
 
 	#[pallet::storage]
+	/* 🚧 TODO 🚧: Update this storage to use a `QueryKind` of `ValueQuery`. */
 	pub(super) type CountForKitties<T: Config> = StorageValue<Value = u32>;
 
 	#[pallet::event]
diff --git a/src/impls.rs b/src/impls.rs
index b9b5548..d283fd6 100644
--- a/src/impls.rs
+++ b/src/impls.rs
@@ -3,11 +3,9 @@ use frame::prelude::*;
 
 impl<T: Config> Pallet<T> {
 	pub fn mint(owner: T::AccountId) -> DispatchResult {
-		/* 🚧 TODO 🚧: Remove the `unwrap_or` which is not needed when using `ValueQuery`. */
-		let current_count: u32 = CountForKitties::<T>::get().unwrap_or(0);
+		let current_count: u32 = CountForKitties::<T>::get();
 		let new_count = current_count.checked_add(1).ok_or(Error::<T>::TooManyKitties)?;
-		/* 🚧 TODO 🚧: Remove the `Option` wrapper when setting the `new_count`. */
-		CountForKitties::<T>::set(Some(new_count));
+		CountForKitties::<T>::set(new_count);
 		Self::deposit_event(Event::<T>::Created { owner });
 		Ok(())
 	}
diff --git a/src/lib.rs b/src/lib.rs
index eeb9724..57baa0d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -19,8 +19,7 @@ pub mod pallet {
 	}
 
 	#[pallet::storage]
-	/* 🚧 TODO 🚧: Update this storage to use a `QueryKind` of `ValueQuery`. */
-	pub(super) type CountForKitties<T: Config> = StorageValue<Value = u32>;
+	pub(super) type CountForKitties<T: Config> = StorageValue<Value = u32, QueryKind = ValueQuery>;
 
 	#[pallet::event]
 	#[pallet::generate_deposit(pub(super) fn deposit_event)]
diff --git a/src/tests.rs b/src/tests.rs
index fd8e478..c95bb32 100644
--- a/src/tests.rs
+++ b/src/tests.rs
@@ -121,26 +121,24 @@ fn create_kitty_emits_event() {
 #[test]
 fn count_for_kitties_created_correctly() {
 	new_test_ext().execute_with(|| {
-		// Querying storage before anything is set will return `None`.
-		assert_eq!(CountForKitties::<TestRuntime>::get(), None);
-		// You can `set` the value using an `Option<u32>`.
-		CountForKitties::<TestRuntime>::set(Some(1337u32));
+		// Querying storage before anything is set will return `0`.
+		assert_eq!(CountForKitties::<TestRuntime>::get(), 0);
+		// You can `set` the value using an `u32`.
+		CountForKitties::<TestRuntime>::set(1337u32);
 		// You can `put` the value directly with a `u32`.
 		CountForKitties::<TestRuntime>::put(1337u32);
-		// Check that the value is now in storage.
-		assert_eq!(CountForKitties::<TestRuntime>::get(), Some(1337u32));
 	})
 }
 
 #[test]
 fn mint_increments_count_for_kitty() {
 	new_test_ext().execute_with(|| {
-		// Querying storage before anything is set will return `None`.
-		assert_eq!(CountForKitties::<TestRuntime>::get(), None);
+		// Querying storage before anything is set will return `0`.
+		assert_eq!(CountForKitties::<TestRuntime>::get(), 0);
 		// Call `create_kitty` which will call `mint`.
 		assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(ALICE)));
-		// Now the storage should be `Some(1)`
-		assert_eq!(CountForKitties::<TestRuntime>::get(), Some(1));
+		// Now the storage should be `1`
+		assert_eq!(CountForKitties::<TestRuntime>::get(), 1);
 	})
 }
 
@@ -148,7 +146,7 @@ fn mint_increments_count_for_kitty() {
 fn mint_errors_when_overflow() {
 	new_test_ext().execute_with(|| {
 		// Set the count to the largest value possible.
-		CountForKitties::<TestRuntime>::set(Some(u32::MAX));
+		CountForKitties::<TestRuntime>::set(u32::MAX);
 		// `create_kitty` should not succeed because of safe math.
 		assert_noop!(
 			PalletKitties::create_kitty(RuntimeOrigin::signed(1)),