0

I am trying to save an hederea contract ID of type *hedera.ContractID into a Gorm field but i get the error "invalid field found for struct github.com/hashgraph/hedera-sdk-go/v2.AccountID's field AliasKey: define a valid foreign key for relations or implement the Valuer interface"

package contract

import (
    "fmt"

    "github.com/.../scanner/controllers/blockchain"
    database "github.com/.../scanner/db"
    model "github.com/.../scanner/models"
    "github.com/rs/xid"
    "gorm.io/gorm"
)

func DeployContract() *gorm.DB {

    //connect to database
    db, err := database.ConnectToDB()

    //if db connection fails
    if err != nil {
        panic(err)
    }

    //init model
    var modelContract model.Contract

    //check if a contract has been deployed
    if err := db.First(&modelContract); err.Error != nil {
        //no deployment found

        //Migrate the schema
        db.AutoMigrate(&model.Contract{})

        //deploy contract
        contract, _ := blockchain.DeployContract()

        //create record

        // generate random id
        id := xid.New()

        // Create
        db.Create(&model.Contract{
            Id:            id.String(),
            ContractId:    contract.Receipt.ContractID,
            GasUsed:       contract.CallResult.GasUsed,
            TransactionId: fmt.Sprint(contract.TransactionID),
            Timestamp:     contract.ConsensusTimestamp,
            ChargeFee:     fmt.Sprint(contract.TransactionFee),
            PayerAccount:  fmt.Sprint(contract.TransactionID.AccountID),
            Status:        fmt.Sprint(contract.Receipt.Status),
        })

    }

    return db
}

Gorm Model

package models

import (
    "time"

    "github.com/hashgraph/hedera-sdk-go/v2"
    "gorm.io/gorm"
)

type Contract struct {
    gorm.Model
    Id            string
    ContractId    *hedera.ContractID
    GasUsed       uint64
    TransactionId string
    Timestamp     time.Time
    ChargeFee     string
    PayerAccount  string
    Status        string
}
mev
  • 177
  • 5

1 Answers1

0

For custom data types, you need to specify how the value will be stored and retrieved from your database. This is done by implementing the Scanner and Valuer interfaces.

However, since hedera.ContractID is defined in another package, you will need to create your own ContractID and implement these interfaces. Something like this:

type ContractID hedera.ContractID

type Contract struct {
    gorm.Model
    Id            string
    ContractId    *ContractID
    GasUsed       uint64
    TransactionId string
    Timestamp     time.Time
    ChargeFee     string
    PayerAccount  string
    Status        string
}     

func (c *ContractID) Scan(value interface{}) error {
  bytes, ok := value.([]byte)
  if !ok {
    return errors.New(fmt.Sprint("Failed to unmarshal ContractID value:", value))
  }

  return json.Unmarshal(bytes, c)
}

func (c ContractID) Value() (driver.Value, error) {
  return json.Marshal(c)
}

Additionally, cast hedera.ContractID into model.ContractID wherever it is used. For example:

    cID := model.ContractID(*contract.Receipt.ContractID)

    // Create
    db.Create(&model.Contract{
        Id:            id.String(),
        ContractId:    &cID,
        GasUsed:       contract.CallResult.GasUsed,
        TransactionId: fmt.Sprint(contract.TransactionID),
        Timestamp:     contract.ConsensusTimestamp,
        ChargeFee:     fmt.Sprint(contract.TransactionFee),
        PayerAccount:  fmt.Sprint(contract.TransactionID.AccountID),
        Status:        fmt.Sprint(contract.Receipt.Status),
    })
Emin Laletovic
  • 4,084
  • 1
  • 13
  • 22
  • Thanks for the message but how can I apply it. – mev Nov 21 '22 at 09:39
  • Add this code to your code (maybe where your `Contract` struct is defined). – Emin Laletovic Nov 21 '22 at 10:54
  • Thanks for the reply. Still cannot get it to work. This is what I have done https://play.golang.com/p/id4GlSqi0-a – mev Nov 21 '22 at 12:10
  • I updated my code with a custom `ContractID` definition. – Emin Laletovic Nov 21 '22 at 14:47
  • Thanks for the message, the scanner/valuer works but when trying to create a db instance using db.Create I get an IncompatibleAssign error for ContractId(storing a value of contract.Receipt.ContractID) as it now has to be of type ContractID hedera.ContractID – mev Nov 21 '22 at 15:53
  • Added more code to the answer, because you need to cast `hedera.ContractID` into `models.ContractID`. – Emin Laletovic Nov 21 '22 at 22:42
  • Is possible to cast the ContractId read from db. back to *hedera.ContractID – mev Nov 23 '22 at 09:45
  • you should be able to do something like `hederaContractID := hedera.ContractID(cID)` where `cID` is of type `model.ContractID`. – Emin Laletovic Nov 23 '22 at 10:10
  • 1
    A big thank you, it worked well. I ended up doing hederaContractID := hedera.ContractID(*cID); thanks again. – mev Nov 23 '22 at 12:52