go-on-rails 0.3.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +30 -20
- data/lib/generators/USAGE +11 -9
- data/lib/generators/gor/converter.rb +1 -1
- data/lib/generators/gor_generator.rb +8 -2
- data/lib/generators/templates/Dockerfile.go_app.erb +1 -1
- data/lib/generators/templates/Makefile +2 -2
- data/lib/generators/templates/docker-compose.yml.erb +3 -3
- data/lib/generators/templates/{gor_model.go.erb → gor_model_mysql.go.erb} +5 -31
- data/lib/generators/templates/gor_model_postgres.go.erb +988 -0
- data/lib/generators/templates/index.tmpl +1 -1
- data/lib/generators/templates/utils.go.erb +23 -0
- data/lib/tasks/gor.rake +1 -1
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1300efab528e68b02247041903cca19315b3dd3d
|
4
|
+
data.tar.gz: 64888a3675703678a9c470a993a41296ca7c0535
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ef7e09edb3d98d4f81b70037f4c5c41b0306542ca4e633bd98fd2bc5e7404aabe51b793a06101ad68389329149b183725b4dd11cde4e59fb66714997b04aee5c
|
7
|
+
data.tar.gz: 9759b05c07feef1658c603d63a20ad668e520da32af309683b0044a382a56850c936c08ae8fa1ad4a414c778427fbd5147133678920a707936d64dad67b7da30
|
data/README.md
CHANGED
@@ -1,12 +1,16 @@
|
|
1
|
+
<p align="center">
|
2
|
+
<img width="260" height="260" src="./go-on-rails.png">
|
3
|
+
</p>
|
4
|
+
|
1
5
|
[![Gem Version](https://badge.fury.io/rb/go-on-rails.svg)](https://badge.fury.io/rb/go-on-rails)
|
2
|
-
[![Build Status](https://travis-ci.org/
|
3
|
-
[![Maintainability](https://api.codeclimate.com/v1/badges/6fba1f226f027a14c19b/maintainability)](https://codeclimate.com/github/
|
6
|
+
[![Build Status](https://travis-ci.org/railstack/go-on-rails.svg?branch=dev)](https://travis-ci.org/railstack/go-on-rails)
|
7
|
+
[![Maintainability](https://api.codeclimate.com/v1/badges/6fba1f226f027a14c19b/maintainability)](https://codeclimate.com/github/railstack/go-on-rails/maintainability)
|
8
|
+
[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/railstack/go-on-rails/blob/master/MIT-LICENSE)
|
4
9
|
|
5
|
-
<img align="right" width="260" height="260" src="./go-on-rails.png">
|
6
10
|
|
7
11
|
# Go on Rails
|
8
12
|
|
9
|
-
[
|
13
|
+
[用 Rails 开发 Go 应用:中文文档](./README_zh.md)
|
10
14
|
|
11
15
|
`go-on-rails` is a Rails generator aims to:
|
12
16
|
|
@@ -15,9 +19,9 @@
|
|
15
19
|
3. Convert a *not very complicated* Rails app to Golang equivalent
|
16
20
|
|
17
21
|
Here's some examples:
|
18
|
-
* A simple [example(tutorial)](https://github.com/
|
19
|
-
* [An advanced example](https://github.com/
|
20
|
-
* [Another example](https://github.com/
|
22
|
+
* A simple [example(tutorial)](https://github.com/railstack/example_simple) on the basic usage of go-on-rails generator
|
23
|
+
* [An advanced example](https://github.com/railstack/example_with_admin) shows how to integrate Go APIs in a Rails project
|
24
|
+
* [Another example](https://github.com/railstack/example_read_rails_session) shows how to handle a Rails session to get an user's info in a go-on-rails generated Go API
|
21
25
|
|
22
26
|
## Prerequisites
|
23
27
|
|
@@ -48,10 +52,16 @@ You must have an existed Rails app or to create a new one before you try go-on-r
|
|
48
52
|
After that you can run the command just as other Rails generators:
|
49
53
|
|
50
54
|
```bash
|
51
|
-
|
55
|
+
rails g gor [dev(elopment) | pro(duction) | test | ...] [-m model_a model_b model_c ...]
|
52
56
|
|
53
57
|
# OR (on rails version < 5.0)
|
54
|
-
|
58
|
+
rake g gor ...
|
59
|
+
```
|
60
|
+
|
61
|
+
here we take generating all models for the `development` environment for example:
|
62
|
+
|
63
|
+
```bash
|
64
|
+
rails g gor dev
|
55
65
|
```
|
56
66
|
|
57
67
|
Then a folder named `go_app` that includes Golang codes will be generated under your Rails app root path.
|
@@ -59,7 +69,7 @@ Then a folder named `go_app` that includes Golang codes will be generated under
|
|
59
69
|
Install the dependent Golang packages for this Go project:
|
60
70
|
|
61
71
|
```bash
|
62
|
-
|
72
|
+
rails gor:deps
|
63
73
|
```
|
64
74
|
|
65
75
|
Then change to the `go_app` directory and run:
|
@@ -73,7 +83,7 @@ You can visit the page in http://localhost:4000 by default.
|
|
73
83
|
More command details about go-on-rails generator:
|
74
84
|
|
75
85
|
```bash
|
76
|
-
|
86
|
+
rails g gor --help
|
77
87
|
```
|
78
88
|
|
79
89
|
## What will be generated?
|
@@ -92,7 +102,7 @@ You can view the godoc page of all functions in http://localhost:7979/doc/models
|
|
92
102
|
bundle exec rails gor:doc
|
93
103
|
```
|
94
104
|
|
95
|
-
Besides, there's [a sample project](https://github.com/
|
105
|
+
Besides, there's [a sample project](https://github.com/railstack/gor_models_sample) generated by go-on-rails, you can view its [godoc](https://godoc.org/github.com/railstack/gor_models_sample) at godoc.org just now to get a picture of what functions are generated.
|
96
106
|
|
97
107
|
|
98
108
|
## Known issues and TODOs
|
@@ -100,7 +110,7 @@ Besides, there's [a sample project](https://github.com/goonr/gor_models_sample)
|
|
100
110
|
The gem is still under development, so there're some known issues.
|
101
111
|
|
102
112
|
* databases specific functions between MySQL and Postgres or other databases are not covered yet
|
103
|
-
* sql.NullType not supported yet, so you'd better in the migrations set those columns "not null" with a default value that's consistent with Golang's zero value specification, such as "" default for string and text typed column, and 0 default for int, etc. And now we have an alternative approch for manipulating the database nullable fields, see the wiki [Working with database nullable fields](https://github.com/
|
113
|
+
* sql.NullType not supported yet, so you'd better in the migrations set those columns "not null" with a default value that's consistent with Golang's zero value specification, such as "" default for string and text typed column, and 0 default for int, etc. And now we have an alternative approch for manipulating the database nullable fields, see the wiki [Working with database nullable fields](https://github.com/railstack/go-on-rails/wiki/Working-with-database-nullable-fields)
|
104
114
|
|
105
115
|
- [x] Associations
|
106
116
|
- [x] has_many
|
@@ -113,21 +123,21 @@ The gem is still under development, so there're some known issues.
|
|
113
123
|
- [x] format(string only)
|
114
124
|
- [x] numericality(partially)
|
115
125
|
- [ ] other validations
|
116
|
-
- [x] Pagination(details see [wiki](https://github.com/
|
126
|
+
- [x] Pagination(details see [wiki](https://github.com/railstack/go-on-rails/wiki/Pagination))
|
117
127
|
- [ ] Callbacks
|
118
128
|
- [ ] Transactions
|
119
129
|
|
120
130
|
## Wiki
|
121
131
|
|
122
|
-
* [Built-in Pagination](https://github.com/
|
123
|
-
* [Working with database nullable fields](https://github.com/
|
124
|
-
* [Some Make commands](https://github.com/
|
125
|
-
* [Dockerize a Go-on-Rails application](https://github.com/
|
132
|
+
* [Built-in Pagination](https://github.com/railstack/go-on-rails/wiki/Pagination)
|
133
|
+
* [Working with database nullable fields](https://github.com/railstack/go-on-rails/wiki/Working-with-database-nullable-fields)
|
134
|
+
* [Some Make commands](https://github.com/railstack/go-on-rails/wiki/Some-Make-commands)
|
135
|
+
* [Dockerize a Go-on-Rails application](https://github.com/railstack/go-on-rails/wiki/Dockerize-a-Go-on-Rails-application)
|
126
136
|
|
127
137
|
## Golang dependencies by default
|
128
138
|
|
129
139
|
* [github.com/jmoiron/sqlx](https://github.com/jmoiron/sqlx): an extension on the standard `database/sql` database API library
|
130
|
-
* [github.com/
|
140
|
+
* [github.com/railstack/go-sqlite3](https://github.com/railstack/go-sqlite3): a SQLite driver(This's a forked version of [mattn/go-sqlite3](https://github.com/mattn/go-sqlite3), and This is [why we use this forked version](https://github.com/mattn/go-sqlite3/pull/468))
|
131
141
|
* [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql): a MySQL driver
|
132
142
|
* [github.com/lib/pq](https://github.com/lib/pq): a PostgreSQL driver
|
133
143
|
* [github.com/asaskevich/govalidator](https://github.com/asaskevich/govalidator): for the struct validation
|
@@ -162,4 +172,4 @@ Run `rails db:seed` to use the data defined in `db/seeds.rb`. And change to `go_
|
|
162
172
|
|
163
173
|
## License
|
164
174
|
|
165
|
-
See the [LICENSE](https://github.com/
|
175
|
+
See the [LICENSE](https://github.com/railstack/go-on-rails/blob/master/MIT-LICENSE) file.
|
data/lib/generators/USAGE
CHANGED
@@ -1,30 +1,32 @@
|
|
1
1
|
Description:
|
2
|
-
|
2
|
+
Generate Golang app by Rails models: use Rails as a model and migration tool to build a Golang app, or migrate some of existed Rails APIs to Golang to decouple and high-perform your services.
|
3
3
|
|
4
|
-
|
4
|
+
Read more: https://github.com/railstack/go-on-rails
|
5
5
|
|
6
6
|
|
7
7
|
Example:
|
8
8
|
rails generate gor development -m user post
|
9
9
|
|
10
|
-
Here are valid ENV_NAME arguments: [dev, development, pro, production, test]
|
10
|
+
Here are valid ENV_NAME arguments by default for a Rails generated database configuration by default: [dev, development, pro, production, test]. The default ENV_NAME is "development" if you omit one. Obviously, you can reconfig the config/database.yml to define your environments.
|
11
11
|
|
12
12
|
So you can also run:
|
13
13
|
|
14
14
|
rails g gor dev -m user post
|
15
15
|
|
16
16
|
This will mainly create:
|
17
|
+
go_app/Dockerfile
|
18
|
+
go_app/Makefile
|
17
19
|
go_app/main.go
|
18
|
-
go_app/
|
19
|
-
go_app/models/
|
20
|
-
go_app/models/
|
20
|
+
go_app/models/doc/models.html
|
21
|
+
go_app/models/db.go
|
22
|
+
go_app/models/gor_user.go
|
23
|
+
go_app/models/gor_post.go
|
21
24
|
|
22
25
|
Notice: If you omit the -m option, all the models of the Rails app will be generated.
|
23
26
|
|
24
|
-
|
27
|
+
If you omit all the options, just run:
|
25
28
|
|
26
29
|
rails g gor
|
27
30
|
|
28
|
-
This will generate all the models and database connection
|
29
|
-
|
31
|
+
This will generate code of all the models and database connection in Rails development environment.
|
30
32
|
|
@@ -16,7 +16,7 @@ module GoOnRails
|
|
16
16
|
}.freeze
|
17
17
|
|
18
18
|
# COALESCE datetime typed field for different databases
|
19
|
-
# sqlite3 is dependent on the driver: https://github.com/
|
19
|
+
# sqlite3 is dependent on the driver: https://github.com/railstack/go-sqlite3, details see: https://github.com/mattn/go-sqlite3/pull/468
|
20
20
|
DATETIME_COALESCE_MAP = {
|
21
21
|
"sqlite3" => "CAST(COALESCE(%s, '0001-01-01T00:00:00Z') as text) AS %s",
|
22
22
|
"mysql" => "COALESCE(%s, CONVERT_TZ('0001-01-01 00:00:00','+00:00','UTC')) AS %s",
|
@@ -50,11 +50,17 @@ class GorGenerator < Rails::Generators::Base
|
|
50
50
|
# iterate the structs info to generate codes for each model
|
51
51
|
@all_structs_info.each do |k, v|
|
52
52
|
@model_name, @struct_info = k, v
|
53
|
-
|
53
|
+
if @db_config[:driver_name] == "postgres"
|
54
|
+
template "gor_model_postgres.go.erb", "go_app/models/gor_#{@model_name.underscore}.go"
|
55
|
+
else
|
56
|
+
template "gor_model_mysql.go.erb", "go_app/models/gor_#{@model_name.underscore}.go"
|
57
|
+
end
|
54
58
|
end
|
55
59
|
|
56
60
|
# generate program for database connection
|
57
61
|
template "db.go.erb", "go_app/models/db.go"
|
62
|
+
# and utils
|
63
|
+
template "utils.go.erb", "go_app/models/utils.go"
|
58
64
|
|
59
65
|
unless options[:only_models]
|
60
66
|
# generate the main.go
|
@@ -91,7 +97,7 @@ class GorGenerator < Rails::Generators::Base
|
|
91
97
|
when "sqlite3"
|
92
98
|
@db_config[:driver_name] = "sqlite3"
|
93
99
|
@db_config[:dsn] = Rails.root.join(@db_config[:database]).to_s
|
94
|
-
@db_config[:driver_package] = "_ \"github.com/
|
100
|
+
@db_config[:driver_package] = "_ \"github.com/railstack/go-sqlite3\""
|
95
101
|
when "mysql2"
|
96
102
|
@db_config[:driver_name] = "mysql"
|
97
103
|
@db_config[:port] ||= "3306"
|
@@ -6,7 +6,7 @@ FROM golang:1.9.2 as builder
|
|
6
6
|
WORKDIR /root/
|
7
7
|
COPY . /root/
|
8
8
|
<%- if %w[127.0.0.1 localhost].include? @db_config[:host] and @db_config[:driver_name] != "sqlite3" -%>
|
9
|
-
RUN perl -pi -e "s/tcp\(.*?:/tcp\(
|
9
|
+
RUN perl -pi -e "s/tcp\(.*?:/tcp\(db:/; s/host=\S+? /host=db /" models/db.go
|
10
10
|
<%- end -%>
|
11
11
|
RUN make deps
|
12
12
|
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o myapp .
|
@@ -15,13 +15,13 @@ build: $(MYAPP)
|
|
15
15
|
deps:
|
16
16
|
$(GO) get -u github.com/jmoiron/sqlx \
|
17
17
|
github.com/gin-gonic/gin \
|
18
|
-
github.com/
|
18
|
+
github.com/railstack/go-sqlite3 \
|
19
19
|
github.com/go-sql-driver/mysql \
|
20
20
|
github.com/lib/pq \
|
21
21
|
github.com/asaskevich/govalidator
|
22
22
|
|
23
23
|
test:
|
24
|
-
$(GO) test -v
|
24
|
+
$(GO) test -v ./...
|
25
25
|
|
26
26
|
run: $(MYAPP)
|
27
27
|
./$(MYAPP)
|
@@ -3,7 +3,7 @@ version: '3'
|
|
3
3
|
services:
|
4
4
|
<%- if %w[127.0.0.1 localhost].include? @db_config[:host] and @db_config[:driver_name] != "sqlite3" -%>
|
5
5
|
# generated according to the config/database.yml
|
6
|
-
|
6
|
+
db:
|
7
7
|
image: <%= @db_config[:driver_name] %>
|
8
8
|
ports:
|
9
9
|
- '<%= @db_config[:port] %>:<%= @db_config[:port] %>'
|
@@ -18,7 +18,7 @@ services:
|
|
18
18
|
- "3000:3000"
|
19
19
|
<%- if %w[127.0.0.1 localhost].include? @db_config[:host] and @db_config[:driver_name] != "sqlite3" -%>
|
20
20
|
depends_on:
|
21
|
-
-
|
21
|
+
- db
|
22
22
|
<%- end -%>
|
23
23
|
|
24
24
|
# golang app part. It depends on the rails_app to initialize the database
|
@@ -32,6 +32,6 @@ services:
|
|
32
32
|
- "4000:4000"
|
33
33
|
depends_on:
|
34
34
|
<%- if %w[127.0.0.1 localhost].include? @db_config[:host] and @db_config[:driver_name] != "sqlite3" -%>
|
35
|
-
-
|
35
|
+
- db
|
36
36
|
<%- end -%>
|
37
37
|
- rails_app
|
@@ -1,5 +1,5 @@
|
|
1
1
|
<%#- var_pmn stands for pluralized model name, its format is same as the table name -#%>
|
2
|
-
<%- var_pmn = table_name = @model_name.
|
2
|
+
<%- var_pmn = table_name = @model_name.tableize -%>
|
3
3
|
<%#- var_umn stands for underscored model name -#%>
|
4
4
|
<%- var_umn = @model_name.underscore -%>
|
5
5
|
<%- fields = @struct_info[:select_fields] -%>
|
@@ -57,11 +57,7 @@ func (_p *<%= @model_name %>Page) Current() ([]<%= @model_name %>, error) {
|
|
57
57
|
_p.buildOrder()
|
58
58
|
}
|
59
59
|
idStr, idParams := _p.buildIdRestrict("current")
|
60
|
-
<% if @db_config[:driver_name] == "postgres" %>
|
61
|
-
whereStr := fmt.Sprintf("%s %s %s FETCH NEXT %v ROWS ONLY", _p.WhereString, idStr, _p.orderStr, _p.PerPage)
|
62
|
-
<% else %>
|
63
60
|
whereStr := fmt.Sprintf("%s %s %s LIMIT %v", _p.WhereString, idStr, _p.orderStr, _p.PerPage)
|
64
|
-
<% end %>
|
65
61
|
whereParams := []interface{}{}
|
66
62
|
whereParams = append(append(whereParams, _p.WhereParams...), idParams...)
|
67
63
|
<%= var_pmn %>, err := Find<%= @model_name.pluralize %>Where(whereStr, whereParams...)
|
@@ -90,11 +86,7 @@ func (_p *<%= @model_name %>Page) Previous() ([]<%= @model_name %>, error) {
|
|
90
86
|
_p.buildOrder()
|
91
87
|
}
|
92
88
|
idStr, idParams := _p.buildIdRestrict("previous")
|
93
|
-
<% if @db_config[:driver_name] == "postgres" %>
|
94
|
-
whereStr := fmt.Sprintf("%s %s %s FETCH NEXT %v ROWS ONLY", _p.WhereString, idStr, _p.orderStr, _p.PerPage)
|
95
|
-
<% else %>
|
96
89
|
whereStr := fmt.Sprintf("%s %s %s LIMIT %v", _p.WhereString, idStr, _p.orderStr, _p.PerPage)
|
97
|
-
<% end %>
|
98
90
|
whereParams := []interface{}{}
|
99
91
|
whereParams = append(append(whereParams, _p.WhereParams...), idParams...)
|
100
92
|
<%= var_pmn %>, err := Find<%= @model_name.pluralize %>Where(whereStr, whereParams...)
|
@@ -124,11 +116,7 @@ func (_p *<%= @model_name %>Page) Next() ([]<%= @model_name %>, error) {
|
|
124
116
|
_p.buildOrder()
|
125
117
|
}
|
126
118
|
idStr, idParams := _p.buildIdRestrict("next")
|
127
|
-
<% if @db_config[:driver_name] == "postgres" %>
|
128
|
-
whereStr := fmt.Sprintf("%s %s %s FETCH NEXT %v ROWS ONLY", _p.WhereString, idStr, _p.orderStr, _p.PerPage)
|
129
|
-
<% else %>
|
130
119
|
whereStr := fmt.Sprintf("%s %s %s LIMIT %v", _p.WhereString, idStr, _p.orderStr, _p.PerPage)
|
131
|
-
<% end %>
|
132
120
|
whereParams := []interface{}{}
|
133
121
|
whereParams = append(append(whereParams, _p.WhereParams...), idParams...)
|
134
122
|
<%= var_pmn %>, err := Find<%= @model_name.pluralize %>Where(whereStr, whereParams...)
|
@@ -593,15 +581,10 @@ func Create<%= @model_name %>(am map[string]interface{}) (int64, error) {
|
|
593
581
|
}
|
594
582
|
}
|
595
583
|
<%- end -%>
|
596
|
-
keys :=
|
597
|
-
i := 0
|
598
|
-
for k := range am {
|
599
|
-
keys[i] = k
|
600
|
-
i++
|
601
|
-
}
|
584
|
+
keys := allKeys(am)
|
602
585
|
sqlFmt := `INSERT INTO <%= table_name %> (%s) VALUES (%s)`
|
603
|
-
|
604
|
-
result, err := DB.NamedExec(
|
586
|
+
sql := fmt.Sprintf(sqlFmt, strings.Join(keys, ","), ":"+strings.Join(keys, ",:"))
|
587
|
+
result, err := DB.NamedExec(sql, am)
|
605
588
|
if err != nil {
|
606
589
|
log.Println(err)
|
607
590
|
return 0, err
|
@@ -940,12 +923,7 @@ func Update<%= @model_name %>(id int64, am map[string]interface{}) error {
|
|
940
923
|
<%- if @struct_info[:timestamp_cols].include? "updated_at" -%>
|
941
924
|
am["updated_at"] = time.Now()
|
942
925
|
<%- end -%>
|
943
|
-
keys :=
|
944
|
-
i := 0
|
945
|
-
for k := range am {
|
946
|
-
keys[i] = k
|
947
|
-
i++
|
948
|
-
}
|
926
|
+
keys := allKeys(am)
|
949
927
|
sqlFmt := `UPDATE <%= table_name %> SET %s WHERE id = %v`
|
950
928
|
setKeysArr := []string{}
|
951
929
|
for _,v := range keys {
|
@@ -994,10 +972,6 @@ func Update<%= @model_name.pluralize %>BySql(sql string, args ...interface{}) (i
|
|
994
972
|
if sql == "" {
|
995
973
|
return 0, errors.New("A blank SQL clause")
|
996
974
|
}
|
997
|
-
<%- if @struct_info[:timestamp_cols].include? "updated_at" -%>
|
998
|
-
sql = strings.Replace(strings.ToLower(sql), "set", "set updated_at = ?, ", 1)
|
999
|
-
args = append([]interface{}{time.Now()}, args...)
|
1000
|
-
<%- end -%>
|
1001
975
|
stmt, err := DB.Preparex(DB.Rebind(sql))
|
1002
976
|
result, err := stmt.Exec(args...)
|
1003
977
|
if err != nil {
|
@@ -0,0 +1,988 @@
|
|
1
|
+
<%#- var_pmn stands for pluralized model name, its format is same as the table name -#%>
|
2
|
+
<%- var_pmn = table_name = @model_name.tableize -%>
|
3
|
+
<%#- var_umn stands for underscored model name -#%>
|
4
|
+
<%- var_umn = @model_name.underscore -%>
|
5
|
+
<%- fields = @struct_info[:select_fields] -%>
|
6
|
+
<%- col_names = @struct_info[:col_names] -%>
|
7
|
+
<%- has_assoc = !@struct_info[:assoc_info][:has_many].empty? || !@struct_info[:assoc_info][:has_one].empty? -%>
|
8
|
+
// Package models includes the functions on the model <%= @model_name %>.
|
9
|
+
package models
|
10
|
+
|
11
|
+
import (
|
12
|
+
"errors"
|
13
|
+
"fmt"
|
14
|
+
"log"
|
15
|
+
"math"
|
16
|
+
"strings"
|
17
|
+
<%- if @struct_info[:has_datetime_type] -%>
|
18
|
+
"time"
|
19
|
+
<%- end -%>
|
20
|
+
|
21
|
+
"github.com/asaskevich/govalidator"
|
22
|
+
)
|
23
|
+
|
24
|
+
// set flags to output more detailed log
|
25
|
+
func init() {
|
26
|
+
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
27
|
+
}
|
28
|
+
|
29
|
+
type <%= @model_name %> struct {
|
30
|
+
<%= @struct_info[:struct_body] -%>
|
31
|
+
}
|
32
|
+
|
33
|
+
// DataStruct for the pagination
|
34
|
+
type <%= @model_name %>Page struct {
|
35
|
+
WhereString string
|
36
|
+
WhereParams []interface{}
|
37
|
+
Order map[string]string
|
38
|
+
FirstId int64
|
39
|
+
LastId int64
|
40
|
+
PageNum int
|
41
|
+
PerPage int
|
42
|
+
TotalPages int
|
43
|
+
TotalItems int64
|
44
|
+
orderStr string
|
45
|
+
}
|
46
|
+
|
47
|
+
// Current get the current page of <%= @model_name %>Page object for pagination.
|
48
|
+
func (_p *<%= @model_name %>Page) Current() ([]<%= @model_name %>, error) {
|
49
|
+
if _, exist := _p.Order["id"]; !exist {
|
50
|
+
return nil, errors.New("No id order specified in Order map")
|
51
|
+
}
|
52
|
+
err := _p.buildPageCount()
|
53
|
+
if err != nil {
|
54
|
+
return nil, fmt.Errorf("Calculate page count error: %v", err)
|
55
|
+
}
|
56
|
+
if _p.orderStr == "" {
|
57
|
+
_p.buildOrder()
|
58
|
+
}
|
59
|
+
idStr, idParams := _p.buildIdRestrict("current")
|
60
|
+
whereStr := fmt.Sprintf("%s %s %s FETCH NEXT %v ROWS ONLY", _p.WhereString, idStr, _p.orderStr, _p.PerPage)
|
61
|
+
whereParams := []interface{}{}
|
62
|
+
whereParams = append(append(whereParams, _p.WhereParams...), idParams...)
|
63
|
+
<%= var_pmn %>, err := Find<%= @model_name.pluralize %>Where(whereStr, whereParams...)
|
64
|
+
if err != nil {
|
65
|
+
return nil, err
|
66
|
+
}
|
67
|
+
if len(<%= var_pmn %>) != 0 {
|
68
|
+
_p.FirstId, _p.LastId = <%= var_pmn %>[0].Id, <%= var_pmn %>[len(<%= var_pmn %>)-1].Id
|
69
|
+
}
|
70
|
+
return <%= var_pmn %>, nil
|
71
|
+
}
|
72
|
+
|
73
|
+
// Previous get the previous page of <%= @model_name %>Page object for pagination.
|
74
|
+
func (_p *<%= @model_name %>Page) Previous() ([]<%= @model_name %>, error) {
|
75
|
+
if _p.PageNum == 0 {
|
76
|
+
return nil, errors.New("This's the first page, no previous page yet")
|
77
|
+
}
|
78
|
+
if _, exist := _p.Order["id"]; !exist {
|
79
|
+
return nil, errors.New("No id order specified in Order map")
|
80
|
+
}
|
81
|
+
err := _p.buildPageCount()
|
82
|
+
if err != nil {
|
83
|
+
return nil, fmt.Errorf("Calculate page count error: %v", err)
|
84
|
+
}
|
85
|
+
if _p.orderStr == "" {
|
86
|
+
_p.buildOrder()
|
87
|
+
}
|
88
|
+
idStr, idParams := _p.buildIdRestrict("previous")
|
89
|
+
whereStr := fmt.Sprintf("%s %s %s FETCH NEXT %v ROWS ONLY", _p.WhereString, idStr, _p.orderStr, _p.PerPage)
|
90
|
+
whereParams := []interface{}{}
|
91
|
+
whereParams = append(append(whereParams, _p.WhereParams...), idParams...)
|
92
|
+
<%= var_pmn %>, err := Find<%= @model_name.pluralize %>Where(whereStr, whereParams...)
|
93
|
+
if err != nil {
|
94
|
+
return nil, err
|
95
|
+
}
|
96
|
+
if len(<%= var_pmn %>) != 0 {
|
97
|
+
_p.FirstId, _p.LastId = <%= var_pmn %>[0].Id, <%= var_pmn %>[len(<%= var_pmn %>)-1].Id
|
98
|
+
}
|
99
|
+
_p.PageNum -= 1
|
100
|
+
return <%= var_pmn %>, nil
|
101
|
+
}
|
102
|
+
|
103
|
+
// Next get the next page of <%= @model_name %>Page object for pagination.
|
104
|
+
func (_p *<%= @model_name %>Page) Next() ([]<%= @model_name %>, error) {
|
105
|
+
if _p.PageNum == _p.TotalPages-1 {
|
106
|
+
return nil, errors.New("This's the last page, no next page yet")
|
107
|
+
}
|
108
|
+
if _, exist := _p.Order["id"]; !exist {
|
109
|
+
return nil, errors.New("No id order specified in Order map")
|
110
|
+
}
|
111
|
+
err := _p.buildPageCount()
|
112
|
+
if err != nil {
|
113
|
+
return nil, fmt.Errorf("Calculate page count error: %v", err)
|
114
|
+
}
|
115
|
+
if _p.orderStr == "" {
|
116
|
+
_p.buildOrder()
|
117
|
+
}
|
118
|
+
idStr, idParams := _p.buildIdRestrict("next")
|
119
|
+
whereStr := fmt.Sprintf("%s %s %s FETCH NEXT %v ROWS ONLY", _p.WhereString, idStr, _p.orderStr, _p.PerPage)
|
120
|
+
whereParams := []interface{}{}
|
121
|
+
whereParams = append(append(whereParams, _p.WhereParams...), idParams...)
|
122
|
+
<%= var_pmn %>, err := Find<%= @model_name.pluralize %>Where(whereStr, whereParams...)
|
123
|
+
if err != nil {
|
124
|
+
return nil, err
|
125
|
+
}
|
126
|
+
if len(<%= var_pmn %>) != 0 {
|
127
|
+
_p.FirstId, _p.LastId = <%= var_pmn %>[0].Id, <%= var_pmn %>[len(<%= var_pmn %>)-1].Id
|
128
|
+
}
|
129
|
+
_p.PageNum += 1
|
130
|
+
return <%= var_pmn %>, nil
|
131
|
+
}
|
132
|
+
|
133
|
+
// GetPage is a helper function for the <%= @model_name %>Page object to return a corresponding page due to
|
134
|
+
// the parameter passed in, i.e. one of "previous, current or next".
|
135
|
+
func (_p *<%= @model_name %>Page) GetPage(direction string) (ps []<%= @model_name %>, err error) {
|
136
|
+
switch direction {
|
137
|
+
case "previous":
|
138
|
+
ps, _ = _p.Previous()
|
139
|
+
case "next":
|
140
|
+
ps, _ = _p.Next()
|
141
|
+
case "current":
|
142
|
+
ps, _ = _p.Current()
|
143
|
+
default:
|
144
|
+
return nil, errors.New("Error: wrong dircetion! None of previous, current or next!")
|
145
|
+
}
|
146
|
+
return
|
147
|
+
}
|
148
|
+
|
149
|
+
// buildOrder is for <%= @model_name %>Page object to build a SQL ORDER BY clause.
|
150
|
+
func (_p *<%= @model_name %>Page) buildOrder() {
|
151
|
+
tempList := []string{}
|
152
|
+
for k, v := range _p.Order {
|
153
|
+
tempList = append(tempList, fmt.Sprintf("%v %v", k, v))
|
154
|
+
}
|
155
|
+
_p.orderStr = " ORDER BY " + strings.Join(tempList, ", ")
|
156
|
+
}
|
157
|
+
|
158
|
+
// buildIdRestrict is for <%= @model_name %>Page object to build a SQL clause for ID restriction,
|
159
|
+
// implementing a simple keyset style pagination.
|
160
|
+
func (_p *<%= @model_name %>Page) buildIdRestrict(direction string) (idStr string, idParams []interface{}) {
|
161
|
+
bindVarNumber := len(_p.WhereParams) + 1
|
162
|
+
switch direction {
|
163
|
+
case "previous":
|
164
|
+
if strings.ToLower(_p.Order["id"]) == "desc" {
|
165
|
+
idStr += fmt.Sprintf("id > $%v ", bindVarNumber)
|
166
|
+
idParams = append(idParams, _p.FirstId)
|
167
|
+
} else {
|
168
|
+
idStr += fmt.Sprintf("id < $%v ", bindVarNumber)
|
169
|
+
idParams = append(idParams, _p.FirstId)
|
170
|
+
}
|
171
|
+
case "current":
|
172
|
+
// trick to make Where function work
|
173
|
+
if _p.PageNum == 0 && _p.FirstId == 0 && _p.LastId == 0 {
|
174
|
+
idStr += fmt.Sprintf("id > $%v ", bindVarNumber)
|
175
|
+
idParams = append(idParams, 0)
|
176
|
+
} else {
|
177
|
+
if strings.ToLower(_p.Order["id"]) == "desc" {
|
178
|
+
idStr += fmt.Sprintf("id <= $%v AND id >= $%v ", bindVarNumber, bindVarNumber + 1)
|
179
|
+
idParams = append(idParams, _p.FirstId, _p.LastId)
|
180
|
+
} else {
|
181
|
+
idStr += fmt.Sprintf("id >= $%v AND id <= $%v ", bindVarNumber, bindVarNumber + 1)
|
182
|
+
idParams = append(idParams, _p.FirstId, _p.LastId)
|
183
|
+
}
|
184
|
+
}
|
185
|
+
case "next":
|
186
|
+
if strings.ToLower(_p.Order["id"]) == "desc" {
|
187
|
+
idStr += fmt.Sprintf("id < $%v ", bindVarNumber)
|
188
|
+
idParams = append(idParams, _p.LastId)
|
189
|
+
} else {
|
190
|
+
idStr += fmt.Sprintf("id > $%v ", bindVarNumber)
|
191
|
+
idParams = append(idParams, _p.LastId)
|
192
|
+
}
|
193
|
+
}
|
194
|
+
if _p.WhereString != "" {
|
195
|
+
idStr = " AND " + idStr
|
196
|
+
}
|
197
|
+
return
|
198
|
+
}
|
199
|
+
|
200
|
+
// buildPageCount calculate the TotalItems/TotalPages for the <%= @model_name %>Page object.
|
201
|
+
func (_p *<%= @model_name %>Page) buildPageCount() error {
|
202
|
+
count, err := <%= @model_name %>CountWhere(_p.WhereString, _p.WhereParams...)
|
203
|
+
if err != nil {
|
204
|
+
return err
|
205
|
+
}
|
206
|
+
_p.TotalItems = count
|
207
|
+
if _p.PerPage == 0 {
|
208
|
+
_p.PerPage = 10
|
209
|
+
}
|
210
|
+
_p.TotalPages = int(math.Ceil(float64(_p.TotalItems) / float64(_p.PerPage)))
|
211
|
+
return nil
|
212
|
+
}
|
213
|
+
|
214
|
+
|
215
|
+
// Find<%= @model_name %> find a single <%= var_umn %> by an ID.
|
216
|
+
func Find<%= @model_name %>(id int64) (*<%= @model_name %>, error) {
|
217
|
+
if id == 0 {
|
218
|
+
return nil, errors.New("Invalid ID: it can't be zero")
|
219
|
+
}
|
220
|
+
_<%= var_umn %> := <%= @model_name %>{}
|
221
|
+
err := DB.Get(&_<%= var_umn %>, DB.Rebind(`SELECT <%= fields %> FROM <%= table_name %> WHERE <%= table_name %>.id = $1 LIMIT 1`), id)
|
222
|
+
if err != nil {
|
223
|
+
log.Printf("Error: %v\n", err)
|
224
|
+
return nil, err
|
225
|
+
}
|
226
|
+
return &_<%= var_umn %>, nil
|
227
|
+
}
|
228
|
+
|
229
|
+
// First<%= @model_name %> find the first one <%= var_umn %> by ID ASC order.
|
230
|
+
func First<%= @model_name %>() (*<%= @model_name %>, error) {
|
231
|
+
_<%= var_umn %> := <%= @model_name %>{}
|
232
|
+
err := DB.Get(&_<%= var_umn %>, DB.Rebind(`SELECT <%= fields %> FROM <%= table_name %> ORDER BY <%= table_name %>.id ASC LIMIT 1`))
|
233
|
+
if err != nil {
|
234
|
+
log.Printf("Error: %v\n", err)
|
235
|
+
return nil, err
|
236
|
+
}
|
237
|
+
return &_<%= var_umn %>, nil
|
238
|
+
}
|
239
|
+
|
240
|
+
// First<%= @model_name.pluralize %> find the first N <%= var_umn.pluralize %> by ID ASC order.
|
241
|
+
func First<%= @model_name.pluralize %>(n uint32) ([]<%= @model_name %>, error) {
|
242
|
+
_<%= var_pmn %> := []<%= @model_name %>{}
|
243
|
+
sql := fmt.Sprintf("SELECT <%= fields %> FROM <%= table_name %> ORDER BY <%= table_name %>.id ASC LIMIT %v", n)
|
244
|
+
err := DB.Select(&_<%= var_pmn %>, DB.Rebind(sql))
|
245
|
+
if err != nil {
|
246
|
+
log.Printf("Error: %v\n", err)
|
247
|
+
return nil, err
|
248
|
+
}
|
249
|
+
return _<%= var_pmn %>, nil
|
250
|
+
}
|
251
|
+
|
252
|
+
// Last<%= @model_name %> find the last one <%= var_umn %> by ID DESC order.
|
253
|
+
func Last<%= @model_name %>() (*<%= @model_name %>, error) {
|
254
|
+
_<%= var_umn %> := <%= @model_name %>{}
|
255
|
+
err := DB.Get(&_<%= var_umn %>, DB.Rebind(`SELECT <%= fields %> FROM <%= table_name %> ORDER BY <%= table_name %>.id DESC LIMIT 1`))
|
256
|
+
if err != nil {
|
257
|
+
log.Printf("Error: %v\n", err)
|
258
|
+
return nil, err
|
259
|
+
}
|
260
|
+
return &_<%= var_umn %>, nil
|
261
|
+
}
|
262
|
+
|
263
|
+
// Last<%= @model_name.pluralize %> find the last N <%= var_umn.pluralize %> by ID DESC order.
|
264
|
+
func Last<%= @model_name.pluralize %>(n uint32) ([]<%= @model_name %>, error) {
|
265
|
+
_<%= var_pmn %> := []<%= @model_name %>{}
|
266
|
+
sql := fmt.Sprintf("SELECT <%= fields %> FROM <%= table_name %> ORDER BY <%= table_name %>.id DESC LIMIT %v", n)
|
267
|
+
err := DB.Select(&_<%= var_pmn %>, DB.Rebind(sql))
|
268
|
+
if err != nil {
|
269
|
+
log.Printf("Error: %v\n", err)
|
270
|
+
return nil, err
|
271
|
+
}
|
272
|
+
return _<%= var_pmn %>, nil
|
273
|
+
}
|
274
|
+
|
275
|
+
// Find<%= @model_name.pluralize %> find one or more <%= var_umn.pluralize %> by the given ID(s).
|
276
|
+
func Find<%= @model_name.pluralize %>(ids ...int64) ([]<%= @model_name %>, error) {
|
277
|
+
if len(ids) == 0 {
|
278
|
+
msg := "At least one or more ids needed"
|
279
|
+
log.Println(msg)
|
280
|
+
return nil, errors.New(msg)
|
281
|
+
}
|
282
|
+
_<%= var_pmn %> := []<%= @model_name %>{}
|
283
|
+
idsHolder := buildIdsHolder(len(ids))
|
284
|
+
sql := DB.Rebind(fmt.Sprintf(`SELECT <%= fields %> FROM <%= table_name %> WHERE <%= table_name %>.id IN (%s)`, idsHolder))
|
285
|
+
idsT := []interface{}{}
|
286
|
+
for _,id := range ids {
|
287
|
+
idsT = append(idsT, interface{}(id))
|
288
|
+
}
|
289
|
+
err := DB.Select(&_<%= var_pmn %>, sql, idsT...)
|
290
|
+
if err != nil {
|
291
|
+
log.Printf("Error: %v\n", err)
|
292
|
+
return nil, err
|
293
|
+
}
|
294
|
+
return _<%= var_pmn %>, nil
|
295
|
+
}
|
296
|
+
|
297
|
+
// Find<%= @model_name %>By find a single <%= var_umn %> by a field name and a value.
|
298
|
+
func Find<%= @model_name %>By(field string, val interface{}) (*<%= @model_name %>, error) {
|
299
|
+
_<%= var_umn %> := <%= @model_name %>{}
|
300
|
+
sqlFmt := `SELECT <%= fields %> FROM <%= table_name %> WHERE %s = ? LIMIT 1`
|
301
|
+
sqlStr := fmt.Sprintf(sqlFmt, field)
|
302
|
+
err := DB.Get(&_<%= var_umn %>, DB.Rebind(sqlStr), val)
|
303
|
+
if err != nil {
|
304
|
+
log.Printf("Error: %v\n", err)
|
305
|
+
return nil, err
|
306
|
+
}
|
307
|
+
return &_<%= var_umn %>, nil
|
308
|
+
}
|
309
|
+
|
310
|
+
// Find<%= @model_name.pluralize %>By find all <%= var_pmn %> by a field name and a value.
|
311
|
+
func Find<%= @model_name.pluralize %>By(field string, val interface{}) (_<%= var_pmn %> []<%= @model_name %>, err error) {
|
312
|
+
sqlFmt := `SELECT <%= fields %> FROM <%= table_name %> WHERE %s = ?`
|
313
|
+
sqlStr := fmt.Sprintf(sqlFmt, field)
|
314
|
+
err = DB.Select(&_<%= var_pmn %>, DB.Rebind(sqlStr), val)
|
315
|
+
if err != nil {
|
316
|
+
log.Printf("Error: %v\n", err)
|
317
|
+
return nil, err
|
318
|
+
}
|
319
|
+
return _<%= var_pmn %>, nil
|
320
|
+
}
|
321
|
+
|
322
|
+
// All<%= @model_name.pluralize %> get all the <%= @model_name %> records.
|
323
|
+
func All<%= @model_name.pluralize %>() (<%= var_pmn %> []<%= @model_name %>, err error) {
|
324
|
+
err = DB.Select(&<%= var_pmn %>, "SELECT <%= fields %> FROM <%= table_name %>")
|
325
|
+
if err != nil {
|
326
|
+
log.Println(err)
|
327
|
+
return nil, err
|
328
|
+
}
|
329
|
+
return <%= var_pmn %>, nil
|
330
|
+
}
|
331
|
+
|
332
|
+
// <%= @model_name %>Count get the count of all the <%= @model_name %> records.
|
333
|
+
func <%= @model_name %>Count() (c int64, err error) {
|
334
|
+
err = DB.Get(&c, "SELECT count(*) FROM <%= table_name %>")
|
335
|
+
if err != nil {
|
336
|
+
log.Println(err)
|
337
|
+
return 0, err
|
338
|
+
}
|
339
|
+
return c, nil
|
340
|
+
}
|
341
|
+
|
342
|
+
// <%= @model_name %>CountWhere get the count of all the <%= @model_name %> records with a where clause.
|
343
|
+
func <%= @model_name %>CountWhere(where string, args ...interface{}) (c int64, err error) {
|
344
|
+
sql := "SELECT count(*) FROM <%= table_name %>"
|
345
|
+
if len(where) > 0 {
|
346
|
+
sql = sql + " WHERE " + where
|
347
|
+
}
|
348
|
+
stmt, err := DB.Preparex(DB.Rebind(sql))
|
349
|
+
if err != nil {
|
350
|
+
log.Println(err)
|
351
|
+
return 0, err
|
352
|
+
}
|
353
|
+
err = stmt.Get(&c, args...)
|
354
|
+
if err != nil {
|
355
|
+
log.Println(err)
|
356
|
+
return 0, err
|
357
|
+
}
|
358
|
+
return c, nil
|
359
|
+
}
|
360
|
+
|
361
|
+
// <%= @model_name %>IncludesWhere get the <%= @model_name %> associated models records, currently it's not same as the corresponding "includes" function but "preload" instead in Ruby on Rails. It means that the "sql" should be restricted on <%= @model_name %> model.
|
362
|
+
func <%= @model_name %>IncludesWhere(assocs []string, sql string, args ...interface{}) (_<%= var_pmn %> []<%= @model_name %>, err error) {
|
363
|
+
_<%= var_pmn %>, err = Find<%= @model_name.pluralize %>Where(sql, args...)
|
364
|
+
if err != nil {
|
365
|
+
log.Println(err)
|
366
|
+
return nil, err
|
367
|
+
}
|
368
|
+
if len(assocs) == 0 {
|
369
|
+
log.Println("No associated fields ard specified")
|
370
|
+
return _<%= var_pmn %>, err
|
371
|
+
}
|
372
|
+
if len(_<%= var_pmn %>) <= 0 {
|
373
|
+
return nil, errors.New("No results available")
|
374
|
+
}
|
375
|
+
ids := make([]interface{}, len(_<%= var_pmn %>))
|
376
|
+
for _, v := range _<%= var_pmn %> {
|
377
|
+
ids = append(ids, interface{}(v.Id))
|
378
|
+
}
|
379
|
+
<%- if has_assoc -%>
|
380
|
+
idsHolder := buildIdsHolder(len(ids))
|
381
|
+
for _, assoc := range assocs {
|
382
|
+
switch assoc {
|
383
|
+
<%- unless @struct_info[:assoc_info][:has_many].empty? -%>
|
384
|
+
<%- has_many = @struct_info[:assoc_info][:has_many] -%>
|
385
|
+
<%- has_many.each do |k, v| -%>
|
386
|
+
case "<%= k.underscore.pluralize %>":
|
387
|
+
<%- if v[:through] || v[:as] -%>
|
388
|
+
// FIXME: optimize the query
|
389
|
+
for i, vvv := range _<%= var_pmn %> {
|
390
|
+
_<%= k.underscore.pluralize %>, err := <%= @model_name %>Get<%= k.pluralize %>(vvv.Id)
|
391
|
+
if err != nil {
|
392
|
+
continue
|
393
|
+
}
|
394
|
+
vvv.<%= k %> = _<%= k.underscore.pluralize %>
|
395
|
+
_<%= var_pmn %>[i] = vvv
|
396
|
+
}
|
397
|
+
<%- else -%>
|
398
|
+
<%- if v[:foreign_key] -%>
|
399
|
+
where := fmt.Sprintf("<%= v[:foreign_key] %> IN (%s)", idsHolder)
|
400
|
+
<%- else -%>
|
401
|
+
where := fmt.Sprintf("<%= var_umn %>_id IN (%s)", idsHolder)
|
402
|
+
<%- end -%>
|
403
|
+
_<%= v[:class_name].underscore.pluralize %>, err := Find<%= v[:class_name].pluralize %>Where(where, ids...)
|
404
|
+
if err != nil {
|
405
|
+
log.Printf("Error when query associated objects: %v\n", assoc)
|
406
|
+
continue
|
407
|
+
}
|
408
|
+
for _, vv := range _<%= v[:class_name].underscore.pluralize %> {
|
409
|
+
for i, vvv := range _<%= var_pmn %> {
|
410
|
+
<%- if v[:foreign_key] -%>
|
411
|
+
if vv.<%= v[:foreign_key].to_s.camelize %> == vvv.Id {
|
412
|
+
vvv.<%= k %> = append(vvv.<%= k %>, vv)
|
413
|
+
}
|
414
|
+
<%- else -%>
|
415
|
+
if vv.<%= @model_name.camelize %>Id == vvv.Id {
|
416
|
+
vvv.<%= k %> = append(vvv.<%= k %>, vv)
|
417
|
+
}
|
418
|
+
<%- end -%>
|
419
|
+
_<%= var_pmn %>[i].<%= k %> = vvv.<%= k %>
|
420
|
+
}
|
421
|
+
}
|
422
|
+
<%- end -%>
|
423
|
+
<%- end -%>
|
424
|
+
<%- end -%>
|
425
|
+
<%- unless @struct_info[:assoc_info][:has_one].empty? -%>
|
426
|
+
<%- has_one = @struct_info[:assoc_info][:has_one] -%>
|
427
|
+
<%- has_one.each do |k, v| -%>
|
428
|
+
case "<%= k.underscore %>":
|
429
|
+
<%- if v[:foreign_key] -%>
|
430
|
+
where := fmt.Sprintf("<%= v[:foreign_key] %> IN (%s)", idsHolder)
|
431
|
+
<%- else -%>
|
432
|
+
where := fmt.Sprintf("<%= var_umn %>_id IN (%s)", idsHolder)
|
433
|
+
<%- end -%>
|
434
|
+
_<%= v[:class_name].underscore.pluralize %>, err := Find<%= v[:class_name].pluralize %>Where(where, ids...)
|
435
|
+
if err != nil {
|
436
|
+
log.Printf("Error when query associated objects: %v\n", assoc)
|
437
|
+
continue
|
438
|
+
}
|
439
|
+
for _, vv := range _<%= v[:class_name].underscore.pluralize %> {
|
440
|
+
for i, vvv := range _<%= var_pmn %> {
|
441
|
+
<%- if v[:foreign_key] -%>
|
442
|
+
if vv.<%= v[:foreign_key].to_s.camelize %> == vvv.Id {
|
443
|
+
vvv.<%= k %> = vv
|
444
|
+
}
|
445
|
+
<%- else -%>
|
446
|
+
if vv.<%= @model_name.camelize %>Id == vvv.Id {
|
447
|
+
vvv.<%= k %> = vv
|
448
|
+
}
|
449
|
+
<%- end -%>
|
450
|
+
_<%= var_pmn %>[i].<%= k %> = vvv.<%= k %>
|
451
|
+
}
|
452
|
+
}
|
453
|
+
<%- end -%>
|
454
|
+
<%- end -%>
|
455
|
+
}
|
456
|
+
}
|
457
|
+
<%- end -%>
|
458
|
+
return _<%= var_pmn %>, nil
|
459
|
+
}
|
460
|
+
|
461
|
+
// <%= @model_name %>Ids get all the IDs of <%= @model_name %> records.
|
462
|
+
func <%= @model_name %>Ids() (ids []int64, err error) {
|
463
|
+
err = DB.Select(&ids, "SELECT id FROM <%= table_name %>")
|
464
|
+
if err != nil {
|
465
|
+
log.Println(err)
|
466
|
+
return nil, err
|
467
|
+
}
|
468
|
+
return ids, nil
|
469
|
+
}
|
470
|
+
|
471
|
+
// <%= @model_name %>IdsWhere get all the IDs of <%= @model_name %> records by where restriction.
|
472
|
+
func <%= @model_name %>IdsWhere(where string, args ...interface{}) ([]int64, error) {
|
473
|
+
ids, err := <%= @model_name %>IntCol("id", where, args...)
|
474
|
+
return ids, err
|
475
|
+
}
|
476
|
+
|
477
|
+
// <%= @model_name %>IntCol get some int64 typed column of <%= @model_name %> by where restriction.
|
478
|
+
func <%= @model_name %>IntCol(col, where string, args ...interface{}) (intColRecs []int64, err error) {
|
479
|
+
sql := "SELECT " + col + " FROM <%= table_name %>"
|
480
|
+
if len(where) > 0 {
|
481
|
+
sql = sql + " WHERE " + where
|
482
|
+
}
|
483
|
+
stmt, err := DB.Preparex(DB.Rebind(sql))
|
484
|
+
if err != nil {
|
485
|
+
log.Println(err)
|
486
|
+
return nil, err
|
487
|
+
}
|
488
|
+
err = stmt.Select(&intColRecs, args...)
|
489
|
+
if err != nil {
|
490
|
+
log.Println(err)
|
491
|
+
return nil, err
|
492
|
+
}
|
493
|
+
return intColRecs, nil
|
494
|
+
}
|
495
|
+
|
496
|
+
// <%= @model_name %>StrCol get some string typed column of <%= @model_name %> by where restriction.
|
497
|
+
func <%= @model_name %>StrCol(col, where string, args ...interface{}) (strColRecs []string, err error) {
|
498
|
+
sql := "SELECT " + col + " FROM <%= table_name %>"
|
499
|
+
if len(where) > 0 {
|
500
|
+
sql = sql + " WHERE " + where
|
501
|
+
}
|
502
|
+
stmt, err := DB.Preparex(DB.Rebind(sql))
|
503
|
+
if err != nil {
|
504
|
+
log.Println(err)
|
505
|
+
return nil, err
|
506
|
+
}
|
507
|
+
err = stmt.Select(&strColRecs, args...)
|
508
|
+
if err != nil {
|
509
|
+
log.Println(err)
|
510
|
+
return nil, err
|
511
|
+
}
|
512
|
+
return strColRecs, nil
|
513
|
+
}
|
514
|
+
|
515
|
+
// Find<%= @model_name.pluralize %>Where query use a partial SQL clause that usually following after WHERE
|
516
|
+
// with placeholders, eg: FindUsersWhere("first_name = ? AND age > ?", "John", 18)
|
517
|
+
// will return those records in the table "users" whose first_name is "John" and age elder than 18.
|
518
|
+
func Find<%= @model_name.pluralize %>Where(where string, args ...interface{}) (<%= var_pmn %> []<%= @model_name %>, err error) {
|
519
|
+
sql := "SELECT <%= fields %> FROM <%= table_name %>"
|
520
|
+
if len(where) > 0 {
|
521
|
+
sql = sql + " WHERE " + where
|
522
|
+
}
|
523
|
+
stmt, err := DB.Preparex(DB.Rebind(sql))
|
524
|
+
if err != nil {
|
525
|
+
log.Println(err)
|
526
|
+
return nil, err
|
527
|
+
}
|
528
|
+
err = stmt.Select(&<%= var_pmn %>, args...)
|
529
|
+
if err != nil {
|
530
|
+
log.Println(err)
|
531
|
+
return nil, err
|
532
|
+
}
|
533
|
+
return <%= var_pmn %>, nil
|
534
|
+
}
|
535
|
+
|
536
|
+
// Find<%= @model_name %>BySql query use a complete SQL clause
|
537
|
+
// with placeholders, eg: FindUserBySql("SELECT * FROM users WHERE first_name = ? AND age > ? ORDER BY DESC LIMIT 1", "John", 18)
|
538
|
+
// will return only One record in the table "users" whose first_name is "John" and age elder than 18.
|
539
|
+
func Find<%= @model_name %>BySql(sql string, args ...interface{}) (*<%= @model_name %>, error) {
|
540
|
+
stmt, err := DB.Preparex(DB.Rebind(sql))
|
541
|
+
if err != nil {
|
542
|
+
log.Println(err)
|
543
|
+
return nil, err
|
544
|
+
}
|
545
|
+
_<%= var_umn %> := &<%= @model_name %>{}
|
546
|
+
err = stmt.Get(_<%= var_umn %>, args...)
|
547
|
+
if err != nil {
|
548
|
+
log.Println(err)
|
549
|
+
return nil, err
|
550
|
+
}
|
551
|
+
return _<%= var_umn %>, nil
|
552
|
+
}
|
553
|
+
|
554
|
+
// Find<%= @model_name.pluralize %>BySql query use a complete SQL clause
|
555
|
+
// with placeholders, eg: FindUsersBySql("SELECT * FROM users WHERE first_name = ? AND age > ?", "John", 18)
|
556
|
+
// will return those records in the table "users" whose first_name is "John" and age elder than 18.
|
557
|
+
func Find<%= @model_name.pluralize %>BySql(sql string, args ...interface{}) (<%= var_pmn %> []<%= @model_name %>, err error) {
|
558
|
+
stmt, err := DB.Preparex(DB.Rebind(sql))
|
559
|
+
if err != nil {
|
560
|
+
log.Println(err)
|
561
|
+
return nil, err
|
562
|
+
}
|
563
|
+
err = stmt.Select(&<%= var_pmn %>, args...)
|
564
|
+
if err != nil {
|
565
|
+
log.Println(err)
|
566
|
+
return nil, err
|
567
|
+
}
|
568
|
+
return <%= var_pmn %>, nil
|
569
|
+
}
|
570
|
+
|
571
|
+
// Create<%= @model_name %> use a named params to create a single <%= @model_name %> record.
|
572
|
+
// A named params is key-value map like map[string]interface{}{"first_name": "John", "age": 23} .
|
573
|
+
func Create<%= @model_name %>(am map[string]interface{}) (int64, error) {
|
574
|
+
if len(am) == 0 {
|
575
|
+
return 0, fmt.Errorf("Zero key in the attributes map!")
|
576
|
+
}
|
577
|
+
<%- unless @struct_info[:timestamp_cols].empty? -%>
|
578
|
+
t := time.Now()
|
579
|
+
for _, v := range []string{<%= @struct_info[:timestamp_cols].map(&:inspect).join(", ") %>} {
|
580
|
+
if am[v] == nil {
|
581
|
+
am[v] = t
|
582
|
+
}
|
583
|
+
}
|
584
|
+
<%- end -%>
|
585
|
+
keys := allKeys(am)
|
586
|
+
sqlFmt := `INSERT INTO <%= table_name %> (%s) VALUES (%s) RETURNING id`
|
587
|
+
sql := fmt.Sprintf(sqlFmt, strings.Join(keys, ","), ":"+strings.Join(keys, ",:"))
|
588
|
+
stmt, err := DB.PrepareNamed(sql)
|
589
|
+
if err != nil {
|
590
|
+
log.Println(err)
|
591
|
+
return 0, err
|
592
|
+
}
|
593
|
+
var lastId int64
|
594
|
+
err = stmt.Get(&lastId, am)
|
595
|
+
if err != nil {
|
596
|
+
log.Println(err)
|
597
|
+
return 0, err
|
598
|
+
}
|
599
|
+
return lastId, nil
|
600
|
+
}
|
601
|
+
|
602
|
+
// Create is a method for <%= @model_name %> to create a record.
|
603
|
+
func (_<%= var_umn %> *<%= @model_name %>) Create() (int64, error) {
|
604
|
+
ok, err := govalidator.ValidateStruct(_<%= var_umn %>)
|
605
|
+
if !ok {
|
606
|
+
errMsg := "Validate <%= @model_name %> struct error: Unknown error"
|
607
|
+
if err != nil {
|
608
|
+
errMsg = "Validate <%= @model_name %> struct error: " + err.Error()
|
609
|
+
}
|
610
|
+
log.Println(errMsg)
|
611
|
+
return 0, errors.New(errMsg)
|
612
|
+
}
|
613
|
+
<%- unless @struct_info[:timestamp_cols].empty? -%>
|
614
|
+
t := time.Now()
|
615
|
+
<%- @struct_info[:timestamp_cols].each do |c| -%>
|
616
|
+
_<%= var_umn %>.<%= c.camelize %> = t
|
617
|
+
<%- end -%>
|
618
|
+
<%- end -%>
|
619
|
+
sql := `INSERT INTO <%= table_name %> (<%= col_names.join(",") %>) VALUES (:<%= col_names.join(",:") %>) RETURNING id`
|
620
|
+
stmt, err := DB.PrepareNamed(sql)
|
621
|
+
if err != nil {
|
622
|
+
log.Println(err)
|
623
|
+
return 0, err
|
624
|
+
}
|
625
|
+
var lastId int64
|
626
|
+
err = stmt.Get(&lastId, _<%= var_umn %>)
|
627
|
+
if err != nil {
|
628
|
+
log.Println(err)
|
629
|
+
return 0, err
|
630
|
+
}
|
631
|
+
return lastId, nil
|
632
|
+
}
|
633
|
+
|
634
|
+
<%- unless @struct_info[:assoc_info][:has_many].empty? -%>
|
635
|
+
<%- has_many = @struct_info[:assoc_info][:has_many] -%>
|
636
|
+
<%- has_many.each do |k, v| -%>
|
637
|
+
// <%= k.pluralize %>Create is used for <%= @model_name %> to create the associated objects <%= k.pluralize %>
|
638
|
+
func (_<%= var_umn %> *<%= @model_name %>) <%= k.pluralize %>Create(am map[string]interface{}) error {
|
639
|
+
<%- if v[:through] -%>
|
640
|
+
// FIXME: use transaction to create these associated objects
|
641
|
+
<%= v[:class_name].underscore %>Id, err := Create<%= v[:class_name] %>(am)
|
642
|
+
if err != nil {
|
643
|
+
return err
|
644
|
+
}
|
645
|
+
_, err = Create<%= v[:through].to_s.singularize.camelize %>(map[string]interface{}{"<%= var_umn %>_id": _<%= var_umn %>.Id, "<%= v[:class_name].underscore %>_id": <%= v[:class_name].underscore %>Id})
|
646
|
+
<%- elsif v[:as] -%>
|
647
|
+
am["<%= v[:as] %>_id"] = _<%= var_umn %>.Id
|
648
|
+
am["<%= v[:as] %>_type"] = "<%= @model_name %>"
|
649
|
+
_, err := Create<%= v[:class_name] %>(am)
|
650
|
+
<%- else -%>
|
651
|
+
<%- if v[:foreign_key] -%>
|
652
|
+
am["<%= v[:foreign_key] %>"] = _<%= var_umn %>.Id
|
653
|
+
<%- else -%>
|
654
|
+
am["<%= var_umn %>_id"] = _<%= var_umn %>.Id
|
655
|
+
<%- end -%>
|
656
|
+
_, err := Create<%= v[:class_name] %>(am)
|
657
|
+
<%- end -%>
|
658
|
+
return err
|
659
|
+
}
|
660
|
+
|
661
|
+
// Get<%= k.pluralize %> is used for <%= @model_name %> to get associated objects <%= k.pluralize %>
|
662
|
+
// Say you have a <%= @model_name %> object named <%= var_umn %>, when you call <%= var_umn %>.Get<%= k.pluralize %>(),
|
663
|
+
// the object will get the associated <%= k.pluralize %> attributes evaluated in the struct.
|
664
|
+
func (_<%= var_umn %> *<%= @model_name %>) Get<%= k.pluralize %>() error {
|
665
|
+
_<%= k.underscore.pluralize %>, err := <%= @model_name %>Get<%= k.pluralize %>(_<%= var_umn %>.Id)
|
666
|
+
if err == nil {
|
667
|
+
_<%= var_umn %>.<%= k %> = _<%= k.underscore.pluralize %>
|
668
|
+
}
|
669
|
+
return err
|
670
|
+
}
|
671
|
+
|
672
|
+
// <%= @model_name %>Get<%= k.pluralize %> a helper fuction used to get associated objects for <%= @model_name %>IncludesWhere().
|
673
|
+
func <%= @model_name %>Get<%= k.pluralize %>(id int64) ([]<%= v[:class_name] %>, error) {
|
674
|
+
<%- if v[:through] -%>
|
675
|
+
// FIXME: use transaction to create these associated objects
|
676
|
+
<%- target_table = v[:class_name].underscore.pluralize -%>
|
677
|
+
<%- through_table = v[:through].to_s.pluralize -%>
|
678
|
+
sql := `SELECT <%= @all_structs_info[v[:class_name]][:select_fields] %>
|
679
|
+
FROM <%= target_table %>
|
680
|
+
INNER JOIN <%= through_table %>
|
681
|
+
ON <%= target_table %>.id = <%= through_table %>.<%= v[:class_name].underscore %>_id
|
682
|
+
WHERE <%= through_table %>.<%= var_umn %>_id = ?`
|
683
|
+
_<%= k.underscore.pluralize %>, err := Find<%= v[:class_name].pluralize %>BySql(sql, id)
|
684
|
+
<%- elsif v[:as] -%>
|
685
|
+
where := `<%= v[:as] %>_type = "<%= @model_name %>" AND <%= v[:as] %>_id = ?`
|
686
|
+
_<%= k.underscore.pluralize %>, err := Find<%= v[:class_name].pluralize %>Where(where, id)
|
687
|
+
<%- else -%>
|
688
|
+
<%- if v[:foreign_key] -%>
|
689
|
+
_<%= k.underscore.pluralize %>, err := Find<%= v[:class_name].pluralize %>By("<%= v[:foreign_key] %>", id)
|
690
|
+
<%- else -%>
|
691
|
+
_<%= k.underscore.pluralize %>, err := Find<%= v[:class_name].pluralize %>By("<%= var_umn %>_id", id)
|
692
|
+
<%- end -%>
|
693
|
+
<%- end -%>
|
694
|
+
return _<%= k.underscore.pluralize %>, err
|
695
|
+
}
|
696
|
+
|
697
|
+
<%- end -%>
|
698
|
+
<%- end -%>
|
699
|
+
|
700
|
+
<%- unless @struct_info[:assoc_info][:has_one].empty? -%>
|
701
|
+
<%- has_one = @struct_info[:assoc_info][:has_one] -%>
|
702
|
+
<%- has_one.each do |k, v| -%>
|
703
|
+
// Create<%= k %> is a method for the <%= @model_name %> model object to create an associated <%= k %> record.
|
704
|
+
func (_<%= var_umn %> *<%= @model_name %>) Create<%= k %>(am map[string]interface{}) error {
|
705
|
+
<%- if v[:foreign_key] -%>
|
706
|
+
am["<%= v[:foreign_key] %>"] = _<%= var_umn %>.Id
|
707
|
+
<%- else -%>
|
708
|
+
am["<%= var_umn %>_id"] = _<%= var_umn %>.Id
|
709
|
+
<%- end -%>
|
710
|
+
_, err := Create<%= v[:class_name] %>(am)
|
711
|
+
return err
|
712
|
+
}
|
713
|
+
<%- end -%>
|
714
|
+
<%- end -%>
|
715
|
+
|
716
|
+
<%- unless @struct_info[:assoc_info][:belongs_to].empty? -%>
|
717
|
+
<%- belongs_to = @struct_info[:assoc_info][:belongs_to] -%>
|
718
|
+
<%- belongs_to.each do |k, v| -%>
|
719
|
+
<%-# don't create virtual table for polymorphic model -%>
|
720
|
+
<%- next if v[:polymorphic] -%>
|
721
|
+
// Create<%= k %> is a method for a <%= @model_name %> object to create an associated <%= k %> record.
|
722
|
+
func (_<%= var_umn %> *<%= @model_name %>) Create<%= k %>(am map[string]interface{}) error {
|
723
|
+
<%- if v[:foreign_key] -%>
|
724
|
+
am["<%= v[:foreign_key] %>"] = _<%= var_umn %>.Id
|
725
|
+
<%- else -%>
|
726
|
+
am["<%= var_umn %>_id"] = _<%= var_umn %>.Id
|
727
|
+
<%- end -%>
|
728
|
+
_, err := Create<%= v[:class_name] %>(am)
|
729
|
+
return err
|
730
|
+
}
|
731
|
+
<%- end -%>
|
732
|
+
<%- end -%>
|
733
|
+
|
734
|
+
// Destroy is method used for a <%= @model_name %> object to be destroyed.
|
735
|
+
func (_<%= var_umn %> *<%= @model_name %>) Destroy() error {
|
736
|
+
if _<%= var_umn %>.Id == 0 {
|
737
|
+
return errors.New("Invalid Id field: it can't be a zero value")
|
738
|
+
}
|
739
|
+
err := Destroy<%= @model_name %>(_<%= var_umn %>.Id)
|
740
|
+
return err
|
741
|
+
}
|
742
|
+
|
743
|
+
// Destroy<%= @model_name %> will destroy a <%= @model_name %> record specified by the id parameter.
|
744
|
+
func Destroy<%= @model_name %>(id int64) error {
|
745
|
+
<%- if @struct_info[:has_assoc_dependent] -%>
|
746
|
+
// Destroy association objects at first
|
747
|
+
// Not care if exec properly temporarily
|
748
|
+
destroy<%= @model_name %>Associations(id)
|
749
|
+
<%- end -%>
|
750
|
+
stmt, err := DB.Preparex(DB.Rebind(`DELETE FROM <%= table_name %> WHERE id = ?`))
|
751
|
+
_, err = stmt.Exec(id)
|
752
|
+
if err != nil {
|
753
|
+
return err
|
754
|
+
}
|
755
|
+
return nil
|
756
|
+
}
|
757
|
+
|
758
|
+
// Destroy<%= @model_name.pluralize %> will destroy <%= @model_name %> records those specified by the ids parameters.
|
759
|
+
func Destroy<%= @model_name.pluralize %>(ids ...int64) (int64, error) {
|
760
|
+
if len(ids) == 0 {
|
761
|
+
msg := "At least one or more ids needed"
|
762
|
+
log.Println(msg)
|
763
|
+
return 0, errors.New(msg)
|
764
|
+
}
|
765
|
+
<%- if @struct_info[:has_assoc_dependent] -%>
|
766
|
+
// Destroy association objects at first
|
767
|
+
// Not care if exec properly temporarily
|
768
|
+
destroy<%= @model_name %>Associations(ids...)
|
769
|
+
<%- end -%>
|
770
|
+
idsHolder := buildIdsHolder(len(ids))
|
771
|
+
sql := fmt.Sprintf(`DELETE FROM <%= table_name %> WHERE id IN (%s)`, idsHolder)
|
772
|
+
idsT := []interface{}{}
|
773
|
+
for _,id := range ids {
|
774
|
+
idsT = append(idsT, interface{}(id))
|
775
|
+
}
|
776
|
+
stmt, err := DB.Preparex(DB.Rebind(sql))
|
777
|
+
result, err := stmt.Exec(idsT...)
|
778
|
+
if err != nil {
|
779
|
+
return 0, err
|
780
|
+
}
|
781
|
+
cnt, err := result.RowsAffected()
|
782
|
+
if err != nil {
|
783
|
+
return 0, err
|
784
|
+
}
|
785
|
+
return cnt, nil
|
786
|
+
}
|
787
|
+
|
788
|
+
// Destroy<%= @model_name.pluralize %>Where delete records by a where clause restriction.
|
789
|
+
// e.g. Destroy<%= @model_name.pluralize %>Where("name = ?", "John")
|
790
|
+
// And this func will not call the association dependent action
|
791
|
+
func Destroy<%= @model_name.pluralize %>Where(where string, args ...interface{}) (int64, error) {
|
792
|
+
sql := `DELETE FROM <%= table_name %> WHERE `
|
793
|
+
if len(where) > 0 {
|
794
|
+
sql = sql + where
|
795
|
+
} else {
|
796
|
+
return 0, errors.New("No WHERE conditions provided")
|
797
|
+
}
|
798
|
+
<%- if @struct_info[:has_assoc_dependent] -%>
|
799
|
+
ids, x_err := <%= @model_name %>IdsWhere(where, args...)
|
800
|
+
if x_err != nil {
|
801
|
+
log.Printf("Delete associated objects error: %v\n", x_err)
|
802
|
+
} else {
|
803
|
+
destroy<%= @model_name %>Associations(ids...)
|
804
|
+
}
|
805
|
+
<%- end -%>
|
806
|
+
stmt, err := DB.Preparex(DB.Rebind(sql))
|
807
|
+
result, err := stmt.Exec(args...)
|
808
|
+
if err != nil {
|
809
|
+
return 0, err
|
810
|
+
}
|
811
|
+
cnt, err := result.RowsAffected()
|
812
|
+
if err != nil {
|
813
|
+
return 0, err
|
814
|
+
}
|
815
|
+
return cnt, nil
|
816
|
+
}
|
817
|
+
|
818
|
+
<%- if @struct_info[:has_assoc_dependent] -%>
|
819
|
+
// destroy<%= @model_name %>Associations is a private function used to destroy a <%= @model_name %> record's associated objects.
|
820
|
+
// The func not return err temporarily.
|
821
|
+
func destroy<%= @model_name %>Associations(ids ...int64) {
|
822
|
+
idsHolder := ""
|
823
|
+
if len(ids) > 1 {
|
824
|
+
idsHolder := buildIdsHolder(len(ids))
|
825
|
+
}
|
826
|
+
idsT := []interface{}{}
|
827
|
+
for _, id := range ids {
|
828
|
+
idsT = append(idsT, interface{}(id))
|
829
|
+
}
|
830
|
+
var err error
|
831
|
+
// make sure no declared-and-not-used exception
|
832
|
+
_, _, _ = idsHolder, idsT, err
|
833
|
+
<%- [:has_many, :has_one].each do |ass| -%>
|
834
|
+
<%- ass_cols = @struct_info[:assoc_info][ass] -%>
|
835
|
+
<%- unless ass_cols.empty? -%>
|
836
|
+
<%- ass_cols.each_value do |opts| -%>
|
837
|
+
<%- if opts.key? :dependent -%>
|
838
|
+
<%- case opts[:dependent] -%>
|
839
|
+
<%- when :destroy, :delete_all -%>
|
840
|
+
<%- if opts[:through] -%>
|
841
|
+
where := fmt.Sprintf("id IN (SELECT id FROM <%= opts[:through].to_s %> WHERE <%= var_umn %>_id IN (%s))", idsHolder)
|
842
|
+
_, err = Destroy<%= opts[:class_name].pluralize %>Where(where, idsT...)
|
843
|
+
if err != nil {
|
844
|
+
log.Printf("Destroy associated object %s error: %v\n", "<%= opts[:class_name].pluralize %>", err)
|
845
|
+
}
|
846
|
+
where = fmt.Sprintf("<%= var_umn %>_id IN (%s)", idsHolder)
|
847
|
+
_, err = Destroy<%= opts[:through].to_s.pluralize.camelize %>Where(where, idsT...)
|
848
|
+
if err != nil {
|
849
|
+
log.Printf("Destroy associated object %s error: %v\n", "<%= opts[:through].to_s.singularize.camelize %>", err)
|
850
|
+
}
|
851
|
+
<%- elsif opts[:as] -%>
|
852
|
+
where := fmt.Sprintf(`<%= opts[:as] %>_type = "<%= @model_name %>" AND <%= opts[:as] %>_id IN (%s)`, idsHolder)
|
853
|
+
_, err = Destroy<%= opts[:class_name].pluralize %>Where(where, idsT...)
|
854
|
+
if err != nil {
|
855
|
+
log.Printf("Destroy associated object %s error: %v\n", "<%= opts[:class_name].pluralize %>", err)
|
856
|
+
}
|
857
|
+
<%- else -%>
|
858
|
+
<%- if opts.key? :foreign_key -%>
|
859
|
+
where := fmt.Sprintf("<%= opts[:foreign_key] %> IN (%s)", idsHolder)
|
860
|
+
<%- else -%>
|
861
|
+
where := fmt.Sprintf("<%= var_umn %>_id IN (%s)", idsHolder)
|
862
|
+
<%- end -%>
|
863
|
+
_, err = Destroy<%= opts[:class_name].pluralize %>Where(where, idsT...)
|
864
|
+
if err != nil {
|
865
|
+
log.Printf("Destroy associated object %s error: %v\n", "<%= opts[:class_name].pluralize %>", err)
|
866
|
+
}
|
867
|
+
<%- end -%>
|
868
|
+
<%- when :nullify -%>
|
869
|
+
// no sql.NULLType supported, just set the associated field to zero value of int64
|
870
|
+
<%- if opts[:through] -%>
|
871
|
+
sql := fmt.Sprintf("UPDATE <%= opts[:through].to_s %> SET <%= opts[:class_name].underscore %>_id = 0 WHERE <%= opts[:class_name].underscore %>_id IN (%s)", idsHolder)
|
872
|
+
_, err = Update<%= opts[:through].to_s.camelize %>BySql(sql, idsT...)
|
873
|
+
if err != nil {
|
874
|
+
log.Printf("Delete associated object %s error: %v\n", "<%= opts[:class_name].pluralize %>", err)
|
875
|
+
}
|
876
|
+
<%- else -%>
|
877
|
+
<%- if opts.key? :foreign_key -%>
|
878
|
+
sql := fmt.Sprintf("UPDATE <%= opts[:class_name].underscore.pluralize %> SET <%= opts[:foreign_key] %> = 0 WHERE <%= opts[:foreign_key] %> IN (%s)", idsHolder)
|
879
|
+
<%- else -%>
|
880
|
+
sql := fmt.Sprintf("UPDATE <%= opts[:class_name].underscore.pluralize %> SET <%= var_umn %>_id = 0 WHERE <%= var_umn %>_id IN (%s)", idsHolder)
|
881
|
+
<%- end -%>
|
882
|
+
_, err = Update<%= opts[:class_name].pluralize %>BySql(sql, idsT...)
|
883
|
+
if err != nil {
|
884
|
+
log.Printf("Delete associated object %s error: %v\n", "<%= opts[:class_name].pluralize %>", err)
|
885
|
+
}
|
886
|
+
<%- end -%>
|
887
|
+
<%- end -%>
|
888
|
+
<%- end -%>
|
889
|
+
<%- end -%>
|
890
|
+
<%- end -%>
|
891
|
+
<%- end -%>
|
892
|
+
}
|
893
|
+
<%- end -%>
|
894
|
+
|
895
|
+
// Save method is used for a <%= @model_name %> object to update an existed record mainly.
|
896
|
+
// If no id provided a new record will be created. FIXME: A UPSERT action will be implemented further.
|
897
|
+
func (_<%= var_umn %> *<%= @model_name %>) Save() error {
|
898
|
+
ok, err := govalidator.ValidateStruct(_<%= var_umn %>)
|
899
|
+
if !ok {
|
900
|
+
errMsg := "Validate <%= @model_name %> struct error: Unknown error"
|
901
|
+
if err != nil {
|
902
|
+
errMsg = "Validate <%= @model_name %> struct error: " + err.Error()
|
903
|
+
}
|
904
|
+
log.Println(errMsg)
|
905
|
+
return errors.New(errMsg)
|
906
|
+
}
|
907
|
+
if _<%= var_umn %>.Id == 0 {
|
908
|
+
_, err = _<%= var_umn %>.Create()
|
909
|
+
return err
|
910
|
+
}
|
911
|
+
<%- if @struct_info[:timestamp_cols].include? "updated_at" -%>
|
912
|
+
_<%= var_umn %>.UpdatedAt = time.Now()
|
913
|
+
<%- end -%>
|
914
|
+
sqlFmt := `UPDATE <%= table_name %> SET %s WHERE id = %v`
|
915
|
+
<%- save_col_names = col_names - ["created_at"] -%>
|
916
|
+
sqlStr := fmt.Sprintf(sqlFmt, "<%= save_col_names.zip(save_col_names).map{|c| c.join(" = :")}.join(", ") %>", _<%= var_umn %>.Id)
|
917
|
+
_, err = DB.NamedExec(sqlStr, _<%= var_umn %>)
|
918
|
+
return err
|
919
|
+
}
|
920
|
+
|
921
|
+
// Update<%= @model_name %> is used to update a record with a id and map[string]interface{} typed key-value parameters.
|
922
|
+
func Update<%= @model_name %>(id int64, am map[string]interface{}) error {
|
923
|
+
if len(am) == 0 {
|
924
|
+
return errors.New("Zero key in the attributes map!")
|
925
|
+
}
|
926
|
+
<%- if @struct_info[:timestamp_cols].include? "updated_at" -%>
|
927
|
+
am["updated_at"] = time.Now()
|
928
|
+
<%- end -%>
|
929
|
+
keys := allKeys(am)
|
930
|
+
sqlFmt := `UPDATE <%= table_name %> SET %s WHERE id = %v`
|
931
|
+
setKeysArr := []string{}
|
932
|
+
for _,v := range keys {
|
933
|
+
s := fmt.Sprintf(" %s = :%s", v, v)
|
934
|
+
setKeysArr = append(setKeysArr, s)
|
935
|
+
}
|
936
|
+
sqlStr := fmt.Sprintf(sqlFmt, strings.Join(setKeysArr, ", "), id)
|
937
|
+
_, err := DB.NamedExec(sqlStr, am)
|
938
|
+
if err != nil {
|
939
|
+
log.Println(err)
|
940
|
+
return err
|
941
|
+
}
|
942
|
+
return nil
|
943
|
+
}
|
944
|
+
|
945
|
+
// Update is a method used to update a <%= @model_name %> record with the map[string]interface{} typed key-value parameters.
|
946
|
+
func (_<%= var_umn %> *<%= @model_name %>) Update(am map[string]interface{}) error {
|
947
|
+
if _<%= var_umn %>.Id == 0 {
|
948
|
+
return errors.New("Invalid Id field: it can't be a zero value")
|
949
|
+
}
|
950
|
+
err := Update<%= @model_name %>(_<%= var_umn %>.Id, am)
|
951
|
+
return err
|
952
|
+
}
|
953
|
+
|
954
|
+
// UpdateAttributes method is supposed to be used to update <%= @model_name %> records as corresponding update_attributes in Ruby on Rails.
|
955
|
+
func (_<%= var_umn %> *<%= @model_name %>) UpdateAttributes(am map[string]interface{}) error {
|
956
|
+
if _<%= var_umn %>.Id == 0 {
|
957
|
+
return errors.New("Invalid Id field: it can't be a zero value")
|
958
|
+
}
|
959
|
+
err := Update<%= @model_name %>(_<%= var_umn %>.Id, am)
|
960
|
+
return err
|
961
|
+
}
|
962
|
+
|
963
|
+
// UpdateColumns method is supposed to be used to update <%= @model_name %> records as corresponding update_columns in Ruby on Rails.
|
964
|
+
func (_<%= var_umn %> *<%= @model_name %>) UpdateColumns(am map[string]interface{}) error {
|
965
|
+
if _<%= var_umn %>.Id == 0 {
|
966
|
+
return errors.New("Invalid Id field: it can't be a zero value")
|
967
|
+
}
|
968
|
+
err := Update<%= @model_name %>(_<%= var_umn %>.Id, am)
|
969
|
+
return err
|
970
|
+
}
|
971
|
+
|
972
|
+
// Update<%= @model_name.pluralize %>BySql is used to update <%= @model_name %> records by a SQL clause
|
973
|
+
// using the '$1...$n' binding syntax.
|
974
|
+
func Update<%= @model_name.pluralize %>BySql(sql string, args ...interface{}) (int64, error) {
|
975
|
+
if sql == "" {
|
976
|
+
return 0, errors.New("A blank SQL clause")
|
977
|
+
}
|
978
|
+
stmt, err := DB.Preparex(DB.Rebind(sql))
|
979
|
+
result, err := stmt.Exec(args...)
|
980
|
+
if err != nil {
|
981
|
+
return 0, err
|
982
|
+
}
|
983
|
+
cnt, err := result.RowsAffected()
|
984
|
+
if err != nil {
|
985
|
+
return 0, err
|
986
|
+
}
|
987
|
+
return cnt, nil
|
988
|
+
}
|