Why are Revel optional func parameters in controller not working? CRUD code redundancy

279 views Asked by At

I was reading lot about Go and see that I cannot have optional parameters (nor default value for some parameters) in methods or functions. Lets take for example simple CRUD.

I want to use same controller action for create and update and just to do simple:

func (c Account) User(user models.User, verifyPassword string, id ...int64) {

    /*
    validate user etc
   */
    if len(id) > 0 {
        c.Txn.Update(&model)
    } else{
        c.Txn.Insert(&model)
    }
}

When I try to do {{ url "Account.User" }} in a template, I get an error saying that I am missing parameters. Once I hardcode value for route, I have some invalid memory address or nil pointer dereference on an unknown part of code.

Without optional/default parameters I will have code redundancy for CRUD that I do not want!

So instead of one function I will have to use two functions for the same thing that are only different in one line of code.

Since I started learning Go and Revel seven days ago, maybe I've missed something. The only reason I used Go and Revel is for speed. I am using this for some project that has a lot of requests (millions per day).

Is there any way to solve this?

Update

First problem is on the view: {{ url "Account.User" }}

When I used it like this, it says:

missing parameter id for route Account.User in func (c Account) User(user models.User, verifyPassword string, id ...int64)

So this is more of a Revel problem then Go.

2

There are 2 answers

0
Pandemonium On BEST ANSWER

Or you can try variadic arguments parsing, like how Python uses *args

func (c Account) User(args ...interface{}) {

    for _, arg := range args {
        switch v := arg.(type) {
        case models.User:
            // validate user
        case string:
            // verify password
        case []int64:
            if len(v) > 0 {
                c.Txn.Update(&model)
            } else {
                c.Txn.Insert(&model)
            }
        default:
            // some default stuff
        }
    }
}
0
evanmcdonnal On

There are many ways to solve this problem, like any other. The simple obvious solution (which works in any language) would be to move the common logic into a helper method and provide two wrappers around it that accept different arguments. That being said, I don't think it's necessary and can't actually understand what your problem is because your code works just fine... My example program below clearly shows you can call the method with 0 or more arguments and decide what to do based on how many are present.

package main

import "fmt"

func main() {
    Test()
    Test(1)
    Test(1, 2)
    Test(1, 2, 3, 4)
}

func Test(numbers ... int) {
    fmt.Println(len(numbers))
}

I would guess your intent is to update if there is an id provided (if there's an id then it would indicate there is an existing record) and do insert if it is not. My other guess is that you're confused about how to call the method, not how to define it. Your definition looks fines and should work how you intend it to so long as you call it correctly. Finally, I think you're probably misusing the ... language feature. If the length of id is intended to be 1 or 0 and you're using that variable length array thing as a substitute for real optional parameters, you probably should stop doing that. You could just use 2 arguments, a bool saying 'update' and an int for id. If update is false, you call update and don't pass the id.