go-on-rails 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bf87cd74390e6eda98fa3fd0f463803699abba3a
4
+ data.tar.gz: 6e4a785e95fde8e7d0bac8667663642a98a157f3
5
+ SHA512:
6
+ metadata.gz: 1f9dd6bcc8a2548005c93a18542694f2b9113d28ff8b9010ef3cdc19b9b1fe7fb1cdaeeb51e93e97600f0815d9f77ee95f5441ed5ed35e441c81df950f9df6b8
7
+ data.tar.gz: 2d0f3af07182f02f4dff820bfe276b8bb0174711badc71aeffc302eb11dc28464d33e7b2a31e1776f6e7f589cd8f1e85118181719d2644bd8bdc97ff9ca7d8a9
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017 B1nj0y <idegorepl@gmail.com>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,64 @@
1
+ go-on-rails
2
+ ====
3
+
4
+ ## Installation
5
+
6
+ Add this line to your application's Gemfile:
7
+
8
+ ``ruby
9
+ gem 'go-on-rails'
10
+ ``
11
+
12
+ And then execute:
13
+ ``bash
14
+ $ bundle
15
+ ``
16
+
17
+ Or install it yourself as:
18
+ ``bash
19
+ $ gem install go-on-rails
20
+ ``
21
+
22
+ ## Usage
23
+
24
+ go-on-rails is a Rails generator used to generate Golang codes from your ever running Rails app or an application that you would create with familiar Rails command tools. One or more examples will be given later on.
25
+
26
+ So you must have a Rails app or to create one before you can use go-on-rails generator to convert a Rails app to Golang codes.
27
+
28
+ You can basically run the command to convert the application:
29
+
30
+ ``ruby
31
+ rails g gor [dev(elopment) | pro(duction) | test]
32
+ ``
33
+
34
+ About more command details, you can run:
35
+
36
+ ``ruby
37
+ rails g gor --help
38
+ ``
39
+
40
+ And the gem is still under development, so there're a lot of known issues.
41
+
42
+ ## Known issues and TODOs
43
+
44
+ * the generated Golang codes includes the association between models, basic relations like has_many, has_one, belongs_to have been supported
45
+ * so some association functions is available
46
+ * and the :dependent action is triggered when destroying some related model
47
+ * but the :through keyword not supported yet
48
+ * databases specific functions between mysql, postgres are not covered yet
49
+ * model callbacks in not available
50
+
51
+ Really a lot...
52
+
53
+ ## Acknowledgement
54
+
55
+ When I had the idea to convert Rails app or build Golang app with Rails tools, I searched github and found the project: https://github.com/t-k/ar2gostruct. And from ar2gostruct I copied some codes on handling data structure convertion and models association, it make my idea come true faster than I imagined.
56
+
57
+ ## Contributing
58
+
59
+ - Fork the project.
60
+ - Make your feature addition or bug fix.
61
+ - Add tests for it. This is important so I don't break it in a future version unintentionally.
62
+ - Commit, do not mess with Rakefile or version (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
63
+ - Send me a pull request. Bonus points for topic branches.
64
+
@@ -0,0 +1,30 @@
1
+ Description:
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
+
4
+ read more: https://github.com/gingerhot/goonrails
5
+
6
+
7
+ Example:
8
+ rails generate gor development -m user post
9
+
10
+ Here are valid ENV_NAME arguments: [dev, development, pro, production, test], the default ENV_NAME is "development" if you omit it.
11
+
12
+ So you can also run:
13
+
14
+ rails g gor dev -m user post
15
+
16
+ This will mainly create:
17
+ go_app/main.go
18
+ go_app/db/conn.go
19
+ go_app/models/user/gor_user.go
20
+ go_app/models/user/gor_post.go
21
+
22
+ Notice: If you omit the -m option, all the models of the Rails app will be generated.
23
+
24
+ So if you omit all the options, just run:
25
+
26
+ rails g gor
27
+
28
+ This will generate all the models and database connection with Rails development env params.
29
+
30
+
@@ -0,0 +1,41 @@
1
+ module GoOnRails
2
+ class Association
3
+ def initialize(klass, models, max_col_size, max_type_size)
4
+ @klass = klass
5
+ @models = models
6
+ @max_col_size = max_col_size
7
+ @max_type_size = max_type_size
8
+ end
9
+ attr_reader :klass, :models, :max_col_size, :max_type_size
10
+
11
+ def get_schema_info
12
+ info = {struct_body: "", assoc_info: {has_many: {}, has_one: {}, belongs_to: {}}}
13
+ self.klass.reflect_on_all_associations.each do |assoc|
14
+ tags = ["json:\"#{assoc.name.to_s}\" db:\"#{assoc.name.to_s}\""]
15
+ case assoc.macro
16
+ when :has_many
17
+ col_name = assoc.name.to_s.camelize
18
+ class_name = assoc.name.to_s.singularize.camelize
19
+ unless assoc.options.empty?
20
+ class_name = assoc.options[:class_name] if assoc.options.key? :class_name
21
+ end
22
+ type_name = "[]#{class_name}"
23
+ info[:assoc_info][:has_many][col_name] = {class_name: class_name}
24
+ info[:assoc_info][:has_many][col_name].merge!(assoc.options) unless assoc.options.empty?
25
+
26
+ when :has_one, :belongs_to
27
+ col_name = class_name = assoc.name.to_s.camelize
28
+ class_name = assoc.options[:class_name] if assoc.options.key? :class_name unless assoc.options.empty?
29
+ type_name = class_name
30
+ info[:assoc_info][assoc.macro][col_name] = {class_name: class_name}
31
+ info[:assoc_info][assoc.macro][col_name].merge!(assoc.options) unless assoc.options.empty?
32
+ end
33
+ if col_name && type_name && (self.models.include? class_name)
34
+ format = "\t%-#{max_col_size}.#{max_col_size+2}s%-#{max_type_size}.#{max_type_size}s`%s`\n"
35
+ info[:struct_body] << sprintf(format, col_name, type_name, tags.join(" "))
36
+ end
37
+ end
38
+ info
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,97 @@
1
+ module GoOnRails
2
+ class Convertor
3
+ TYPE_MAP = {
4
+ "string" => "string",
5
+ "text" => "string",
6
+ "boolean" => "bool",
7
+ "integer(1)" => "int8",
8
+ "integer(2)" => "int16",
9
+ "integer(3)" => "int32",
10
+ "integer(4)" => "int64",
11
+ "integer(8)" => "int64",
12
+ "float" => "float64",
13
+ "datetime" => "time.Time",
14
+ "date" => "time.Time"
15
+ }
16
+
17
+ def initialize(klass, models, option = {})
18
+ @klass = klass
19
+ @models = models
20
+ @max_col_size = 0
21
+ @max_type_size = 0
22
+ end
23
+ attr_accessor :klass, :models, :max_col_size, :max_type_size
24
+
25
+ def convert
26
+ get_schema_info
27
+ end
28
+
29
+ private
30
+
31
+ def get_schema_info
32
+ struct_info = {col_names: [], timestamp_cols: [], has_datetime_type: false, struct_body: ""}
33
+
34
+ self.max_col_size = get_max_col_size
35
+ self.max_type_size = get_max_type_size
36
+
37
+ self.klass.columns.each_with_index do |col, index|
38
+ tags = []
39
+
40
+ # add struct tag
41
+ tags << struct_tag(col)
42
+
43
+ col_type = col.type.to_s
44
+ struct_info[:has_datetime_type] = true if %w(datetime time).include? col_type
45
+ if col_type == "datetime" and %w(created_at updated_at).include? col.name
46
+ struct_info[:timestamp_cols] << col.name
47
+ end
48
+
49
+ case col_type
50
+ when "integer"
51
+ type = TYPE_MAP["integer(#{col.limit})"] || "int64"
52
+ type = "u#{type}" if col.sql_type.match("unsigned").present?
53
+ else
54
+ type = TYPE_MAP[col_type] || "string"
55
+ end
56
+
57
+ format = (index == 0 ? "" : "\t") + "%-#{self.max_col_size}.#{self.max_col_size}s%-#{self.max_type_size}.#{self.max_type_size}s`%s`\n"
58
+ struct_info[:col_names] << col.name unless col.name == "id"
59
+ struct_info[:struct_body] << sprintf(format, col.name.camelize, type, tags.join(" "))
60
+ end
61
+
62
+ assoc = get_associations
63
+ struct_info[:struct_body] << assoc[:struct_body]
64
+ struct_info[:assoc_info] = assoc[:assoc_info]
65
+ return struct_info
66
+ end
67
+
68
+ def get_max_col_size
69
+ col_name_max_size = self.klass.column_names.collect{|name| name.size}.max || 0
70
+ assoc_max_size = self.klass.reflect_on_all_associations.collect{|assoc| assoc.name.to_s.size}.max || 0
71
+ type_max_size = TYPE_MAP.collect{|key, value| key.size}.max || 0
72
+ [col_name_max_size + 1, assoc_max_size, type_max_size].max
73
+ end
74
+
75
+ def get_max_type_size
76
+ assoc_max_size = self.klass.reflect_on_all_associations.collect{|assoc| assoc.name.to_s.size + 2}.max || 0
77
+ type_max_size = TYPE_MAP.collect{|key, value| key.size}.max || 0
78
+ [assoc_max_size, type_max_size].max
79
+ end
80
+
81
+ def get_struct_name
82
+ self.klass.table_name.camelize
83
+ end
84
+
85
+ def get_associations
86
+ builder = GoOnRails::Association.new(self.klass, self.models, self.max_col_size, self.max_type_size)
87
+ builder.get_schema_info
88
+ end
89
+
90
+ def struct_tag(col)
91
+ "json:\"#{col.name}\" db:\"#{col.name}\""
92
+ end
93
+
94
+ end
95
+ end
96
+
97
+ require_relative 'association'
@@ -0,0 +1,93 @@
1
+ class GorGenerator < Rails::Generators::Base
2
+ source_root File.expand_path('../templates', __FILE__)
3
+ argument :env_name, type: :string, default: "development"
4
+ class_option :models, type: :array, default: [], aliases: '-m'
5
+ class_option :only_models, type: :boolean, default: false, aliases: '-o', description: "only generate models"
6
+
7
+ def generate_gor
8
+ env_names = %W(dev development pro production test)
9
+ unless env_names.include? env_name
10
+ printf("Invalid env argument: Not any of %p\n\n", env_names)
11
+ exit
12
+ end
13
+
14
+ rails_env = case env_name
15
+ when "dev"
16
+ "development"
17
+ when "pro"
18
+ "production"
19
+ else
20
+ env_name
21
+ end
22
+
23
+ models = options[:models]
24
+ if models.empty?
25
+ models = get_all_models "app/models"
26
+ else
27
+ models.map!(&:camelize)
28
+ end
29
+ puts "The models: #{models} and Rails env [#{rails_env}] will be used to generate Golang App!"
30
+
31
+ models.each do |m|
32
+ begin
33
+ klass = m.split('::').inject(Object) { |kls, part| kls.const_get(part) }
34
+ if klass < ActiveRecord::Base && !klass.abstract_class?
35
+ @model_name = klass.to_s
36
+ convertor = GoOnRails::Convertor.new(klass, models)
37
+ @struct_info = convertor.convert
38
+ template "gor_model.go.erb", "go_app/models/gor_#{@model_name.underscore}.go"
39
+ end
40
+ rescue Exception => e
41
+ puts "Failed to convert the model [#{m}]: #{e.message}"
42
+ end
43
+ end
44
+
45
+ unless options[:only_models]
46
+ # generate the main.go
47
+ copy_file "main.go", "go_app/main.go"
48
+
49
+ # generate program for database connection
50
+ @db_config = {}
51
+ create_database_config(rails_env)
52
+ template "db.go.erb", "go_app/models/db.go"
53
+
54
+ # generate the controllers and views dir
55
+ copy_file "home_controller.go", "go_app/controllers/home_controller.go"
56
+ copy_file "index.tmpl", "go_app/views/index.tmpl"
57
+ copy_file "favicon.ico", "go_app/public/favicon.ico"
58
+ end
59
+ end
60
+
61
+ private
62
+
63
+ def get_all_models model_dir
64
+ Dir.chdir(model_dir) do
65
+ Dir["**/*.rb"]
66
+ end.map { |m| m.sub(/\.rb$/,'').camelize }
67
+ end
68
+
69
+ def create_database_config rails_env
70
+ db_conf = Rails.configuration.database_configuration[rails_env]
71
+ case db_conf["adapter"]
72
+ when "sqlite3"
73
+ @db_config[:driver_name] = "sqlite3"
74
+ @db_config[:dsn] = "../" + db_conf["database"]
75
+ @db_config[:driver_package] = "_ \"github.com/mattn/go-sqlite3\""
76
+ when "mysql2"
77
+ @db_config[:driver_name] = "mysql"
78
+ # MySQL DSN format: username:password@protocol(address)/dbname?param=value
79
+ # See more: https://github.com/go-sql-driver/mysql
80
+ format = "%s:%s@%s/%s?charset=%s&parseTime=True&loc=Local"
81
+ @db_config[:dsn] = sprintf(format, *db_conf.values_at("username", "password", "host", "database", "encoding"))
82
+ @db_config[:driver_package] = "_ \"github.com/go-sql-driver/mysql\""
83
+ when "postgresql"
84
+ @db_config[:driver_name] = "postgres"
85
+ format = "host=%s user=%s dbname=%s sslmode=disable password=%s"
86
+ @db_config[:dsn] = sprintf(format, *db_conf.values_at("host", "username", "database", "password"))
87
+ @db_config[:driver_package] = "_ \"github.com/lib/pq\""
88
+ end
89
+ end
90
+
91
+ end
92
+
93
+ require_relative 'go_on_rails/converter'
@@ -0,0 +1,26 @@
1
+ package model
2
+
3
+ import (
4
+ "log"
5
+
6
+ <%= @db_config[:driver_package] %>
7
+ "github.com/jmoiron/sqlx"
8
+ )
9
+
10
+ var db *sqlx.DB
11
+
12
+ func init() {
13
+ var err error
14
+ driver_name := "<%= @db_config[:driver_name] %>"
15
+ if driver_name == "" {
16
+ log.Fatal("Invalid driver name")
17
+ }
18
+ dsn := "<%= @db_config[:dsn] %>"
19
+ if dsn == "" {
20
+ log.Fatal("Invalid DSN")
21
+ }
22
+ db, err = sqlx.Connect(driver_name, dsn)
23
+ if err != nil {
24
+ log.Fatal(err)
25
+ }
26
+ }
@@ -0,0 +1,451 @@
1
+ <%- param_name_plural = table_name = @model_name.underscore.pluralize -%>
2
+ <%- model_name_underscore = @model_name.underscore -%>
3
+ <%- col_names = @struct_info[:col_names] -%>
4
+ // The file is generated by go_on_rails, a Rails generator gem:
5
+ // https://rubygems.org/gems/go_on_rails
6
+ // By B1nj0y <idegorepl@gmail.com>
7
+ package model
8
+
9
+ import (
10
+ "errors"
11
+ "fmt"
12
+ "log"
13
+ "strings"
14
+ <%- if @struct_info[:has_datetime_type] -%>
15
+ "time"
16
+ <%- end -%>
17
+ )
18
+
19
+ type <%= @model_name %> struct {
20
+ <%= @struct_info[:struct_body] -%>
21
+ }
22
+
23
+ // Find<%= @model_name %> find a single <%= model_name_underscore %> by an id
24
+ func Find<%= @model_name %>(id int64) (*<%= @model_name %>, error) {
25
+ if id == 0 {
26
+ return nil, errors.New("Invalid id: it can't be zero")
27
+ }
28
+ var_<%= model_name_underscore %> := <%= @model_name %>{}
29
+ err := db.Get(&var_<%= model_name_underscore %>, "SELECT * FROM <%= table_name %> WHERE id = $1 LIMIT 1", id)
30
+ if err != nil {
31
+ log.Printf("Error: %v\n", err)
32
+ return nil, err
33
+ }
34
+ return &var_<%= model_name_underscore %>, nil
35
+ }
36
+
37
+ // Find<%= @model_name.pluralize %> find one or more <%= model_name_underscore.pluralize %> by one or more ids
38
+ func Find<%= @model_name.pluralize %>(ids ...int64) ([]<%= @model_name %>, error) {
39
+ if len(ids) == 0 {
40
+ msg := "At least one or more ids needed"
41
+ log.Println(msg)
42
+ return nil, errors.New(msg)
43
+ }
44
+ var_<%= param_name_plural %> := []<%= @model_name %>{}
45
+ idsStr := strings.Trim(strings.Replace(fmt.Sprint(ids), " ", ",", -1), "[]")
46
+ sql := fmt.Sprintf(`SELECT * FROM <%= table_name %> WHERE id IN (%s)`, idsStr)
47
+ err := db.Select(&var_<%= param_name_plural %>, sql)
48
+ if err != nil {
49
+ log.Printf("Error: %v\n", err)
50
+ return nil, err
51
+ }
52
+ return var_<%= param_name_plural %>, nil
53
+ }
54
+
55
+ // Find<%= @model_name %>By find a single <%= model_name_underscore %> by a field name and a value
56
+ func Find<%= @model_name %>By(field string, val interface{}) (*<%= @model_name %>, error) {
57
+ var_<%= model_name_underscore %> := <%= @model_name %>{}
58
+ sqlFmt := `SELECT * FROM <%= table_name %> WHERE %s = $1 LIMIT 1`
59
+ sqlStr := fmt.Sprintf(sqlFmt, field)
60
+ err := db.Get(&var_<%= model_name_underscore %>, sqlStr, val)
61
+ if err != nil {
62
+ log.Printf("Error: %v\n", err)
63
+ return nil, err
64
+ }
65
+ return &var_<%= model_name_underscore %>, nil
66
+ }
67
+
68
+ // Find<%= @model_name.pluralize %>By find all <%= param_name_plural %> by a field name and a value
69
+ func Find<%= @model_name.pluralize %>By(field string, val interface{}) (var_<%= param_name_plural %> []<%= @model_name %>, err error) {
70
+ sqlFmt := `SELECT * FROM <%= table_name %> WHERE %s = $1`
71
+ sqlStr := fmt.Sprintf(sqlFmt, field)
72
+ err = db.Select(&var_<%= param_name_plural %>, sqlStr, val)
73
+ if err != nil {
74
+ log.Printf("Error: %v\n", err)
75
+ return nil, err
76
+ }
77
+ return var_<%= param_name_plural %>, nil
78
+ }
79
+
80
+ // All<%= @model_name.pluralize %> get all the <%= @model_name %> records
81
+ func All<%= @model_name.pluralize %>() (<%= param_name_plural %> []<%= @model_name %>, err error) {
82
+ err = db.Select(&<%= table_name %>, "SELECT * FROM <%= table_name %>")
83
+ if err != nil {
84
+ log.Print(err)
85
+ return nil, err
86
+ }
87
+ return <%= param_name_plural %>, nil
88
+ }
89
+
90
+ // <%= @model_name %>Ids get all the Ids of <%= @model_name %> records
91
+ func <%= @model_name %>Ids() (ids []int64, err error) {
92
+ err = db.Select(&ids, "SELECT id FROM <%= table_name %>")
93
+ if err != nil {
94
+ log.Print(err)
95
+ return nil, err
96
+ }
97
+ return ids, nil
98
+ }
99
+
100
+ // <%= @model_name %>Ids get all the Ids of <%= @model_name %> records by where restriction
101
+ func <%= @model_name %>IdsWhere(where string, args ...interface{}) ([]int64, error) {
102
+ ids, err := <%= @model_name %>IntCol("id", where, args...)
103
+ return ids, err
104
+ }
105
+
106
+ // <%= @model_name %>IntCol get some int64 typed column of <%= @model_name %> by where restriction
107
+ func <%= @model_name %>IntCol(col, where string, args ...interface{}) (intColRecs []int64, err error) {
108
+ sql := "SELECT " + col + " FROM <%= table_name %>"
109
+ if len(where) > 0 {
110
+ sql = sql + " WHERE " + where
111
+ }
112
+ stmt, err := db.Preparex(sql)
113
+ if err != nil {
114
+ log.Print(err)
115
+ return nil, err
116
+ }
117
+ err = stmt.Select(&intColRecs, args...)
118
+ if err != nil {
119
+ log.Print(err)
120
+ return nil, err
121
+ }
122
+ return intColRecs, nil
123
+ }
124
+
125
+ // <%= @model_name %>StrCol get some string typed column of <%= @model_name %> by where restriction
126
+ func <%= @model_name %>StrCol(col, where string, args ...interface{}) (strColRecs []string, err error) {
127
+ sql := "SELECT " + col + " FROM <%= table_name %>"
128
+ if len(where) > 0 {
129
+ sql = sql + " WHERE " + where
130
+ }
131
+ stmt, err := db.Preparex(sql)
132
+ if err != nil {
133
+ log.Print(err)
134
+ return nil, err
135
+ }
136
+ err = stmt.Select(&strColRecs, args...)
137
+ if err != nil {
138
+ log.Print(err)
139
+ return nil, err
140
+ }
141
+ return strColRecs, nil
142
+ }
143
+
144
+ // Find<%= @model_name.pluralize %>Where query use a partial SQL clause that usually following after WHERE
145
+ // with placeholders, eg: FindUsersWhere("first_name = ? AND age > ?", "John", 18)
146
+ // will return those records in the table "users" whose first_name is "John" and age elder than 18
147
+ func Find<%= @model_name.pluralize %>Where(where string, args ...interface{}) (<%= param_name_plural %> []<%= @model_name %>, err error) {
148
+ sql := "SELECT * FROM <%= table_name %>"
149
+ if len(where) > 0 {
150
+ sql = sql + " WHERE " + where
151
+ }
152
+ stmt, err := db.Preparex(sql)
153
+ if err != nil {
154
+ log.Print(err)
155
+ return nil, err
156
+ }
157
+ err = stmt.Select(&<%= param_name_plural %>, args...)
158
+ if err != nil {
159
+ log.Print(err)
160
+ return nil, err
161
+ }
162
+ return <%= param_name_plural %>, nil
163
+ }
164
+
165
+ // Find<%= @model_name.pluralize %>BySql query use a complete SQL clause
166
+ // with placeholders, eg: FindUsersBySql("SELECT * FROM users WHERE first_name = ? AND age > ?", "John", 18)
167
+ // will return those records in the table "users" whose first_name is "John" and age elder than 18
168
+ func Find<%= @model_name.pluralize %>BySql(sql string, args ...interface{}) (<%= param_name_plural %> []<%= @model_name %>, err error) {
169
+ stmt, err := db.Preparex(sql)
170
+ if err != nil {
171
+ log.Print(err)
172
+ return nil, err
173
+ }
174
+ err = stmt.Select(&<%= param_name_plural %>, args...)
175
+ if err != nil {
176
+ log.Print(err)
177
+ return nil, err
178
+ }
179
+ return <%= param_name_plural %>, nil
180
+ }
181
+
182
+ func Create<%= @model_name %>(am map[string]interface{}) error {
183
+ if len(am) == 0 {
184
+ return fmt.Errorf("Zero key in the attributes map!")
185
+ }
186
+ <%- unless @struct_info[:timestamp_cols].empty? -%>
187
+ t := time.Now()
188
+ for _, v := range []string{<%= @struct_info[:timestamp_cols].map(&:inspect).join(", ") %>} {
189
+ if am[v] == nil {
190
+ am[v] = t
191
+ }
192
+ }
193
+ <%- end -%>
194
+ keys := make([]string, len(am))
195
+ i := 0
196
+ for k := range am {
197
+ keys[i] = k
198
+ i++
199
+ }
200
+ sqlFmt := `INSERT INTO <%= table_name %> (%s) VALUES (%s)`
201
+ sqlStr := fmt.Sprintf(sqlFmt, strings.Join(keys, ","), ":"+strings.Join(keys, ",:"))
202
+ _, err := db.NamedExec(sqlStr, am)
203
+ if err != nil {
204
+ log.Print(err)
205
+ return err
206
+ }
207
+ return nil
208
+ }
209
+
210
+ func (var_<%= model_name_underscore %> *<%= @model_name %>) Create() error {
211
+ <%- unless @struct_info[:timestamp_cols].empty? -%>
212
+ t := time.Now()
213
+ <%- @struct_info[:timestamp_cols].each do |c| -%>
214
+ var_<%= model_name_underscore %>.<%= c.camelize %> = t
215
+ <%- end -%>
216
+ <%- end -%>
217
+ sql := `INSERT INTO <%= table_name %> (<%= col_names.join(",") %>) VALUES (:<%= col_names.join(",:") %>)`
218
+ _, err := db.NamedExec(sql, var_<%= model_name_underscore %>)
219
+ return err
220
+ }
221
+
222
+ <%- unless @struct_info[:assoc_info][:has_many].empty? -%>
223
+ <%- has_many = @struct_info[:assoc_info][:has_many] -%>
224
+ <%- has_many.each do |k, v| -%>
225
+ func (var_<%= model_name_underscore %> *<%= @model_name %>) <%= v[:class_name].pluralize %>Create(am map[string]interface{}) error {
226
+ <%- if v[:foreign_key] -%>
227
+ am["<%= v[:foreign_key] %>"] = var_<%= model_name_underscore %>.Id
228
+ <%- else -%>
229
+ am["<%= model_name_underscore %>_id"] = var_<%= model_name_underscore %>.Id
230
+ <%- end -%>
231
+ err := Create<%= v[:class_name] %>(am)
232
+ return err
233
+ }
234
+
235
+ func (var_<%= model_name_underscore %> *<%= @model_name %>) Get<%= v[:class_name].pluralize %>() error {
236
+ <%- if v[:foreign_key] -%>
237
+ var_<%= v[:class_name].underscore.pluralize %>, err := Find<%= v[:class_name].pluralize %>By("<%= v[:foreign_key] %>", var_<%= model_name_underscore %>.Id)
238
+ <%- else -%>
239
+ var_<%= v[:class_name].underscore.pluralize %>, err := Find<%= v[:class_name].pluralize %>By("<%= model_name_underscore %>_id", var_<%= model_name_underscore %>.Id)
240
+ <%- end -%>
241
+ if err == nil {
242
+ var_<%= model_name_underscore %>.<%= k %> = var_<%= v[:class_name].underscore.pluralize %>
243
+ }
244
+ return err
245
+ }
246
+ <%- end -%>
247
+ <%- end -%>
248
+
249
+ <%- unless @struct_info[:assoc_info][:has_one].empty? -%>
250
+ <%- has_one = @struct_info[:assoc_info][:has_one] -%>
251
+ <%- has_one.each do |k, v| -%>
252
+ func (var_<%= model_name_underscore %> *<%= @model_name %>) Create<%= v[:class_name] %>(am map[string]interface{}) error {
253
+ <%- if v[:foreign_key] -%>
254
+ am["<%= v[:foreign_key] %>"] = var_<%= model_name_underscore %>.Id
255
+ <%- else -%>
256
+ am["<%= model_name_underscore %>_id"] = var_<%= model_name_underscore %>.Id
257
+ <%- end -%>
258
+ err := Create<%= v[:class_name] %>(am)
259
+ return err
260
+ }
261
+ <%- end -%>
262
+ <%- end -%>
263
+
264
+ <%- unless @struct_info[:assoc_info][:belongs_to].empty? -%>
265
+ <%- belongs_to = @struct_info[:assoc_info][:belongs_to] -%>
266
+ <%- belongs_to.each do |k, v| -%>
267
+ func (var_<%= model_name_underscore %> *<%= @model_name %>) Create<%= v[:class_name] %>(am map[string]interface{}) error {
268
+ <%- if v[:foreign_key] -%>
269
+ am["<%= v[:foreign_key] %>"] = var_<%= model_name_underscore %>.Id
270
+ <%- else -%>
271
+ am["<%= model_name_underscore %>_id"] = var_<%= model_name_underscore %>.Id
272
+ <%- end -%>
273
+ err := Create<%= v[:class_name] %>(am)
274
+ return err
275
+ }
276
+ <%- end -%>
277
+ <%- end -%>
278
+
279
+ func (var_<%= model_name_underscore %> *<%= @model_name %>) Destroy() error {
280
+ if var_<%= model_name_underscore %>.Id == 0 {
281
+ return errors.New("Invalid Id field: it can't be a zero value")
282
+ }
283
+ err := Destroy<%= @model_name %>(var_<%= model_name_underscore %>.Id)
284
+ return err
285
+ }
286
+
287
+ func Destroy<%= @model_name %>(id int64) error {
288
+ stmt, err := db.Preparex(`DELETE FROM <%= table_name %> WHERE id = ?`)
289
+ _, err = stmt.Exec(id)
290
+ if err != nil {
291
+ return err
292
+ }
293
+ <%- [:has_many, :has_one].each do |ass| -%>
294
+ <%- ass_cols = @struct_info[:assoc_info][ass] -%>
295
+ <%- unless ass_cols.empty? -%>
296
+ <%- ass_cols.each_value do |opts| -%>
297
+ <%- if opts.key? :dependent -%>
298
+ <%- if opts.key? :foreign_key -%>
299
+ Destroy<%= opts[:class_name].pluralize %>Where("<%= opts[:foreign_key] %> = ?", id)
300
+ <%- else -%>
301
+ Destroy<%= opts[:class_name].pluralize %>Where("<%= model_name_underscore %>_id = ?", id)
302
+ <%- end -%>
303
+ <%- end -%>
304
+ <%- end -%>
305
+ <%- end -%>
306
+ <%- end -%>
307
+ return nil
308
+ }
309
+
310
+ func Destroy<%= @model_name.pluralize %>(ids ...int64) (int64, error) {
311
+ if len(ids) == 0 {
312
+ msg := "At least one or more ids needed"
313
+ log.Println(msg)
314
+ return 0, errors.New(msg)
315
+ }
316
+ idsStr := strings.Trim(strings.Replace(fmt.Sprint(ids), " ", ",", -1), "[]")
317
+ sql := fmt.Sprintf(`DELETE FROM <%= table_name %> WHERE id IN (%s)`, idsStr)
318
+ stmt, err := db.Preparex(sql)
319
+ result, err := stmt.Exec()
320
+ if err != nil {
321
+ return 0, err
322
+ }
323
+ cnt, err := result.RowsAffected()
324
+ if err != nil {
325
+ return 0, err
326
+ }
327
+ <%- [:has_many, :has_one].each do |ass| -%>
328
+ <%- ass_cols = @struct_info[:assoc_info][ass] -%>
329
+ <%- unless ass_cols.empty? -%>
330
+ <%- ass_cols.each_value do |opts| -%>
331
+ <%- if opts.key? :dependent -%>
332
+ <%- if opts.key? :foreign_key -%>
333
+ where := fmt.Sprintf("<%= opts[:foreign_key] %> IN (%s)", idsStr)
334
+ Destroy<%= opts[:class_name].pluralize %>Where(where)
335
+ <%- else -%>
336
+ where := fmt.Sprintf("<%= model_name_underscore %>_id IN (%s)", idsStr)
337
+ Destroy<%= opts[:class_name].pluralize %>Where(where)
338
+ <%- end -%>
339
+ <%- end -%>
340
+ <%- end -%>
341
+ <%- end -%>
342
+ <%- end -%>
343
+ return cnt, nil
344
+ }
345
+
346
+ // Destroy<%= @model_name.pluralize %>Where delete records by a where clause
347
+ // like: Destroy<%= @model_name.pluralize %>Where("name = ?", "John")
348
+ // And this func will not call the association dependent action
349
+ func Destroy<%= @model_name.pluralize %>Where(where string, args ...interface{}) (int64, error) {
350
+ sql := `DELETE FROM <%= table_name %> WHERE `
351
+ if len(where) > 0 {
352
+ sql = sql + where
353
+ } else {
354
+ return 0, errors.New("No WHERE conditions provided")
355
+ }
356
+ stmt, err := db.Preparex(sql)
357
+ result, err := stmt.Exec(args...)
358
+ if err != nil {
359
+ return 0, err
360
+ }
361
+ cnt, err := result.RowsAffected()
362
+ if err != nil {
363
+ return 0, err
364
+ }
365
+ return cnt, nil
366
+ }
367
+
368
+ func (var_<%= model_name_underscore %> *<%= @model_name %>) Save() error {
369
+ if var_<%= model_name_underscore %>.Id == 0 {
370
+ return errors.New("Invalid Id field: it can't be a zero value")
371
+ }
372
+ <%- if @struct_info[:timestamp_cols].include? "updated_at" -%>
373
+ var_<%= model_name_underscore %>.UpdatedAt = time.Now()
374
+ <%- end -%>
375
+ sqlFmt := `UPDATE <%= table_name %> SET %s WHERE id = %v`
376
+ sqlStr := fmt.Sprintf(sqlFmt, "<%= col_names.zip(col_names).map{|c| c.join(" = :")}.join(", ") %>", var_<%= model_name_underscore %>.Id)
377
+ _, err := db.NamedExec(sqlStr, var_<%= model_name_underscore %>)
378
+ return err
379
+ }
380
+
381
+ func Update<%= @model_name %>(id int64, am map[string]interface{}) error {
382
+ if len(am) == 0 {
383
+ return errors.New("Zero key in the attributes map!")
384
+ }
385
+ <%- if @struct_info[:timestamp_cols].include? "updated_at" -%>
386
+ am["updated_at"] = time.Now()
387
+ <%- end -%>
388
+ keys := make([]string, len(am))
389
+ i := 0
390
+ for k := range am {
391
+ keys[i] = k
392
+ i++
393
+ }
394
+ sqlFmt := `UPDATE <%= table_name %> SET %s WHERE id = %v`
395
+ setKeysArr := []string{}
396
+ for _,v := range keys {
397
+ s := fmt.Sprintf(" %s = :%s", v, v)
398
+ setKeysArr = append(setKeysArr, s)
399
+ }
400
+ sqlStr := fmt.Sprintf(sqlFmt, strings.Join(setKeysArr, ", "), id)
401
+ _, err := db.NamedExec(sqlStr, am)
402
+ if err != nil {
403
+ log.Print(err)
404
+ return err
405
+ }
406
+ return nil
407
+ }
408
+
409
+ func (var_<%= model_name_underscore %> *<%= @model_name %>) Update(am map[string]interface{}) error {
410
+ if var_<%= model_name_underscore %>.Id == 0 {
411
+ return errors.New("Invalid Id field: it can't be a zero value")
412
+ }
413
+ err := Update<%= @model_name %>(var_<%= model_name_underscore %>.Id, am)
414
+ return err
415
+ }
416
+
417
+ func (var_<%= model_name_underscore %> *<%= @model_name %>) UpdateAttributes(am map[string]interface{}) error {
418
+ if var_<%= model_name_underscore %>.Id == 0 {
419
+ return errors.New("Invalid Id field: it can't be a zero value")
420
+ }
421
+ err := Update<%= @model_name %>(var_<%= model_name_underscore %>.Id, am)
422
+ return err
423
+ }
424
+
425
+ func (var_<%= model_name_underscore %> *<%= @model_name %>) UpdateColumns(am map[string]interface{}) error {
426
+ if var_<%= model_name_underscore %>.Id == 0 {
427
+ return errors.New("Invalid Id field: it can't be a zero value")
428
+ }
429
+ err := Update<%= @model_name %>(var_<%= model_name_underscore %>.Id, am)
430
+ return err
431
+ }
432
+
433
+ func Update<%= @model_name.pluralize %>BySql(sql string, args ...interface{}) (int64, error) {
434
+ if sql == "" {
435
+ return 0, errors.New("A blank SQL clause")
436
+ }
437
+ <%- if @struct_info[:timestamp_cols].include? "updated_at" -%>
438
+ sql = strings.Replace(strings.ToLower(sql), "set", "set updated_at = ?, ", 1)
439
+ args = append([]interface{}{time.Now()}, args...)
440
+ <%- end -%>
441
+ stmt, err := db.Preparex(sql)
442
+ result, err := stmt.Exec(args...)
443
+ if err != nil {
444
+ return 0, err
445
+ }
446
+ cnt, err := result.RowsAffected()
447
+ if err != nil {
448
+ return 0, err
449
+ }
450
+ return cnt, nil
451
+ }
@@ -0,0 +1,27 @@
1
+ package controller
2
+
3
+ import (
4
+ "html/template"
5
+ "net/http"
6
+ // you can import models
7
+ //m "../models"
8
+ )
9
+
10
+ func HomeHandler(w http.ResponseWriter, r *http.Request) {
11
+ // you can use model functions to do CRUD
12
+ //
13
+ // user, _ := m.FindUser(1)
14
+ // u, err := json.Marshal(user)
15
+ // if err != nil {
16
+ // log.Printf("JSON encoding error: %v\n", err)
17
+ // u = []byte("Get data error!")
18
+ // }
19
+
20
+ type Greeting struct {
21
+ Name string
22
+ Words string
23
+ }
24
+ greeting := Greeting{Name: "Rubyist", Words: "Welcome to GoOnRails!"}
25
+ t, _ := template.ParseFiles("views/index.tmpl")
26
+ t.Execute(w, greeting)
27
+ }
@@ -0,0 +1,8 @@
1
+ <html>
2
+ <title>GoOnRails Framework</title>
3
+ <body>
4
+ <h1>
5
+ Hello {{ .Name }}, {{ .Words }}
6
+ </h1>
7
+ </body>
8
+ </html>
@@ -0,0 +1,29 @@
1
+ package main
2
+
3
+ import (
4
+ "flag"
5
+ "log"
6
+ "net/http"
7
+ "os"
8
+
9
+ c "./controllers"
10
+ "github.com/gorilla/handlers"
11
+ "github.com/gorilla/mux"
12
+ )
13
+
14
+ func main() {
15
+ // The app will run on port 3000 by default, you can custom it with the flag -port
16
+ servePort := flag.String("port", "3000", "Http Server Port")
17
+ flag.Parse()
18
+ log.Printf("The application starting on the port: [%v]\n", *servePort)
19
+
20
+ // Here we are instantiating the gorilla/mux router
21
+ r := mux.NewRouter()
22
+ // Then we bind some route to some handler(controller action)
23
+ r.HandleFunc("/", c.HomeHandler)
24
+ // Create a static assets router
25
+ r.PathPrefix("/public/").Handler(http.StripPrefix("/public/", http.FileServer(http.Dir("./public/"))))
26
+
27
+ // Let's start the server
28
+ http.ListenAndServe(":"+*servePort, handlers.LoggingHandler(os.Stdout, r))
29
+ }
metadata ADDED
@@ -0,0 +1,58 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: go-on-rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - B1nj0y
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-04-03 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Modeling, developing and testing your Golang app with your familiar Rails
14
+ tools like rails generate, db migration, console etc. And you can convert your ever
15
+ running Rails app to Golang app partially or completely(not now or your Rails app
16
+ not so complicated)
17
+ email: idegorepl@gmail.com
18
+ executables: []
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - MIT-LICENSE
23
+ - README.md
24
+ - lib/generators/gor/USAGE
25
+ - lib/generators/gor/go_on_rails/association.rb
26
+ - lib/generators/gor/go_on_rails/converter.rb
27
+ - lib/generators/gor/gor_generator.rb
28
+ - lib/generators/gor/templates/db.go.erb
29
+ - lib/generators/gor/templates/favicon.ico
30
+ - lib/generators/gor/templates/gor_model.go.erb
31
+ - lib/generators/gor/templates/home_controller.go
32
+ - lib/generators/gor/templates/index.tmpl
33
+ - lib/generators/gor/templates/main.go
34
+ homepage: https://github.com/goonr/go-on-rails
35
+ licenses:
36
+ - MIT
37
+ metadata: {}
38
+ post_install_message:
39
+ rdoc_options: []
40
+ require_paths:
41
+ - lib
42
+ required_ruby_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ required_rubygems_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ requirements: []
53
+ rubyforge_project:
54
+ rubygems_version: 2.5.2
55
+ signing_key:
56
+ specification_version: 4
57
+ summary: Use Rails generator to Generate a Golang application
58
+ test_files: []