Some things to note
- The table datatype is not native to the Move smart contract language.
- Tables is a type that is a part of the Aptos framework.
- You will have to import the Aptos framework to work with this
Lets make a real estate management smart contract that stores properties under sellers.
Imports
use aptos_framework::table::{Self, Table};
use std::signer;
use std::string::String;
We gotta import the table::{Self, Table}
from the aptos framework to be able to use it.
The signer is needed to be able to use the move_to
functionality to push the table to the sellers account.
The string import is for storing the address strings in the property struct.
Making our structure to store property data
struct Property has store, copy, drop {
baths: u16,
beds: u16,
sqm: u16,
phy_addr: String,
price: u64,
available: bool
}
Pretty self explanatory. We are making a struct Property that describes the house.
PropList
for storing multiple properties under a single seller
Since there are going to be multiple houses under a single seller, we need a key to be able to access them. To do that, we need another struct with the key attribute, like this:
struct PropList has key {
info: Table<u64, Property>,
prop_id: u64
}
We just need to use the prop_id
to be able to traverse through the multiple properties a seller might have.
Now, moving on to the functions:
Registering a seller
fun register_seller(account: &signer) {
let init_property = PropList {
info: table::new(),
prop_id: 0
};
move_to(account, init_property);
}
This bit of code takes the reference to some account’s signer, makes a new PropList
for them and then moves the PropList
into their account.
Now, to list new properties:
Listing new properties under a seller
fun list_property(account: &signer, prop_info: Property)
acquires PropList {
let account_addr = signer::address_of(account);
assert!(exists<PropList>(account_addr) == true, 404);
let prop_list = borrow_global_mut<PropList>(account_addr);
let new_id = prop_list.prop_id + 1;
table::upsert(&mut prop_list.info, new_id, prop_info);
prop_list.prop_id = new_id;
}
We take the account (another reference to their signer), and a Property
type as the input for this function. It needs to acquire PropList
, since we are working with it.
We are then acquiring the address of the seller using the signer::address_of(account);
function.
We check if the PropList
exists using the assert.
We then retrieve a mutable version of the PropList
from the seller using the borrow_global_mut
method.
prop_id
is set to 0 by default, when we initialize a user. We need to increment it by 1 every time we add a new property to a seller’s list.
We then use the table::upsert(&mut prop_list.info, prop_info
) to add a new entry to the PropList
.
Reading Property info
fun read_property(account: &signer, prop_id: u64): (u16, u16, u16, String, u64, bool) //Gives you the info as a tuple
acquires PropList {
let account_addr = signer::address_of(account);
assert!(exists<PropList>(account_addr) == true, 404);
let prop_list = borrow_global<PropList>(account_addr);
let info = table::borrow(&prop_list.info, prop_id);
return (info.beds, info.baths, info.sqm, info.phy_addr, info.price, info.available)
}
Function takes in the signer as a reference and the prop_id that you need to check, and then returns a bunch of data as a tuple as described. It needs to acquire PropList
.
First, you need to borrow the table from the seller’s PropList
immutably into a variable called prop_list
. Then you need to borrow the data under the id into the info
variable using the table::borrow
function. The info
variable is now a Property
struct. You can unpack it into a tuple in the return statement as shown.
Testing
#[test_only]
use std::debug::print;
#[test_only]
use std::string::{utf8};
#[test(seller1 = @0x123, seller2 = @0x124)]
fun test_function(seller1: &signer, seller2: &signer) acquires PropList {
register_seller(seller1);
let prop_info = Property {
baths: 2,
beds: 3,
sqm: 110,
phy_addr: utf8(b"123 Main St, Montevideo, Uruguay"),
price: 120000,
available: true
};
list_property(seller1, prop_info);
let (_,_,_,location,_,_) = read_property(seller1, 1);
print(&location);
register_seller(seller2);
let prop_info2 = Property {
baths: 3,
beds: 3,
sqm: 140,
phy_addr: utf8(b"14 Ave, Berlin, Germany"),
price: 150000,
available: true
};
list_property(seller2, prop_info2);
let (_,_,_,_,price,_) = read_property(seller2, 1);
print(&price);
let (_,_,_,location,_,_) = read_property(seller2, 1);
print(&location);
}
The important thing to note here is this notation here near the end where you are acquiring only the information you need using the (_,_,_,_,price,_)
notation. This will now load only price
with the information, and then you could print it with the print(&price)
function and be able to see that exact piece of information.