go-on-rails 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
[](https://badge.fury.io/rb/go-on-rails)
|
2
|
-
[](https://codeclimate.com/github/
|
6
|
+
[](https://travis-ci.org/railstack/go-on-rails)
|
7
|
+
[](https://codeclimate.com/github/railstack/go-on-rails/maintainability)
|
8
|
+
[](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
|
+
}
|