Skip to content

Commit

Permalink
handle not found errors in odoo.go to not repeat in every model (#50)
Browse files Browse the repository at this point in the history
* handle not found errors in odoo.go to not repeat in every model + added errors variables ErrNotFound and ErrPartiallyFound

* updated generator and clarified usage
  • Loading branch information
ahuret authored Feb 22, 2024
1 parent 18d3bc8 commit 462cbb1
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 68 deletions.
33 changes: 5 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,31 +11,8 @@ An Odoo API client enabling Go programs to interact with Odoo in a simple and un

### Generate your models

**Note: Generating models require to follow instructions in GOPATH mode. Refactoring for go modules will come soon.**

Define the environment variables to be able to connect to your odoo instance :

(Don't set `ODOO_MODELS` if you want all your models to be generated)

```
export ODOO_ADMIN=admin // ensure the user has sufficient permissions to generate models
export ODOO_PASSWORD=password
export ODOO_DATABASE=odoo
export ODOO_URL=http://localhost:8069
export ODOO_MODELS="crm.lead"
```

`ODOO_REPO_PATH` is the path where the repository will be downloaded (by default its GOPATH):
```
export ODOO_REPO_PATH=$(echo $GOPATH | awk -F ':' '{ print $1 }')/src/github.com/skilld-labs/go-odoo
```

Download library and generate models :
```
GO111MODULE="off" go get github.com/skilld-labs/go-odoo
cd $ODOO_REPO_PATH
ls | grep -v "conversion.go\|generator\|go.mod\|go-odoo-generator\|go.sum\|ir_model_fields.go\|ir_model.go\|LICENSE\|odoo.go\|README.md\|types.go\|version.go" // keep only go-odoo core files
GO111MODULE="off" go generate
```bash
./generator/generator -u admin_name -p admin_password -d database_name -o /the/directory/you/want/the/files/to/be/generated/in --url http://localhost:8069 -t ./generator/cmd/tmpl/model.tmpl -m crm.lead,res.users
```

That's it ! Your models have been generated !
Expand Down Expand Up @@ -67,9 +44,9 @@ import (

func main() {
c, err := odoo.NewClient(&odoo.ClientConfig{
Admin: "admin",
Password: "password",
Database: "odoo",
Admin: "admin_name",
Password: "admin_password",
Database: "database_name",
URL: "http://localhost:8069",
})
if err != nil {
Expand Down
4 changes: 4 additions & 0 deletions generator/cmd/generator.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cmd

import (
"errors"
"fmt"
"os"
"os/exec"
Expand Down Expand Up @@ -80,6 +81,9 @@ func (g *generator) getAllModelsName() ([]string, error) {
func (g *generator) modelFieldsFromModel(model string) ([]*modelField, error) {
imfs, err := g.odoo.FindIrModelFieldss(odoo.NewCriteria().Add("model", "=", model), nil)
if err != nil {
if errors.Is(err, odoo.ErrNotFound) {
return nil, nil
}
return nil, err
}
return g.irModelFieldsToModelFields(imfs), nil
Expand Down
26 changes: 14 additions & 12 deletions generator/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (

var (
rootCmd = &cobra.Command{
Use: "./go-odoo -u admin -p admin -d odoo --url http://localhost:8069 --models crm.lead",
Use: "./go-odoo -u admin -p admin -d odoo --url http://localhost:8069 --models crm.lead -t generator/cmd/tmpl/model.tmpl",
Short: "Generates your odoo models for go-odoo golang library.",
Long: `
Generates your odoo models for go-odoo golang library.
Expand All @@ -29,16 +29,17 @@ You can provide models name as arguments to specify what models to generate. By
}
},
}
database string
admin string
password string
url string
noFmt bool
destFolder string
models string
c *odoo.Client
t *template.Template
g *generator
database string
admin string
password string
url string
noFmt bool
destFolder string
models string
modelTemplate string
c *odoo.Client
t *template.Template
g *generator
)

// Execute executes the root command.
Expand All @@ -57,6 +58,7 @@ func init() {
rootCmd.PersistentFlags().StringVar(&url, "url", "http://localhost:8069", "the url of your odoo instance")
rootCmd.PersistentFlags().StringVarP(&destFolder, "dest", "o", "", "the destination of generated models")
rootCmd.PersistentFlags().StringVarP(&models, "models", "m", "", "the models you want to generate, separated by commas, empty means generate all")
rootCmd.PersistentFlags().StringVarP(&modelTemplate, "template", "t", "", "the model template location used to generate the models code")
rootCmd.PersistentFlags().BoolVar(&noFmt, "no-fmt", false, "specify if you want to disable auto format of generated models")
}

Expand All @@ -78,7 +80,7 @@ func initOdoo() {

func initTemplate() {
var err error
if t, err = template.New("model.tmpl").ParseFiles("./generator/cmd/tmpl/model.tmpl"); err != nil {
if t, err = template.New("model.tmpl").ParseFiles(modelTemplate); err != nil {
handleError(err)
}
}
Expand Down
25 changes: 4 additions & 21 deletions generator/cmd/tmpl/model.tmpl
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
package odoo

import (
"fmt"
)

// {{.StructName}} represents {{ .Name }} model.
type {{.StructName}} struct { {{range .Fields}}
{{.VarName}} {{.Type}} `xmlrpc:"{{.Name}},omptempty"`{{end }}
Expand Down Expand Up @@ -68,10 +64,7 @@ func (c *Client) Get{{.StructName}}(id int64) (*{{.StructName}}, error) {
if err != nil {
return nil, err
}
if {{.VarsName}} != nil && len(*{{.VarsName}}) > 0 {
return &((*{{.VarsName}})[0]), nil
}
return nil, fmt.Errorf("id %v of {{.Name}} not found", id)
return &((*{{.VarsName}})[0]), nil
}

// Get{{.StructName}}s gets {{ .Name }} existing records.
Expand All @@ -89,10 +82,7 @@ func (c *Client) Find{{.StructName}}(criteria *Criteria) (*{{.StructName}}, erro
if err := c.SearchRead({{.StructName}}Model, criteria, NewOptions().Limit(1), {{.VarsName}}); err != nil {
return nil, err
}
if {{.VarsName}} != nil && len(*{{.VarsName}}) > 0 {
return &((*{{.VarsName}})[0]), nil
}
return nil, fmt.Errorf("{{ .Name }} was not found with criteria %v", criteria)
return &((*{{.VarsName}})[0]), nil
}

// Find{{.StructName}}s finds {{ .Name }} records by querying it
Expand All @@ -108,11 +98,7 @@ func (c *Client) Find{{.StructName}}s(criteria *Criteria, options *Options) (*{{
// Find{{.StructName}}Ids finds records ids by querying it
// and filtering it with criteria and options.
func (c *Client) Find{{.StructName}}Ids(criteria *Criteria, options *Options) ([]int64, error) {
ids, err := c.Search({{.StructName}}Model, criteria, options)
if err != nil {
return []int64{}, err
}
return ids, nil
return c.Search({{.StructName}}Model, criteria, options)
}

// Find{{.StructName}}Id finds record id by querying it with criteria.
Expand All @@ -121,8 +107,5 @@ func (c *Client) Find{{.StructName}}Id(criteria *Criteria, options *Options) (in
if err != nil {
return -1, err
}
if len(ids) > 0 {
return ids[0], nil
}
return -1, fmt.Errorf("{{ .Name }} was not found with criteria %v and options %v", criteria, options)
return ids[0], nil
}
Binary file modified generator/generator
Binary file not shown.
32 changes: 25 additions & 7 deletions odoo.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
//Package odoo contains client code of library
//go:generate ./generator/generator -u $ODOO_ADMIN -p $ODOO_PASSWORD -d $ODOO_DATABASE --url $ODOO_URL -o $ODOO_REPO_PATH --models $ODOO_MODELS
//go:generate ./generator/generator -u $ODOO_ADMIN -p $ODOO_PASSWORD -d $ODOO_DATABASE --url $ODOO_URL -o $ODOO_REPO_PATH --models $ODOO_MODELS -t generator/cmd/tmpl/model.tmpl
package odoo

import (
"errors"
"fmt"
"log"

"github.com/kolo/xmlrpc"
)

var (
errClientConfigurationInvalid = errors.New("client configuration is invalid")
errClientNotAuthenticate = errors.New("client is not authenticate")
errClientAuthentication = errors.New("client authentication error: please verify client configuration")
ErrClientConfigurationInvalid = errors.New("client configuration is invalid")
ErrClientNotAuthenticate = errors.New("client is not authenticate")
ErrClientAuthentication = errors.New("client authentication error: please verify client configuration")
ErrNotFound = errors.New("not found")
ErrPartiallyFound = errors.New("partially found")
)

// ClientConfig is the configuration to create a new *Client by givin connection infomations.
Expand Down Expand Up @@ -42,7 +45,7 @@ type Client struct {
// NewClient creates a new *Client.
func NewClient(cfg *ClientConfig) (*Client, error) {
if !cfg.valid() {
return nil, errClientConfigurationInvalid
return nil, ErrClientConfigurationInvalid
}
c := &Client{
cfg: cfg,
Expand Down Expand Up @@ -279,6 +282,10 @@ func (c *Client) SearchRead(model string, criteria *Criteria, options *Options,
if err != nil {
return err
}
respLen := len(resp.([]interface{}))
if respLen == 0 {
return fmt.Errorf("%s model was %w with criteria %v and options %v", model, ErrNotFound, criteria, options)
}
if err := convertFromDynamicToStatic(resp, elem); err != nil {
return err
}
Expand All @@ -292,9 +299,16 @@ func (c *Client) Read(model string, ids []int64, options *Options, elem interfac
if err != nil {
return err
}
respLen := len(resp.([]interface{}))
if respLen == 0 {
return fmt.Errorf("%s ids %v was %w with options %v", model, ids, ErrNotFound, options)
}
if err := convertFromDynamicToStatic(resp, elem); err != nil {
return err
}
if respLen != len(ids) {
return fmt.Errorf("%s ids %v was %w with options %v", model, ids, ErrPartiallyFound, options)
}
return nil
}

Expand All @@ -315,6 +329,10 @@ func (c *Client) Search(model string, criteria *Criteria, options *Options) ([]i
if err != nil {
return []int64{}, err
}
respLen := len(resp.([]interface{}))
if respLen == 0 {
return []int64{}, fmt.Errorf("%s model was %w with criteria %v and options %v", model, ErrNotFound, criteria, options)
}
return sliceInterfaceToInt64Slice(resp.([]interface{})), nil
}

Expand Down Expand Up @@ -348,7 +366,7 @@ func (c *Client) authenticate() error {
return err
}
if _, ok := resp.(bool); ok {
return errClientAuthentication
return ErrClientAuthentication
}
c.uid = resp.(int64)
c.auth = true
Expand Down Expand Up @@ -407,7 +425,7 @@ func (c *Client) loadXmlrpcClient(x *xmlrpc.Client, path string) error {

func (c *Client) checkForAuthentication() error {
if !c.isAuthenticate() {
return errClientNotAuthenticate
return ErrClientNotAuthenticate
}
return nil
}
Expand Down

0 comments on commit 462cbb1

Please sign in to comment.