Table Modify Assignment

Post your solutions here to the Table Modify Assignment.

ACTION helloworld::modify(uint64_t identifier, name new_owner, std::string new_name, uint64_t new_age){
  auto dog = _dogs.get(identifier, "Doggo not found");
  require_auth(dog.owner_name);
  auto dog_iterator = _dogs.find(identifier);
  _dogs.modify(dog_iterator, dog.owner_name,
  [&](auto& modify_dog){
    modify_dog.owner_name = new_owner;
    modify_dog.dog_name = new_name;
    modify_dog.age = new_age;
  });
}

I"ve left out the definition of the table but it seems to work without it, probably because I"ve added a declaration after defining the table type:

 typedef multi_index <name("dogs"), dog> dog_table;
  dog_table _dogs;
1 Like

ACTION edit(name dog_owner, int dog_id, int new_age, std::string new_name){
dog_index dogs(get_self(),get_self().value);
auto dog=dogs.find(dog_id);
require_auth(dog_owner);
dogs.modify(dog, dog_owner,[&](auto& selected) {
selected.dog_age=new_age;
selected.dog_name=new_name;
});
}

1 Like
ACTION mopdify(int id, string dog_name) {
      dog_index dogs(get_self(), get_self().value);

      auto dog = dogs.get(id, "Dog not find");
      require_auth(dog.owner);

      auto iterator = dogs.find(id);
      dogs.modify(iterator, dog.owner, [&](auto& dog){
        dog.dog_name = dog_name;
      }); 
}
1 Like

ACTION modify(int dog_id, std::string dog_name, int dog_age){
dog_index dogs(get_self(), get_self().value);
//require auth so only owner can erase its dogs.
auto dog = dogs.get(dog_id,ā€œUnable to fetch dog. Or no dogā€);
require_auth(dog.owner);
//end auth
auto iterator = dogs.find(dog_id);
dogs.modify(iterator, dog.owner, [&](auto& dog){
dog.dog_name = dog_name;
dog.dog_age = dog_age;
});
}

working by ID, cant modify ID nor owner, only name and age.

1 Like
      ACTION modify(int dog_id, std::string new_name = "", int new_age = 0)
      {
        dog_index dogs(get_self(), get_self().value);
        
        auto dog = dogs.get(dog_id, "unable to fetch dogger.");
        require_auth(dog.owner);

        auto iterator = dogs.find(dog_id);
        dogs.modify(iterator, dog.owner, [&](auto& dog)
        {
          // update dogger here.
          if (new_name != ""){
            dog.dog_name = new_name;
          }
          if (new_age > 0){
            dog.age = new_age;
          }
        });
      }
1 Like

Hi @filip, have probably complicated this for myself, but hey hoā€¦ Have adapted the dog example and done something around cars instead. Two of my properties are bools and that is causing me a slight issue for modifying as Iā€™m not sure how to pass in a default value for a bool. Is it best to overload the method when using boolean arguments?

Also, I am going back to work as a full-time PM so will probably have to switch my focus to the business aspect of the course for the time being, but hope to come back the development side in due course.

Iā€™m not 100% sure what you are asking. The default value of a bool is always false, when you donā€™t initialize it to anything else. But when you create your car object, if thatā€™s what you are doing, you can always set it to true of course, just like an integer or a string. But maybe that wasnā€™t your question at all. Could you elaborate on what the issue is?

Apologies, I should have been more specificā€¦ We can modify strings and integers easily by testing for a default value. i.e.
modify(string newStringValue = ā€œā€, int newIntValue = 0, bool newBoolValue){
if(newStringValue != ā€œā€){stringValue = newStringValue;}
if(newIntValue > 0){intValue = newIntValue;}
}

As you say, the default value for bool is false so I donā€™t see how we can test it. If the current value of the boolean property is true and we donā€™t provide a value it will default to false, which is not what we want. I canā€™t see any way around this other than to overload the modify method:

modify(string newStringValue = ā€œā€, int newIntValue = 0){
if(newStringValue != ā€œā€){stringValue = newStringValue;}
if(newIntValue > 0){intValue = newIntValue;}
}
modify(string newStringValue = ā€œā€, int newIntValue = 0, bool newBoolValue){
if(newStringValue != ā€œā€){stringValue = newStringValue;}
if(newIntValue > 0){intValue = newIntValue;}
boolValue = newBoolValue;
}

Hope this makes more sense now. Thanks

Thatā€™s right, you canā€™t know if a boolean is false because it was never set or because someone set it to false. But Iā€™m still not 100% sure of what you are trying to accomplish.

So the solution depends on your usecase.

But one way around this is to add a boolean flag somewhere, perhaps in the struct (the issue is most common in structs), that signals if the struct has been modified or not. This is a common problem in solidity mappings for example. But Iā€™m not sure whatā€™s the bigger problem you are trying to solve here.

Hi Filip, appreciate your patience in looking at this. Iā€™m sure you are very busy so I donā€™t want to drag this out, especially given that it is slightly off topic. Letā€™s suppose the use case is the management of a fleet of vehicles and this is a vehicle objectā€¦ Our vehicle object has many properties, but we are focused on:
int currentMileage, bool hasTowHitch, bool hasRoofRack
When we initialise the object we set:
currentMilieage = 500
hasTowHitch = true
hasRoofRack = false
The modification function is:
modify(int currentMilieage = 0, bool hasTowHitch = false, bool hasRoofRack = false){}
This is what our properties will be if I update only the mileage:
currentMilieage = 6458
hasTowHitch = false
hasRoofRack = false
This is not what we want as the record says the vehicle no longer has a tow hitch even though it still does. As I see it we have the following options:

  1. Read the entire record from the table into a vehicle object; update the appropriate properties; and write the entire record back.
  2. Overload the modify method with different parameter signatures and just call the relevant version of the modify method.
  3. Use a bitwise reference table to store all the boolean options and hold an int value in a single variable to correspond to the selected options. i.e.
    Table vehicle_options
    Key : Option
    1 : No options selected
    2 : Tow Hitch
    4 : Roof Rack
    8 : Heated Windscreen
    16 : Leather Trim
    32 : Air Conditioning

We could use an int property ā€˜optionsā€™ to hold the selection. For instance, value 42 could only equate to the Tow Hitch, Heated Windscreen and Air Conditioning options. The modify method could then use a default value of 0 for the options parameter if we did not intend to change that property.

I suppose the best solution would be the one that uses the least amount of processing power.

Okay, now I see your problem clearly. Thank you! Itā€™s not an easy one. I see a few solutions.

  1. If some of the properties are immutable, then you donā€™t need them in the modify function. So should a car be able to remove itā€™s roofracks? Or is that something that can only be determined upon creation of the car and the record?

  2. The person updating the record would need to input the entire object, not just the properties that should be changed. This is not a horrible solution if done correctly with a nice frontend for example. Where you could easily fetch the entire object, present it to the user/operator and they can change what they want and re-submit. Probably the best solution.

Unfortunately you canā€™t overload actions in eos, otherwise that would have been a good solution. Another solution would be to have separate update functions for all different properties, but that doesnā€™t really makes sense in this case. The solution above is better.

So you really figured it out yourself, good job! :smiley:

Thanks Filip, appreciate your feedback on this. The info on overloading is definitely interesting and well worth remembering.

Will plug away at the development side, but my focus will have to be on the business aspect for the time being. Iā€™m also currently doing my APM PMQ so lots going on at moment.

This is a great site and Iā€™m so pleased I found it. Cheers :ok_hand:

1 Like

Here is my solution.
ACTION modify takes 3 arguments. dog id, name of new owner and new name for dog
itā€™s required that the original owner signs the modify action, then the dog is transferred to the new owner.

image

Ivo

1 Like

It seems the link on the assignment page is broken.

ā€œHere is the documentation for the eosio::multi_index class: https://eosio.github.io/eosio.cdt/1.6.0/classeosio_1_1multi__index.htmlā€

Thanx, we will fix itā€¦ :+1:

Why can I not use this to modify table:

 ACTION modify(int dog_id){
      dog_index dogs(get_self(), get_self().value);

      auto dog = dogs.get(dog_id, "Unable to modify dog");
      require_auth(dog.owner);

      auto iterator = dogs.find(dog_id);
      dogs.modify(iterator);
      };
1 Like

Hi.
Iā€™m not sure, It looks right to meā€¦ I can run it later today and seeā€¦
Ivo

1 Like

Hi.
If you look at my answer below, you can see that you are havenā€™t passed the arguments (new_owner and new_dog_name in the ACTION modify function.

You are also missing the last part in the dogs.modify()
image

I hope this helps you. :slight_smile:
Ivo

1 Like

Here is my attempt at this point:

    ACTION modify(int dog_id, std::string new_dog_name, int new_age) {
      dog_index dogs(get_self(), get_self().value);

      auto dog = dogs.get(dog_id, "Unable to fetch dog");
      require_auth(owner);

      auto iterator = dogs.find(dog_id);
      dogs.modify(iterator, account owner, [&](auto& row) {
        row.dog_name = new_dog_name;
        row.age = new_age;
      };

    }

Screenshot:

I think there should be some mistakes here and there. Please feel free to correct me.

I am not sure of account owner. Is account accepted as a type?

Due to the bug on EOS Studio Web (not solved yet), I cannot build nor deploy to make some tests. I will move on to the next videos, but in the meantime, your inputs are welcomed for me to correct and make my code work.