9

Hello I'm trying to work out how to create complex relationships in Solidity.

In this example a customer will place an order using a function with arguments, however it cannot be for any combination of shops, types, and products, the relationship must already be established.

In a normal relational database the foreign keys would ensure the relationship was good, and I think in Solidity this is the case with mappings, but I'm not sure how this could be applied:

struct ShopName {
    string name; // ShopA, ShopB, ShopC
}

// Each shop can have one or more types 
struct ShopType {
    string type; // market, brick, online 
}

// each type can have one or more products
struct Product {
    string productCode;
    uint unitPrice;
}

struct SalesOrders {
    address customer;
    uint qty;
    string status; // paid, unpaid
}

So I am imagining a transaction something like this:

function placeOrder(string _shopName, string _shopType, string _productCode, uint _qty) {
    ...
}

In this example the ShopName ShopType and Product must have an established set of related values, and when an order is placed only those related values can be allowed.

But somehow I think I have a got totally lost because I don't know how to think about this problem, let alone how to access the data.

I have seen the example in readthedocs but I am confused about putting this into practice. Can someone give me some direction please?

2

This could be useful, from https://dappsforbeginners.wordpress.com/tutorials/typing-and-your-contracts-storage/

We can also include mappings as data types within another mapping:

contract rainbowCoin {
mapping (address => mapping (uint => uint)) balances;
function rainbowCoin() {
    balances[msg.sender][0] = 10000; ///red coin
    balances[msg.sender][1] = 10000; ///orange coin
    balances[msg.sender][2] = 10000; ///yellow coin
    balances[msg.sender][3] = 10000; ///green coin
    balances[msg.sender][4] = 10000; ///blue coin
    balances[msg.sender][5] = 10000; ///indigo coin
    balances[msg.sender][6] = 10000; ///violet coin
}
function sendCoin(address receiver, uint amount, uint coin) returns(bool successful) {
    if (balances[msg.sender][coin] < amount) return false;
    balances[msg.sender][coin] -= amount;
    balances[receiver][coin] += amount;
    return true;
}

}

Think about the potentials of this:

It is also possible to place mappings inside of structs, and place structs inside mappings – in fact the only data type that you cannot place inside a struct or a mapping is itself.

Could you give us a feedback about how many mappings you could successfully implement into each other? I never tried this out :)

8

There are many ways to attack this problem. One approach would be to design the contract as one shop and deploy instances of it for each new shop. Then the contract address becomes the unique ID for each shop. Here's an example:

// Basic contract for a shop. A shop is identified by it contract address
contract Shop {
  address owner;

  string name;
  string type;
  struct Product {
    string code;
    uint unitPrice;
  }
  mapping(string => Product) products;

  function placeOrder(string productCode, uint qty) {
    ....
  }
}


// The shop registry is a place to lookup the address of a shop by name
contract ShopRegistry {
  mapping(string => address) shops;

  function getShop(string name) returns (address) {
    return shops[name];
  }
}

// Here's how you could use the contracts with the web3.js api:

// Find the shop's address by name
var registry = ShopRegistry.at(registry_address);

// Get the shops's address
var shopAddress = registry.getShop('EtherTShirtsRUs');

// Get an instance of the shop's contract
var etherTShirts = Shop.at(shopAddress);

// Place the order directly to the shop
etherTShirts.placeOrder(...);

The added benefit of this approach is each shop and owner would have control over it's funds.

  • 1
    This only deals with the top level "shop", it doesn't deal with the fact that the same shop can have multiple types, (which is the same problem for types to products). i.e. In this answer there can only be one type per shop. What I am trying to do is have multiple possible types per shop and be able to address them somehow. – T9b Mar 30 '16 at 12:31
4

The simplest way to implement this would be as a series of nested maps: A shops map, which contains Shop objects, each of which contains a Types map of ShopType objects, each of which contains an SKUs map, of SKU objects. To find a product, simply look up each one in the chain, throwing an error if any of them don't exist.

  • This is what I was thinking, although I don't know how that is done. If I put a mapping statement in a struct Mix complains that accessors on dynamic arrays is not yet implemented. Can you give an example of what you mean? – T9b Mar 30 '16 at 14:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.