# Store & Retrieve values with Maps

### Prerequisites

Before getting started, make sure you have the following ready:

1. You are generally familiar with command-line interfaces (CLI).
2. You have **installed Rust** and set up your development environment as described in one of the sources below:
   1. [Rust learn documentation](https://doc.rust-lang.org/book/ch01-01-installation.html)
   2. [Substrate documentation](https://docs.substrate.io/install/)
   3. [Rust-lang](https://www.rust-lang.org/tools/install)
3. We recommend going through both the [flipper](https://docs.ternoa.network/getting-started/ink-smartcontracts/start-building-your-first-smart-contract) & the [previous](https://docs.ternoa.network/build-1/ink-smartcontracts/store-and-retrieve-values-with-maps) tutorials.

In the [Develop the Counter smart contract section](https://docs.ternoa.network/build-1/ink-smartcontracts/develop-the-counter-smart-contract), you created a smart contract designed for the storage and retrieval of a singular numerical value. \
\
This tutorial demonstrates how to enhance your smart contract to handle a distinct number for each user by employing the Mapping type. \
\
The ink! language offers the Mapping type as a means to organize data in key-value pairs. For instance, the code below shows how to map a number to a specific user:

```rust
// Import the `Mapping` type
use ink::storage::Mapping;

#[ink(storage)]
pub struct MyContract {
  // Store a mapping from AccountIds to a u32
  my_map: Mapping<AccountId, u32>,
}
```

Using the `Mapping` data type allows you to maintain a distinct storage value for every key. In this tutorial, every AccountId serves as a unique key that is linked to a singular stored numeric value within `my_map`. \
\
Consequently, each user is limited to storing, increasing, and accessing the value tied to their specific `AccountId.`

### Initialize a `Mapping`

The initial step involves setting up the mapping between an `AccountId` and its corresponding stored value. This requires specifying both the mapping key and the value it is associated with. \
\
The example below demonstrates how to establish a `Mapping` and accessing a value:

```rust
#![cfg_attr(not(feature = "std"), no_std)]

#[ink::contract]
mod mycontract {
    use ink::storage::Mapping;

    #[ink(storage)]
    pub struct MyContract {
        // Store a mapping from AccountIds to a u32
        my_map: Mapping<AccountId, u32>,
    }

    impl MyContract {
        #[ink(constructor)]
        pub fn new(count: u32) -> Self {
            let mut my_map = Mapping::default();
            let caller = Self::env().caller();
            my_map.insert(&caller, &count);

            Self { my_map }
        }

        // Get the number associated with the caller's AccountId, if it exists
        #[ink(message)]
        pub fn get(&self) -> u32 {
            let caller = Self::env().caller();
            self.my_map.get(&caller).unwrap_or_default()
        }
    }
}
```

**Setting the Caller of the Contract**

In the example provided earlier, you may have observed the usage of the `Self::env().caller()` function. This function, which can be invoked at any point within the contract's logic, consistently identifies the entity calling the contract. It's crucial to distinguish between the contract caller and the origin caller. If a contract invoked by a user subsequently triggers another contract, the `Self::env().caller()` in this secondary contract refers to the first contract's address, not the initiating user's.

**Applying the Contract Caller Information**

Understanding the identity of the contract caller is beneficial in various contexts. For instance, `Self::env().caller()` can be leveraged to establish an access control mechanism that restricts users from interacting only with their data. Additionally, it can be utilized to record the contract's owner at the time of its deployment, as shown in the following example:

```rust
#![cfg_attr(not(feature = "std"), no_std)]

#[ink::contract]
mod my_contract {

    #[ink(storage)]
    pub struct MyContract {
        // Store a contract owner
        owner: AccountId,
    }

    impl MyContract {
        #[ink(constructor)]
        pub fn new() -> Self {
            Self {
                owner: Self::env().caller(),
            }
        }
        /* --snip-- */
    }
}
```

By storing the contract caller under the `owner` identifier, you can subsequently develop functions to verify if the present contract caller is the contract's owner.

### Add mapping to the smart contract <a href="#add-mapping-to-the-smart-contract" id="add-mapping-to-the-smart-contract"></a>

You are now ready to introduce a storage map to the `incrementer` contract.

To add a storage map to the `incrementer` contract:

1. Open a terminal shell on your computer, if needed.
2. Verify that you are in the `incrementer` project folder.
3. Open the `lib.rs` file in a text editor.
4. Import the `Mapping` type.

   ```rust
   #[ink::contract
   mod incrementer {
      use ink::storage::Mapping;
   ```
5. Add the mapping key from `AccountId` to the `i32` data type stored as `my_map`.

   ```rust
   pub struct Incrementer {
      value: i32,
      my_map: Mapping<AccountId, i32>,
   }
   ```
6. In the `new` constructor create a new `Mapping` and use that to initialize your contract.

   ```rust
   #[ink(constructor)]
   pub fn new(init_value: i32) -> Self {
      let mut my_map = Mapping::default();
      let caller = Self::env().caller();
      my_map.insert(&caller, &0);

      Self {
          value: init_value,
          my_map,
      }
   }
   ```
7. In the `default` constructor add a new default `Mapping` along with the already defined default `value`.

   ```rust
   #[ink(constructor)]
   pub fn default() -> Self {
   Self {
           value: 0,
           my_map: Mapping::default(),
       }
   }
   ```
8. Add a `get_mine()` function to read `my_map` using the Mapping API's `get()` method and return `my_map` for the contract caller.

   ```rust
   #[ink(message)]
   pub fn get_mine(&self) -> i32 {
       let caller = self.env().caller();
       self.my_map.get(&caller).unwrap_or_default()
   }
   ```
9. Add a new test to the initialize accounts.

   ```rust
   #[ink::test]
   fn my_map_works() {
      let contract = Incrementer::new(11);
      assert_eq!(contract.get(), 11);
      assert_eq!(contract.get_mine(), 0);
   }
   ```
10. Save your changes and close the file.
11. Use the `test` subcommand and `nightly` toolchain to test your work by running the following command:

    ```bash
    cargo test
    ```

    The command should display output similar to the following to indicate successful test completion:

    <pre data-overflow="wrap"><code>running 3 tests
    test incrementer::tests::default_works ... ok
    test incrementer::tests::it_works ... ok
    test incrementer::tests::my_map_works ... ok

    test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
    </code></pre>

### Enabling Values Modification  <a href="#insert-update-or-remove-values" id="insert-update-or-remove-values"></a>

The final step of the `Incrementer` contract involves empowering users to modify their specific values. \
\
This capability can be facilitated through the use of the Mapping API within the smart contract, which grants straightforward access to storage items. \
\
For instance, to replace an existing value for a storage item, you can utilize the `Mapping::insert()` function with a previously used key. Moreover, values can be updated by initially retrieving them from storage with `Mapping::get()`, followed by applying `Mapping::insert()` to input the new value. Should `Mapping::get()` find no current value for a specified key, it will return `None`. \
\
Given that the Mapping API offers unmediated access to storage, the `Mapping::remove()` function can be employed to eliminate the value associated with a particular key from storage. \
\
To add functions for inserting and removing values into the contract:

1. Open a terminal shell on your computer, if needed.
2. Verify that you are in the `incrementer` project folder.
3. Open the `lib.rs` file in a text editor.
4. Add an `inc_mine()` function that allows the contract caller to get the `my_map` storage item and insert an incremented `value` into the mapping.

   ```rust
   #[ink(message)]
   pub fn inc_mine(&mut self, by: i32) {
      let caller = self.env().caller();
      let my_value = self.get_mine();
      self.my_map.insert(caller, &(my_value + by));
   }
   ```
5. Add a `remove_mine()` function that allows the contract caller to clear the `my_map` storage item from storage.

   ```rust
   #[ink(message)]
   pub fn remove_mine(&self) {
      let caller = self.env().caller();
      self.my_map.remove(&caller)
   }
   ```
6. Add a new test to verify that the `inc_mine()` functions works as expected.

   ```rust
   #[ink::test]
   fn inc_mine_works() {
      let mut contract = Incrementer::new(11);
      assert_eq!(contract.get_mine(), 0);
      contract.inc_mine(5);
      assert_eq!(contract.get_mine(), 5);
      contract.inc_mine(5);
      assert_eq!(contract.get_mine(), 10);
   }
   ```
7. Add a new test to verify that the `remove_mine()` functions works as expected.

   ```rust
   #[ink::test]
   fn remove_mine_works() {
      let mut contract = Incrementer::new(11);
      assert_eq!(contract.get_mine(), 0);
      contract.inc_mine(5);
      assert_eq!(contract.get_mine(), 5);
      contract.remove_mine();
      assert_eq!(contract.get_mine(), 0);
   }
   ```
8. Check your work using the `test` subcommand:

   ```bash
   cargo test
   ```

   The command should display output similar to the following to indicate successful test completion:

   <pre data-overflow="wrap"><code>running 5 tests
   test incrementer::tests::default_works ... ok
   test incrementer::tests::it_works ... ok
   test incrementer::tests::remove_mine_works ... ok
   test incrementer::tests::inc_mine_works ... ok
   test incrementer::tests::my_map_works ... ok

   test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
   </code></pre>
