CRUD Contract

Has anyone implemented a CRUD (create, read, update, and delete) for global storage using Move?

I want to port some code from EOS that uses upsert.

2 Likes

Can you give some example in EOS?

Sure, This my favorite blockchain class and #2 reason I like EOS. The #1 is no gas required!. Class below is .cpp, includes DBMS upsert.

#include <eosiolib/eosio.hpp>

using namespace eosio;

class [[eosio::contract]] addressbook : public eosio::contract {

public:
using contract::contract;

addressbook(name receiver, name code, datastream<const char*> ds): contract(receiver, code, ds) {}

[[eosio::action]]
void upsert(name user, std::string first_name, std::string last_name, std::string street, std::string city, std::string state) {
require_auth( user );
address_index addresses(_code, _code.value);
auto iterator = addresses.find(user.value);
if( iterator == addresses.end() )
{
addresses.emplace(user, [&]( auto& row ) {
row.key = user;
row.first_name = first_name;
row.last_name = last_name;
row.street = street;
row.city = city;
row.state = state;
});
}
else {
std::string changes;
addresses.modify(iterator, user, [&]( auto& row ) {
row.key = user;
row.first_name = first_name;
row.last_name = last_name;
row.street = street;
row.city = city;
row.state = state;
});
}
}

[[eosio::action]]
void erase(name user) {
// require_auth(user);

address_index addresses(_self, _code.value);

auto iterator = addresses.find(user.value);
eosio_assert(iterator != addresses.end(), "Record does not exist");
addresses.erase(iterator);

}

private:
struct [[eosio::table]] person {
name key;
std::string first_name;
std::string last_name;
std::string street;
std::string city;
std::string state;
uint64_t primary_key() const { return key.value; }
};
typedef eosio::multi_index<“people”_n, person> address_index;

};

EOSIO_DISPATCH( addressbook, (upsert)(erase))

1 Like

I try to write a Move contract but Move did not support collection currently, so an account just can keep one address record. I just implement upsert function, because Libra did not support query function like eth.

code: https://github.com/jolestar/libra/blob/hack/client/move/address_book.mvir
Execute with my libra fork client:

hack execute 0 $libra_project_dir/libra/client/move/address_book.mvir 74657374 c759e60f58b4543763580278736d929d6a779afd3edd9bfbee2d43f6f3d1d6e1 6265696a696e67

modules:

module Addressbook {

//Move not support collection currently,
//If Move support collection, this resource should use a collection to contain address data.
resource T {
    name: bytearray,
    addr: address,
    city: bytearray,
}

public upsert(name: bytearray, addr:address, city: bytearray){
    let sender:address;
    let entry: R#Self.T;
    let entry_exists: bool;

    sender = get_txn_sender();
    entry_exists = exists<T>(copy(sender));
    if (move(entry_exists)) {
        entry = move_from<T>(move(sender));
    } else {
        entry = T{ name:move(name), addr:move(addr), city:move(city) };
    }
    move_to_sender<T>(move(entry));
    return;
  }
 }

script:

import Transaction.Addressbook;

main(name:bytearray, addr:address, city:bytearray){
    Addressbook.upsert(move(name), move(addr), move(city));
    return;
}
1 Like

:star2::star2::star2::star2::star2:
This is excellent first start. You saved me a lot of time. Bravo!

Collections may be minor in beginning. May rely more on primary key
if I can use UnsignedInt64.

Question: The key for the record would be T which =
name ∪ addr ∪ city

Any advice how to handle “erase” … pursuant to EOS example?

the key would be name or addr.

just move_from the resource and release(T) it.

Sorry new to Move, are you suggesting use of releaseref(entry) ?

just use release(entry)

1 Like

@blockcowboy

release only can release ref, if you want to delete Resource, can move it out then expand filed to consume it.

public delete(){
    let sender: address;
    let name: bytearray;
    let addr: address;
    let city: bytearray;
    let entry_exists: bool;
    let entry: R#Self.T;
    
    sender = get_txn_sender();
    entry_exists = exists<T>(copy(sender));
    if (move(entry_exists)) {
        entry = move_from<T>(move(sender));
        T{name,addr,city} = move(entry);
    }
    return; 
}