i am working on supply chain DApps .here i want to add budget with ownername only not with the whole block - go

type Product struct {
ID string `json:"id"`
Name string `json:"name"`
Area string `json:"area"`
OwnerName string `json:"ownerName"`
Value int `json:"cost"`
Budget int `json:"budget"`
}
func (pc *ProductTransferSmartContract) AddProduct(ctx contractapi.TransactionContextInterface, id string, name string, area string, ownerName string, cost int, budget int) error {
productJSON, err := ctx.GetStub().GetState(id)
if err != nil {
return fmt.Errorf("Failed to read the data from world state", err)
}
if productJSON != nil {
return fmt.Errorf("the product %s already exists", id)
}
prop := Product{
ID: id,
Name: name,
Area: area,
OwnerName: ownerName,
Value: cost,
}
productBytes, err := json.Marshal(prop)
if err != nil {
return err
}
return ctx.GetStub().PutState(id, productBytes)
}
here i want to attach budget only with owner name so that if owner got changed i can change the budget too. Here i have written chaincode in golang.

If requirement is to restrict budget access only for owner, then private data collection can be used. Corresponding APIs are getPrivateData and putPrivateData.

Related

How to return nested entities after creating a new object?

Model Account contains nested structures - Currency and User
When I create a new instance of Account in DB, and then return it in my response, nested entities are empty:
type Account struct {
BaseModel
Name string `gorm:"size:64;not null" json:"name"`
Balance decimal.Decimal `gorm:"type:decimal(16, 2);default:0;not null;" json:"balance"`
UserID int `gorm:"not null" json:"-"`
User User `gorm:"foreignKey:UserID" json:"user"`
CurrencyID int `gorm:"not null" json:"-"`
Currency Currency `gorm:"foreignKey:CurrencyID" json:"currency"`
}
type CreateAccountBody struct {
Name string `json:"name" binding:"required"`
Balance decimal.Decimal `json:"balance"`
CurrencyID int `json:"currency_id" binding:"required"`
}
func CreateAccount(ctx *gin.Context) {
body := CreateAccountBody{}
if err := ctx.Bind(&body); err != nil {
log.Println("Error while binding body:", err)
ctx.JSON(
http.StatusBadRequest,
gin.H{"error": "Wrong request parameters"},
)
return
}
account := Account {
Name: body.Name,
Balance: body.Balance,
CurrencyID: body.CurrencyID,
UserID: 1,
}
if result := db.DB.Create(&account); result.Error != nil {
log.Println("Unable to create an account:", result.Error)
}
ctx.JSON(http.StatusCreated, gin.H{"data": account})
}
To avoid this problem, I refresh account variable with separate query:
db.DB.Create(&account)
db.DB.Preload("User").Preload("Currency").Find(&account, account.ID)
ctx.JSON(http.StatusCreated, gin.H{"data": account})
Is this the most effective and correct way to achieve the desired result?
I'm gonna share you how usually I managed this scenario. First, let me share the code.
main.go file
package main
import (
"context"
"gogindemo/handlers"
"github.com/gin-gonic/gin"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
var (
db *gorm.DB
ctx *gin.Context
)
func init() {
dsn := "host=localhost user=postgres password=postgres dbname=postgres port=5432 sslmode=disable"
var err error
db, err = gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil {
panic(err)
}
db.AutoMigrate(&handlers.Currency{})
db.AutoMigrate(&handlers.User{})
db.AutoMigrate(&handlers.Account{})
}
func AddDb() gin.HandlerFunc {
return func(ctx *gin.Context) {
ctx.Request = ctx.Request.WithContext(context.WithValue(ctx.Request.Context(), "DB", db))
ctx.Next()
}
}
func main() {
db.Create(&handlers.User{Id: 1, Name: "john doe"})
db.Create(&handlers.User{Id: 2, Name: "mary hut"})
db.Create(&handlers.Currency{Id: 1, Name: "EUR"})
db.Create(&handlers.Currency{Id: 2, Name: "USD"})
r := gin.Default()
r.POST("/account", AddDb(), handlers.CreateAccount)
r.Run()
}
Here, I've just added the code for bootstrapping the database objects and add some dummy data to it.
handlers/handlers.go file
package handlers
import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/shopspring/decimal"
"gorm.io/gorm"
)
type User struct {
Id int
Name string
}
type Currency struct {
Id int
Name string
}
type Account struct {
Id int
Name string `gorm:"size:64;not null" json:"name"`
Balance decimal.Decimal `gorm:"type:decimal(16, 2);default:0;not null;" json:"balance"`
UserID int `gorm:"not null" json:"-"`
User User `gorm:"foreignKey:UserID" json:"user"`
CurrencyID int `gorm:"not null" json:"-"`
Currency Currency `gorm:"foreignKey:CurrencyID" json:"currency"`
}
type CreateAccountBody struct {
Name string `json:"name" binding:"required"`
Balance decimal.Decimal `json:"balance"`
CurrencyID int `json:"currency_id" binding:"required"`
}
func CreateAccount(c *gin.Context) {
db, ok := c.Request.Context().Value("DB").(*gorm.DB)
if !ok {
c.JSON(http.StatusInternalServerError, gin.H{"error": "internal server error"})
return
}
var accountReq CreateAccountBody
if err := c.BindJSON(&accountReq); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "wrong request body payload"})
return
}
// create Account & update the "account" variable
account := Account{Name: accountReq.Name, Balance: accountReq.Balance, CurrencyID: accountReq.CurrencyID, UserID: 1}
db.Create(&account).Preload("Currency").Preload("User").Find(&account, account.Id)
c.IndentedJSON(http.StatusCreated, account)
}
Within this file, I actually talk with the database through the DB passed in the context. Now, back to your question.
If the relationship between the Currency/Account and User/Account is of type 1:1, then, you should rely on the Preload clause. This will load the related entity in a separate query instead of adding it in an INNER JOIN clause.
Let me know if this solves your issue, thanks!

Error:interface must be a pointer to struct Error Returned in fiber (golang), how to solve this?

I'm new in Golang Programming
I'm Faceing an issue..
I'm trying to acces my sent body data by "BodyParser"functtion
But I got an error
schema: interface must be a pointer to struct
I'm Giving the Function Bellow
func CreateService(c *fiber.Ctx) error {
if c.Locals("user_type") != "1" {
return c.SendString("Wrong One")
}
file, err := c.FormFile("image")
// Check for errors:
if err != nil {
fmt.Println(err.Error())
return c.JSON("Something error")
}
// 👷 Save file to root directory:
c.SaveFile(file, fmt.Sprintf("./%s", file.Filename))
// 👷 Save file inside uploads folder under current working directory:
c.SaveFile(file, fmt.Sprintf("./uploads/%s", file.Filename))
// 👷 Save file using a relative path:
c.SaveFile(file, fmt.Sprintf("/tmp/uploads_relative/%s", file.Filename))
var data map[string]string
if err := c.BodyParser(&data); err != nil {
return err
}
service := models.Services{
Title: data["title"],
Src: PORT + "/" + file.Filename,
}
database.DB.Create(&service)
return c.JSON(service)
}
model.Services is
type Services struct {
Id uint `json:"id"`
Title string `json:"title"`
Src string `json:"src"`
}
Please Help me out. Thanks a lot in advance!!!
We need to provide pointer to a struct in GoFiber_v2 not *map[string]string. This is causing the issue.
Below Function for getting data from GoFiber_v2 BodyParser:
func Register(c *fiber.Ctx) error {
var user models.User
err := c.BodyParser(&user)
if err != nil {
return err
}
fmt.Printf("%#+v", user)
}
Model Package
package models
type User struct {
Id uint `json:"id"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Email string `json:"email"`
Password string `json:"password"`
}

golang: convert row sql to object

Hello I am using pgx to use my postgres, and I have doubts as to how I can transform a row in the database into an aggregate
I am using entities and value objects
without value object it seems easy using marshal, but using value object I think it is not a good idea to have fields exported and then my question comes in, how can I convert my line into a struct of my aggregate
my aggregrate :
type Email struct {
address string
}
type Password struct {
value string
}
type Name struct {
firstName string
lastName string
}
type Person struct {
Id string
Name valueObject.Name
Email valueObject.Email
Password valueObject.Password
Created time.Time
Updated time.Time
}
func NewPerson(name valueObject.Name, email valueObject.Email, password valueObject.Password) *Person {
id := uuid.New()
return &Person{
Id: id.String(),
Name: name,
Email: email,
Password: password,
Created: time.Now(),
Updated: time.Now(),
}
}
all my value objects have a method to get the private value through a function simulating a get, I didn’t put the rest of the code of my value objects so it wouldn’t get big
func to get all rows from table:
func (r *personRepository) GetAll() (persons []*entities.Person, err error) {
qry := `select id, first_name, last_name, email, password created_at, updated_at from persons`
rows, err := r.conn.Query(context.Background(), qry)
return nil, fmt.Errorf("err")
}
If someone can give me a glimpse of how I can pass this line from the bank to a struct of my aggregate using this value object
You can use something like this (not yet tested and need optimization):
func (r *personRepository) GetAll() (persons []*entities.Person, err error) {
qry := `select id, first_name, last_name, email, password, created_at, updated_at from persons`
rows, err := r.conn.Query(context.Background(), qry)
var items []*entities.Person
if err != nil {
// No result found with the query.
if err == pgx.ErrNoRows {
return items, nil
}
// Error happened
log.Printf("can't get list person: %v\n", err)
return items, err
}
defer rows.Close()
for rows.Next() {
// Build item Person for earch row.
// must be the same with the query column position.
var id, firstName, lastName, email, password string
var createdAt, updatedAt time.Time
err = rows.Scan(&id, &firstName, &lastName, &email,
&createdAt, updatedAt)
if err != nil {
log.Printf("Failed to build item: %v\n", err)
return items, err
}
item := &entities.Person{
Id: id,
FirstName: firstName,
// fill other value
}
// Add item to the list.
items = append(items, item)
}
return items, nil
}
Don't forget to add the comma after text password in your query.
I am using entities and value objects without value object it seems easy using marshal,
Sorry, I don't know about the value object in your question.

Reuse or cast structs for validation, API results, and DB saves in Go

I'm trying to write an API that will do different things with the data depending on its purpose.
API results - The API should expose certain fields to the user
Validation - Validation should handle different schemas e.g. login form doesn't require Name, but register does
Database - The database should save everything, including password etc. - if I try using the same struct for the API and DB with json:"-" or un-exporting the field the database save also ignores the field
Some sample code is below with a couple of comments in capitals to show where I ideally need to type cast to change the data. As they are different structs, they cannot be type cast, so I get an error. How can I fix this?
Alternatively, what is a better way of doing different things with the data without having lots of similar structs?
// IDValidation for uuids
type IDValidation struct {
ID string `json:"id" validate:"required,uuid"`
}
// RegisterValidation for register form
type RegisterValidation struct {
Name string `json:"name" validate:"required"`
Email string `json:"email" validate:"required,email"`
Password string `json:"password" validate:"required,min=8"`
}
// UserModel to save in DB
type UserModel struct {
ID string `json:"id,omitempty"`
Name string `json:"name"`
Email string `json:"email"`
Password string `json:"password,omitempty"`
Active bool `json:"active,omitempty"`
CreatedAt int64 `json:"created_at,omitempty"`
UpdatedAt int64 `json:"updated_at,omitempty"`
jwt.StandardClaims
}
// UserAPI data to display to user
type UserAPI struct {
ID string `json:"id,omitempty"`
Name string `json:"name"`
Email string `json:"email"`
Active bool `json:"active,omitempty"`
}
// register a user
func register(c echo.Context) error {
u := new(UserModel)
if err := c.Bind(u); err != nil {
return err
}
// NEED TO CAST TO RegisterValidation HERE?
if err := c.Validate(u); err != nil {
return err
}
token, err := u.Register()
if err != nil {
return err
}
return c.JSON(http.StatusOK, lib.JSON{"token": token})
}
// retrieve a user
func retrieve(c echo.Context) error {
u := IDValidation{
ID: c.Param("id"),
}
if err := c.Validate(u); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
}
// NEED TO CAST USER TO UserAPI?
user, err := userModel.GetByID(u.ID)
if err != nil {
return err
}
return c.JSON(200, lib.JSON{"message": "User found", "user": user})
}

UnmarshalMap using aws-go-sdk

// UserInfo 用来解构返回的数据
type UserInfo struct {
gender string `dynamo:"gender"`
product string `dynamo:"product"`
id string `dynamo:"id"`
createTime int `dynamo:"create_time"`
name string `dynamo:"name"`
}
// GetUserInfoByID 根据userId在supe_user表取回用户信息
func GetUserInfoByID(userId string) (UserInfo, error) {
queryInput := dynamodb.GetItemInput{
Key: map[string]*dynamodb.AttributeValue{
"userId": {
S: aws.String(userId),
},
},
TableName: aws.String("user"),
}
result, err := dbsession.DynamoDB.GetItem(&queryInput)
userInfo := UserInfo{}
if err != nil {
fmt.Println(err.Error())
return userInfo, err
}
unmarshalMapErr := dynamodbattribute.UnmarshalMap(result.Item, &userInfo)
if unmarshalMapErr != nil {
return userInfo, err
}
fmt.Println(result.Item)
fmt.Println(userInfo.name)
return userInfo, nil
}
Why is this not working? It did not throw any error, just not working...
My guess is something wrong with my UserInfo type, but can't figure the right way to do this, help, please.
In Go, a name is exported if it begins with a capital letter. You should make first letters of fields UPPERCASED to make sure they're exported, like:
type UserInfo struct {
Gender string `dynamo:"gender"`
Product string `dynamo:"product"`
Id string `dynamo:"id"`
CreateTime int `dynamo:"create_time"`
Name string `dynamo:"name"`
}
more info: https://www.goinggo.net/2014/03/exportedunexported-identifiers-in-go.html

Resources