-
Notifications
You must be signed in to change notification settings - Fork 1
More things you can do with Laminar with examples
- Addition of a record
- How to define the input and mapping it's data types
- Handling of enums in the table
- mutation type is 'I'. Available mutation types are
- 'I' Insert
- 'S' Insert
- 'U' Update
- 'D' Delete
[
{
"title" : "AddCustomer",
"req_name" : "",
"res_name" : "",
"decl_req" : 1,
"decl_res" : 1,
"decl_grpc" : 1,
"decl_grapql" : 1,
"sql_stmt" : "insert into Customer (name,govt_id_type,govt_id,gender,PhoneNo) values (?,?,?,?,?);",
"sql_params" : "name:Customer.name,govt_id_type:Customer.govt_id_type,govt_id:Customer.govt_id,gender:Customer.gender,PhoneNo:Customer.PhoneNo",
"sql_uniquekey" : 0,
"impl_dao" : 1,
"impl_grpc" : 1,
"null_sql_replace" : 1,
"sql_replace" : "",
"impl_reacrjs" : 0,
"req_override" : "",
"res_override" : "",
"mutation" : "I",
"oauth_public" : 0,
"oauth_claims" : "",
"status" : 1
}
]
* protoc --go_out=zerotouch/golang/proto --go-grpc_out=zerotouch/golang/proto zerotouch/golang/proto/*.proto -I=/Users/kishannigam/go/src/code.nurture.farm/Core/FarmService
* cd zerotouch/golang
* sh run_local.sh
- Addition of multiple records
[
{
"title" : "AddProduct",
"req_name" : "",
"res_name" : "",
"decl_req" : 1,
"decl_res" : 1,
"decl_grpc" : 1,
"decl_grapql" : 1,
"sql_stmt" : "insert into Product (name,description) values (?,?);",
"sql_params" : "name:Product.name,description:string",
"sql_uniquekey" : 0,
"impl_dao" : 1,
"impl_grpc" : 1,
"null_sql_replace" : 1,
"sql_replace" : "",
"impl_reacrjs" : 0,
"req_override" : "",
"res_override" : "",
"mutation" : "I",
"oauth_public" : 0,
"oauth_claims" : "",
"status" : 1
}
]
* protoc --go_out=zerotouch/golang/proto --go-grpc_out=zerotouch/golang/proto zerotouch/golang/proto/*.proto -I=/Users/kishannigam/go/src/code.nurture.farm/Core/FarmService
* cd zerotouch/golang
* sh run_local.sh
For addition/update/delete 3 hooks are provided
- onRequest
- onResponse
- onError
The ReqRes object holds both the request and response. On can override the request object which will be used for data insert. If the response object is populated on onRequest, immediately the response is sent to client.
We will use the onRequest to validate the request input. If it is not valid, we will return a error response.
func (rc *AddProductController) OnRequest(ctx context.Context, request interface{}) (interface{}) {
addProductRequest := request.(*fs.AddProductRequest)
if len(addProductRequest.Description) > 256 {
return &fs.AddProductResponse{
Status: &fs.Status{
Status: fs.StatusCode_INVALID_REQUEST,
ErrorMessages: []string{
"Description allowes 256 characters.",
},
},
}
}
return nil
}
* protoc --go_out=zerotouch/golang/proto --go-grpc_out=zerotouch/golang/proto zerotouch/golang/proto/*.proto -I=/Users/kishannigam/go/src/code.nurture.farm/Core/FarmService
* cd zerotouch/golang
* sh run_local.sh
- Get one single record
- How to define the input and mapping it's data types
[
{
"title" : "FindProductById",
"req_name" : "",
"res_name" : "",
"decl_req" : 1,
"decl_res" : 1,
"decl_grpc" : 1,
"decl_grapql" : 0,
"sql_stmt" : "select name,description from Product where product_id = ?;",
"sql_params" : "productid:int32",
"sql_uniquekey" : 0,
"impl_dao" : 1,
"impl_grpc" : 1,
"null_sql_replace" : 1,
"sql_replace" : "",
"impl_reacrjs" : 0,
"req_override" : "",
"res_override" : "",
"mutation" : "S",
"oauth_public" : 0,
"oauth_claims" : "",
"status" : 1
}
]
* protoc --go_out=zerotouch/golang/proto --go-grpc_out=zerotouch/golang/proto zerotouch/golang/proto/*.proto -I=/Users/kishannigam/go/src/code.nurture.farm/Core/FarmService
* cd zerotouch/golang
* sh run_local.sh
- Override the total count using Data access object.
- Override onData to set the count.
[
{
"title" : "FindProductByNameCount",
"req_name" : "",
"res_name" : "",
"decl_req" : 0,
"decl_res" : 0,
"decl_grpc" : 0,
"decl_grapql" : 0,
"sql_stmt" : "select count(name) as total from Product where name = ?;",
"sql_params" : "name:string",
"sql_uniquekey" : 0,
"impl_dao" : 1,
"impl_grpc" : 0,
"null_sql_replace" : 1,
"sql_replace" : "",
"impl_reacrjs" : 0,
"req_override" : "",
"res_override" : "",
"mutation" : "S",
"oauth_public" : 0,
"oauth_claims" : "",
"status" : 1
}
]
- Disable req, res, grpc, graphql
- Implement dao only.
- Override
onData - Setup count in the
FindProductRes.Builder responseBuilder - At the end framework reads all records from data and add to response.
- Clearing
List datawill have empty list in response. - Setting the response in
ReqRes<FindProductReq, FindProductRes> currentStepwill ignore any further processing including <List data - Usage of
setReadOnTxnScope - Direct usage of
FindProductByNameCountResponseDao
func (rc *FindProductByNameAndDescController) OnData(ctx context.Context, request interface{}, response interface{}) (interface{}) {
findProductByNameAndDescReq := request.(*fs.FindProductReq)
findProductByNameAndDescRes := response.(*fs.FindProductRes)
if len(findProductByNameAndDescReq.Name)>0 && len(findProductByNameAndDescReq.Description)==0 {
var rows = entsql.Rows{}
var args []interface{}
args = append(args, findProductByNameAndDescReq.Name)
query := query.QUERY_FindProductByNameCount
err := executor.Driver.GetDriver().Query(ctx, query, args, &rows)
if err != nil {
logger.Error("Error could not ExecuteFindProductByNameCount", zap.Error(err))
return &fs.FindProductRes{
Status: &fs.Status{
Status: fs.StatusCode_DB_FAILURE,
},
}
}
for rows.Next() {
model := models.FindProductByNameCountResponseVO{}
err := rows.Scan(&model.Total)
if err != nil {
logger.Error("Error while fetching rows for ExecuteFindProductByNameCount", zap.Error(err))
return &fs.FindProductRes{
Status: &fs.Status{
Status: fs.StatusCode_DB_FAILURE,
},
}
}
findProductByNameAndDescRes.Count = cast.ToInt32(model.Total.Int64)
}
}
return findProductByNameAndDescRes
}
* protoc --go_out=zerotouch/golang/proto --go-grpc_out=zerotouch/golang/proto zerotouch/golang/proto/*.proto -I=/Users/kishannigam/go/src/code.nurture.farm/Core/FarmService
* cd zerotouch/golang
* sh run_local.sh
Example 6 - Enter multiple data types in a single transaction (e.g. order detail with multiple items)
- In a single transaction insert to multiple tables
- Use the auto ID generated from upstream inserts in downstream inserts.
- Mix Batch with Single record insert
- Do it in transaction scope
- Order Detail - Declare request, response and implement dao.
[
{
"title" : "AddOrderDetail",
"req_name" : "",
"res_name" : "",
"decl_req" : 1,
"decl_res" : 1,
"decl_grpc" : 0,
"decl_grapql" : 0,
"sql_stmt" : "insert into OrderDetail (customer_id, order_status) values (?, ?);",
"sql_params" : "customer_id:OrderDetail.customer_id,order_status:OrderDetail.order_status",
"sql_uniquekey" : 0,
"impl_dao" : 1,
"impl_grpc" : 1,
"null_sql_replace" : 1,
"sql_replace" : "",
"impl_reacrjs" : 0,
"req_override" : "",
"res_override" : "",
"mutation" : "I",
"oauth_public" : 0,
"oauth_claims" : "",
"status" : 1
}
]
- Order Items - Declare request, response and implement dao.
[
{
"title" : "AddOrderItem",
"req_name" : "",
"res_name" : "",
"decl_req" : 1,
"decl_res" : 1,
"decl_grpc" : 0,
"decl_grapql" : 0,
"sql_stmt" : "insert into OrderItem (order_id, product_id, quantity) values (?, ?, ?);",
"sql_params" : "order_id:OrderItem.order_id,product_id:OrderItem.product_id,quantity:OrderItem.quantity",
"sql_uniquekey" : 0,
"impl_dao" : 1,
"impl_grpc" : 0,
"null_sql_replace" : 1,
"sql_replace" : "",
"impl_reacrjs" : 0,
"req_override" : "",
"res_override" : "",
"mutation" : "I",
"oauth_public" : 0,
"oauth_claims" : "",
"status" : 1
}
]
- Generate proto messages
- Override request to take multiple messages
- Don't implement grpc, Hooks need to be implemented.
[
{
"title" : "EnterOrder",
"req_name" : "EnterOrderReq",
"res_name" : "EnterOrderRes",
"decl_req" : 1,
"decl_res" : 1,
"decl_grpc" : 1,
"decl_grapql" : 0,
"sql_stmt" : "",
"sql_params" : "",
"sql_uniquekey" : 0,
"impl_dao" : 1,
"impl_grpc" : 0,
"null_sql_replace" : 1,
"sql_replace" : "",
"impl_reacrjs" : 0,
"req_override" : "AddOrderDetailRequest orderDetail = 5; BulkAddOrderItemRequest orderItems = 6;",
"res_override" : "",
"mutation" : "I",
"oauth_public" : 0,
"oauth_claims" : "",
"status" : 1
}
]
func (rc *EnterOrderController) OnRequest(ctx context.Context, request *fs.EnterOrderReq) (*fs.EnterOrderRes) {
enterOrderRequest := request
var response fs.EnterOrderRes
response.Status = &common.RequestStatusResult{
Status: common.RequestStatus_SUCCESS,
}
response.Count = 1
_, txErr:= executor.Driver.TransactionRunner(ctx, "OnRequestEnterOrder", func(ctx context.Context, txName string, tx dialect.Tx) (res executor.TransactionResult, err error){
model := mappers.MakeAddOrderDetailRequestVO(enterOrderRequest.OrderDetail)
args := executor.AddOrderDetailArgs(model)
var rows sql.Result
err = tx.Exec(ctx, query.QUERY_AddOrderDetail, args, &rows)
if err != nil {
logger.Error("Error could not AddOrderDetail", zap.Error(err))
return nil, err
}
insertedId, err := rows.LastInsertId()
if err != nil {
logger.Error("Error could not get lastInsertedId for AddOrderDetail", zap.Error(err))
return nil, err
}
response.RecordId = cast.ToString(insertedId)
for _, enterOrderItemRequest := range enterOrderRequest.OrderItems {
enterOrderItemRequest.OrderId = cast.ToInt32(insertedId)
model := mappers.MakeAddOrderItemRequestVO(enterOrderItemRequest)
args := executor.AddOrderItemArgs(model)
var rows sql.Result
query := query.QUERY_AddOrderItem
err := tx.Exec(ctx, query, args, &rows)
if err != nil {
logger.Error("Error could not ExecuteAddOrderItemRequest", zap.Error(err))
return nil, err
}
_, err = rows.LastInsertId()
if err != nil {
logger.Error("Error could not get lastInsertedId for AddOrderItemRequest", zap.Error(err))
return nil, err
}
}
return nil, nil
})
if txErr != nil {
response.Status = &common.RequestStatusResult{
Status: common.RequestStatus_INTERNAL_ERROR,
ErrorCode: common.ErrorCode_DATABASE_ERROR,
}
response.Count = 0
response.RecordId = ""
return &response
}
return &response
}
Steps to generate and run code :
* protoc --go_out=zerotouch/golang/proto --go-grpc_out=zerotouch/golang/proto zerotouch/golang/proto/*.proto -I=/Users/kishannigam/go/src/code.nurture.farm/Core/FarmService
* cd zerotouch/golang
* sh run_local.sh
- Ses the column alias or column name to determine the key name in the message.
- If an alias contains dots, the proto message is selected to create nested objects.
Query
SQL
SELECT
BusinessEntityID As Id,
FirstName, LastName,
Title As 'Info.Title',
MiddleName As 'Info.MiddleName'
FROM Person.Person
limit 10
Result
JSON
Copy
[{
"Id": 1,
"FirstName": "Ken",
"LastName": "Sanchez",
"Info": {
"MiddleName": "J"
}
}, {
"Id": 2,
"FirstName": "Terri",
"LastName": "Duffy",
"Info": {
"MiddleName": "Lee"
}
}, {
"Id": 3,
"FirstName": "Roberto",
"LastName": "Tamburello"
}, {
"Id": 4,
"FirstName": "Rob",
"LastName": "Walters"
}, {
"Id": 5,
"FirstName": "Gail",
"LastName": "Erickson",
"Info": {
"Title": "Ms.",
"MiddleName": "A"
}
}][
{
"title" : "GetLatestOrder",
"req_name" : "",
"res_name" : "",
"decl_req" : 1,
"decl_res" : 1,
"decl_grpc" : 1,
"decl_grapql" : 0,
"sql_stmt" : "select order_id, customer_id ,order_status, created_on from OrderDetail where created_on > ?;",
"sql_params" : "creation_time:OrderDetail.created_on",
"sql_uniquekey" : 1,
"impl_dao" : 1,
"impl_grpc" : 0,
"null_sql_replace" : 1,
"sql_replace" : "",
"impl_reacrjs" : 0,
"req_override" : "",
"res_override" : "",
"mutation" : "S",
"oauth_public" : 0,
"oauth_claims" : "",
"status" : 1
}
]
- Request is reused.
[
{
"title" : "GetLatestOrderCustomers",
"req_name" : "GetLatestOrderRequest",
"res_name" : "",
"decl_req" : 0,
"decl_res" : 1,
"decl_grpc" : 1,
"decl_grapql" : 0,
"sql_stmt" : "select customer_id,name,govt_id_type,govt_id,gender,PhoneNo from Customer where customer_id in ( select customer_id from OrderDetail where created_on > ? )",
"sql_params" : "creation_time:OrderDetail.created_on",
"sql_uniquekey" : 0,
"impl_dao" : 1,
"impl_grpc" : 1,
"null_sql_replace" : 1,
"sql_replace" : "",
"impl_reacrjs" : 0,
"req_override" : "",
"res_override" : "",
"mutation" : "S",
"oauth_public" : 0,
"oauth_claims" : "",
"status" : 1
}
]
- Request is reused.
-
GetLatestOrderResponseRecord.order_statusare mapped to generated record and fields
[
{
"title" : "GetOrderCustomerMix",
"req_name" : "GetLatestOrderRequest",
"res_name" : "",
"decl_req" : 0,
"decl_res" : 1,
"decl_grpc" : 1,
"decl_grapql" : 0,
"sql_stmt" : "select o.order_status as `GetLatestOrderResponseRecord.order_status`, c.name as `GetLatestOrderCustomersResponseRecord.name` from OrderDetail o, Customer c where o.customer_id = c.customer_id and o.customer_id = c.customer_id and o.created_on > ?;",
"sql_params" : "creation_time:OrderDetail.created_on",
"sql_uniquekey" : 0,
"impl_dao" : 1,
"impl_grpc" : 1,
"null_sql_replace" : 1,
"sql_replace" : "",
"impl_reacrjs" : 0,
"req_override" : "",
"res_override" : "",
"mutation" : "S",
"oauth_public" : 0,
"oauth_claims" : "",
"status" : 1
}
]
* protoc --go_out=zerotouch/golang/proto --go-grpc_out=zerotouch/golang/proto zerotouch/golang/proto/*.proto -I=/Users/kishannigam/go/src/code.nurture.farm/Core/FarmService
* cd zerotouch/golang
* sh run_local.sh
Example 8 - Call extrnal micro service
- No request, response implementation
- Complete implementation.
[
{
"title" : "WeatherService",
"req_name" : "",
"res_name" : "",
"decl_req" : 1,
"decl_res" : 1,
"decl_grpc" : 1,
"decl_grapql" : 0,
"sql_stmt" : "",
"sql_params" : "",
"sql_uniquekey" : 0,
"impl_dao" : 0,
"impl_grpc" : 0,
"null_sql_replace" : 1,
"sql_replace" : "",
"impl_reacrjs" : 0,
"req_override" : "LatLng latlng=9; } message LatLng {double lat = 1; double lng = 2",
"res_override" : "int32 temp = 9;",
"mutation" : "S",
"oauth_public" : 0,
"oauth_claims" : "",
"status" : 1
}
]
func (rc *WeatherServiceController) OnRequest(ctx context.Context, request interface{}) (interface{}) {
weatherServiceRequest := request.(*fs.WeatherServiceRequest)
logger.Info("LatLng:"+cast.ToString(weatherServiceRequest.GetLatlng().GetLat())+ ", " +cast.ToString(weatherServiceRequest.GetLatlng().GetLng()))
return &fs.WeatherServiceResponse{
Status: &fs.Status{
Status: fs.StatusCode_SUCCESS,
},
TemparatureInDegrees: 23.23,
}
}
Steps to generate and run code :
* protoc --go_out=zerotouch/golang/proto --go-grpc_out=zerotouch/golang/proto zerotouch/golang/proto/*.proto -I=/Users/kishannigam/go/src/code.nurture.farm/Core/FarmService
* cd zerotouch/golang
* sh run_local.sh
- OAuth setup
- Running in private scope
[ { "title" : "FindProductByIds", "req_name" : "", "res_name" : "", "decl_req" : 1, "decl_res" : 1, "decl_grpc" : 1, "decl_grapql" : 0, "sql_stmt" : "select product_id,name from Product where product_id in (@productid@);", "sql_params" : "", "sql_uniquekey" : 0, "impl_dao" : 1, "impl_grpc" : 1, "null_sql_replace" : 1, "sql_replace" : "productid:repeated int32", "impl_reacrjs" : 0, "req_override" : "", "res_override" : "", "mutation" : "S", "oauth_public" : 0, "oauth_claims" : "", "status" : 1 } ]
- Deleting of records
- Filter on selected Ids
[
{
"title" : "DeleteCustomerByIds",
"req_name" : "",
"res_name" : "",
"decl_req" : 1,
"decl_res" : 1,
"decl_grpc" : 1,
"decl_grapql" : 0,
"sql_stmt" : "delete from Customer where govt_id in (@govtids@);",
"sql_params" : "",
"sql_uniquekey" : 0,
"impl_dao" : 1,
"impl_grpc" : 1,
"null_sql_replace" : 1,
"sql_replace" : "govtids:repeated string",
"impl_reacrjs" : 0,
"req_override" : "",
"res_override" : "",
"mutation" : "D",
"oauth_public" : 0,
"oauth_claims" : "",
"status" : 1
}
]
Currently replace tag should be all small case.
* protoc --go_out=zerotouch/golang/proto --go-grpc_out=zerotouch/golang/proto zerotouch/golang/proto/*.proto -I=/Users/kishannigam/go/src/code.nurture.farm/Core/FarmService
* cd zerotouch/golang
* sh run_local.sh
- Override the total count using Data access object.
- Override onData to set the count.
- Disable req, res, grpc, graphql
- Implement dao only.
[
{
"title" : "FindProductByNameCount",
"req_name" : "",
"res_name" : "",
"decl_req" : 0,
"decl_res" : 0,
"decl_grpc" : 0,
"decl_grapql" : 0,
"sql_stmt" : "select count(name) as total from Product where name = ?;",
"sql_params" : "name:string",
"sql_uniquekey" : 0,
"impl_dao" : 1,
"impl_grpc" : 0,
"null_sql_replace" : 1,
"sql_replace" : "",
"impl_reacrjs" : 0,
"req_override" : "",
"res_override" : "",
"mutation" : "S",
"oauth_public" : 0,
"oauth_claims" : "",
"status" : 1
}
]
- Override
onData - Setup count in the
FindProductRes.Builder responseBuilder - At the end framework reads all records from data and add to response.
- Clearing
List datawill have empty list in response. - Setting the response in
ReqRes<FindProductReq, FindProductRes> currentStepwill ignore any further processing including <List data - Usage of
setReadOnTxnScope - Direct usage of
FindProductByNameCountResponseDao
func (rc *FindProductByNameAndDescController) OnData(ctx context.Context, request interface{}, response interface{}) (interface{}) {
findProductByNameAndDescReq := request.(*fs.FindProductReq)
findProductByNameAndDescRes := response.(*fs.FindProductRes)
if len(findProductByNameAndDescReq.Name)>0 && len(findProductByNameAndDescReq.Description)==0 {
var rows = entsql.Rows{}
var args []interface{}
args = append(args, findProductByNameAndDescReq.Name)
query := query.QUERY_FindProductByNameCount
err := executor.Driver.GetDriver().Query(ctx, query, args, &rows)
if err != nil {
logger.Error("Error could not ExecuteFindProductByNameCount", zap.Error(err))
return &fs.FindProductRes{
Status: &fs.Status{
Status: fs.StatusCode_DB_FAILURE,
},
}
}
for rows.Next() {
model := models.FindProductByNameCountResponseVO{}
err := rows.Scan(&model.Total)
if err != nil {
logger.Error("Error while fetching rows for ExecuteFindProductByNameCount", zap.Error(err))
return &fs.FindProductRes{
Status: &fs.Status{
Status: fs.StatusCode_DB_FAILURE,
},
}
}
findProductByNameAndDescRes.Count = cast.ToInt32(model.Total.Int64)
}
}
return findProductByNameAndDescRes
}
Steps to generate and run code :
* protoc --go_out=zerotouch/golang/proto --go-grpc_out=zerotouch/golang/proto zerotouch/golang/proto/*.proto -I=/Users/kishannigam/go/src/code.nurture.farm/Core/FarmService
* cd zerotouch/golang
* sh run_local.sh
* protoc --go_out=zerotouch/golang/proto --go-grpc_out=zerotouch/golang/proto zerotouch/golang/proto/*.proto -I=/Users/kishannigam/go/src/code.nurture.farm/Core/FarmService
* cd zerotouch/golang
* sh run_local.sh