go-on-rails 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bf87cd74390e6eda98fa3fd0f463803699abba3a
4
- data.tar.gz: 6e4a785e95fde8e7d0bac8667663642a98a157f3
3
+ metadata.gz: 2839e5d56004e5a3974cb77427e5c3438ef3c5df
4
+ data.tar.gz: 24a489fcc1fac898832b6d1269a287d0c88d7a89
5
5
  SHA512:
6
- metadata.gz: 1f9dd6bcc8a2548005c93a18542694f2b9113d28ff8b9010ef3cdc19b9b1fe7fb1cdaeeb51e93e97600f0815d9f77ee95f5441ed5ed35e441c81df950f9df6b8
7
- data.tar.gz: 2d0f3af07182f02f4dff820bfe276b8bb0174711badc71aeffc302eb11dc28464d33e7b2a31e1776f6e7f589cd8f1e85118181719d2644bd8bdc97ff9ca7d8a9
6
+ metadata.gz: 6107aa404f72156d23e5191b0414c5d5c6d391eaca61e68cf48031f17d55c627fe4c30e8f46a2aeb6939c850835e2c83504354155ad369ffd03f7a64f443a7c5
7
+ data.tar.gz: 3a3a53bc94bbc3d8ce3b9d48b8d6140b8e1e2b19699843d13ed97206cdc9345b809330092b350cbf66c5afa97de2bba5ee99b5b582cd2cfde5c456f3edbe9032
data/README.md CHANGED
@@ -1,41 +1,67 @@
1
1
  go-on-rails
2
2
  ====
3
3
 
4
+ ## Prerequisites
5
+
6
+ * Rails development environment
7
+ * Golang development environment
8
+
4
9
  ## Installation
5
10
 
6
11
  Add this line to your application's Gemfile:
7
12
 
8
- ``ruby
13
+ ```ruby
9
14
  gem 'go-on-rails'
10
- ``
15
+ ```
11
16
 
12
17
  And then execute:
13
- ``bash
18
+ ```bash
14
19
  $ bundle
15
- ``
20
+ ```
16
21
 
17
22
  Or install it yourself as:
18
- ``bash
23
+ ```bash
19
24
  $ gem install go-on-rails
20
- ``
21
-
25
+ ```
22
26
  ## Usage
23
27
 
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.
28
+ go-on-rails aims at three scenarios:
29
+
30
+ 1. Integrate some api written in Golang to existed Rails app for high performance
31
+ 2. Use your farmiliar Rails tools to develope and manage a Golang app project
32
+ 3. Convert a *not very complicated* Rails app to Golang equivalent
33
+
34
+ One or more examples will be given later on.
35
+
36
+ So you must have a Rails app or to create one before you can try go-on-rails generator to convert a Rails app to Golang codes.
37
+
38
+ You can just run the command to convert the application:
39
+
40
+ ```bash
41
+ rails g gor [dev(elopment) | pro(duction) | test] [-m model_a model_b model_c ...]
42
+ ```
43
+
44
+ Then a directory named "go_app" with Golang codes will be generated under your Rails app root path.
45
+
46
+ Install the dependent Golang packages:
47
+
48
+ ```bash
49
+ rails gor:deps
50
+ ```
25
51
 
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.
52
+ Then change to the "go_app" directory and run:
27
53
 
28
- You can basically run the command to convert the application:
54
+ ```bash
55
+ go run main.go
56
+ ```
29
57
 
30
- ``ruby
31
- rails g gor [dev(elopment) | pro(duction) | test]
32
- ``
58
+ You can visit the page in http://localhost:3000 by default.
33
59
 
34
- About more command details, you can run:
60
+ More command details about go-on-rails generator:
35
61
 
36
- ``ruby
62
+ ```bash
37
63
  rails g gor --help
38
- ``
64
+ ```
39
65
 
40
66
  And the gem is still under development, so there're a lot of known issues.
41
67
 
@@ -44,9 +70,9 @@ And the gem is still under development, so there're a lot of known issues.
44
70
  * the generated Golang codes includes the association between models, basic relations like has_many, has_one, belongs_to have been supported
45
71
  * so some association functions is available
46
72
  * and the :dependent action is triggered when destroying some related model
47
- * but the :through keyword not supported yet
48
73
  * databases specific functions between mysql, postgres are not covered yet
49
- * model callbacks in not available
74
+ * model callbacks is not available
75
+ * sql.NullType not supported yet, so you'd better set all columns "not null" with a default value in the migration, such as "" default for string and text typed column, and 0 default for int, etc, that's consistent with Golang's zero value specification.
50
76
 
51
77
  Really a lot...
52
78
 
@@ -1,41 +1,41 @@
1
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
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
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?
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},omitempty\" 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
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
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(" "))
39
36
  end
37
+ end
38
+ info
40
39
  end
40
+ end
41
41
  end
@@ -1,97 +1,97 @@
1
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: ""}
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
33
24
 
34
- self.max_col_size = get_max_col_size
35
- self.max_type_size = get_max_type_size
25
+ def convert
26
+ get_schema_info
27
+ end
36
28
 
37
- self.klass.columns.each_with_index do |col, index|
38
- tags = []
29
+ private
39
30
 
40
- # add struct tag
41
- tags << struct_tag(col)
31
+ def get_schema_info
32
+ struct_info = {col_names: [], timestamp_cols: [], has_datetime_type: false, struct_body: ""}
42
33
 
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
34
+ self.max_col_size = get_max_col_size
35
+ self.max_type_size = get_max_type_size
48
36
 
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
37
+ self.klass.columns.each_with_index do |col, index|
38
+ tags = []
56
39
 
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
40
+ # add struct tag
41
+ tags << struct_tag(col)
61
42
 
62
- assoc = get_associations
63
- struct_info[:struct_body] << assoc[:struct_body]
64
- struct_info[:assoc_info] = assoc[:assoc_info]
65
- return struct_info
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
66
47
  end
67
48
 
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
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"
73
55
  end
74
56
 
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
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
80
61
 
81
- def get_struct_name
82
- self.klass.table_name.camelize
83
- end
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
84
67
 
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
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
89
74
 
90
- def struct_tag(col)
91
- "json:\"#{col.name}\" db:\"#{col.name}\""
92
- end
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
93
80
 
81
+ def get_struct_name
82
+ self.klass.table_name.camelize
94
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},omitempty\" db:\"#{col.name}\""
92
+ end
93
+
94
+ end
95
95
  end
96
96
 
97
97
  require_relative 'association'
@@ -5,89 +5,96 @@ class GorGenerator < Rails::Generators::Base
5
5
  class_option :only_models, type: :boolean, default: false, aliases: '-o', description: "only generate models"
6
6
 
7
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
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
13
 
14
- rails_env = case env_name
15
- when "dev"
16
- "development"
17
- when "pro"
18
- "production"
19
- else
20
- env_name
21
- end
14
+ rails_env = case env_name
15
+ when "dev"
16
+ "development"
17
+ when "pro"
18
+ "production"
19
+ else
20
+ env_name
21
+ end
22
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!"
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
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
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}"
43
42
  end
43
+ end
44
44
 
45
- unless options[:only_models]
46
- # generate the main.go
47
- copy_file "main.go", "go_app/main.go"
45
+ unless options[:only_models]
46
+ # generate the main.go
47
+ copy_file "main.go", "go_app/main.go"
48
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"
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
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
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
+
60
+ # use gofmt to prettify the generated Golang files
61
+ gofmt_go_files
59
62
  end
60
63
 
61
64
  private
62
65
 
63
66
  def get_all_models model_dir
64
- Dir.chdir(model_dir) do
65
- Dir["**/*.rb"]
66
- end.map { |m| m.sub(/\.rb$/,'').camelize }
67
+ Dir.chdir(model_dir) do
68
+ Dir["**/*.rb"]
69
+ end.map { |m| m.sub(/\.rb$/,'').camelize }
67
70
  end
68
71
 
69
72
  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
73
+ db_conf = Rails.configuration.database_configuration[rails_env]
74
+ case db_conf["adapter"]
75
+ when "sqlite3"
76
+ @db_config[:driver_name] = "sqlite3"
77
+ @db_config[:dsn] = "../" + db_conf["database"]
78
+ @db_config[:driver_package] = "_ \"github.com/mattn/go-sqlite3\""
79
+ when "mysql2"
80
+ @db_config[:driver_name] = "mysql"
81
+ # MySQL DSN format: username:password@protocol(address)/dbname?param=value
82
+ # See more: https://github.com/go-sql-driver/mysql
83
+ format = "%s:%s@%s/%s?charset=%s&parseTime=True&loc=Local"
84
+ @db_config[:dsn] = sprintf(format, *db_conf.values_at("username", "password", "host", "database", "encoding"))
85
+ @db_config[:driver_package] = "_ \"github.com/go-sql-driver/mysql\""
86
+ when "postgresql"
87
+ @db_config[:driver_name] = "postgres"
88
+ format = "host=%s user=%s dbname=%s sslmode=disable password=%s"
89
+ @db_config[:dsn] = sprintf(format, *db_conf.values_at("host", "username", "database", "password"))
90
+ @db_config[:driver_package] = "_ \"github.com/lib/pq\""
91
+ end
89
92
  end
90
93
 
94
+ def gofmt_go_files
95
+ go_files = Rails.root.join('go_app', 'models/*.go').to_s
96
+ system "gofmt -w #{go_files} > /dev/null 2>&1"
97
+ end
91
98
  end
92
99
 
93
100
  require_relative 'go_on_rails/converter'
@@ -1,8 +1,9 @@
1
1
  <%- param_name_plural = table_name = @model_name.underscore.pluralize -%>
2
2
  <%- model_name_underscore = @model_name.underscore -%>
3
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
4
+ // The file is generated by go-on-rails, a Rails generator gem:
5
+ // https://rubygems.org/gems/go-on-rails
6
+ // Or on Github: https://github.com/goonr/go-on-rails
6
7
  // By B1nj0y <idegorepl@gmail.com>
7
8
  package model
8
9
 
@@ -42,9 +43,13 @@ func Find<%= @model_name.pluralize %>(ids ...int64) ([]<%= @model_name %>, error
42
43
  return nil, errors.New(msg)
43
44
  }
44
45
  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)
46
+ idsHolder := strings.Repeat(",?", len(ids)-1)
47
+ sql := fmt.Sprintf(`SELECT * FROM <%= table_name %> WHERE id IN (?%s)`, idsHolder)
48
+ idsT := []interface{}{}
49
+ for _,id := range ids {
50
+ idsT = append(idsT, interface{}(id))
51
+ }
52
+ err := db.Select(&var_<%= param_name_plural %>, sql, idsT...)
48
53
  if err != nil {
49
54
  log.Printf("Error: %v\n", err)
50
55
  return nil, err
@@ -179,9 +184,9 @@ func Find<%= @model_name.pluralize %>BySql(sql string, args ...interface{}) (<%=
179
184
  return <%= param_name_plural %>, nil
180
185
  }
181
186
 
182
- func Create<%= @model_name %>(am map[string]interface{}) error {
187
+ func Create<%= @model_name %>(am map[string]interface{}) (int64, error) {
183
188
  if len(am) == 0 {
184
- return fmt.Errorf("Zero key in the attributes map!")
189
+ return 0, fmt.Errorf("Zero key in the attributes map!")
185
190
  }
186
191
  <%- unless @struct_info[:timestamp_cols].empty? -%>
187
192
  t := time.Now()
@@ -199,12 +204,17 @@ func Create<%= @model_name %>(am map[string]interface{}) error {
199
204
  }
200
205
  sqlFmt := `INSERT INTO <%= table_name %> (%s) VALUES (%s)`
201
206
  sqlStr := fmt.Sprintf(sqlFmt, strings.Join(keys, ","), ":"+strings.Join(keys, ",:"))
202
- _, err := db.NamedExec(sqlStr, am)
207
+ result, err := db.NamedExec(sqlStr, am)
203
208
  if err != nil {
204
209
  log.Print(err)
205
- return err
210
+ return 0, err
206
211
  }
207
- return nil
212
+ lastId, err := result.LastInsertId()
213
+ if err != nil {
214
+ log.Print(err)
215
+ return 0, err
216
+ }
217
+ return lastId, nil
208
218
  }
209
219
 
210
220
  func (var_<%= model_name_underscore %> *<%= @model_name %>) Create() error {
@@ -223,25 +233,43 @@ func (var_<%= model_name_underscore %> *<%= @model_name %>) Create() error {
223
233
  <%- has_many = @struct_info[:assoc_info][:has_many] -%>
224
234
  <%- has_many.each do |k, v| -%>
225
235
  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
236
+ <%- if v[:through] -%>
237
+ // FIXME: use transaction to create these associated objects
238
+ <%= v[:class_name].underscore %>_id, err := Create<%= v[:class_name] %>(am)
239
+ if err != nil {
240
+ return err
241
+ }
242
+ _, err = Create<%= v[:through].to_s.singularize.camelize %>(map[string]interface{}{"<%= model_name_underscore %>_id": var_<%= model_name_underscore %>.Id, "<%= v[:class_name].underscore %>_id": <%= v[:class_name].underscore %>_id})
243
+ <%- else -%>
244
+ <%- if v[:foreign_key] -%>
245
+ am["<%= v[:foreign_key] %>"] = var_<%= model_name_underscore %>.Id
246
+ <%- else -%>
247
+ am["<%= model_name_underscore %>_id"] = var_<%= model_name_underscore %>.Id
248
+ <%- end -%>
249
+ _, err := Create<%= v[:class_name] %>(am)
230
250
  <%- end -%>
231
- err := Create<%= v[:class_name] %>(am)
232
251
  return err
233
252
  }
234
253
 
235
254
  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)
255
+ <%- if v[:through] -%>
256
+ // FIXME: use transaction to create these associated objects
257
+ <%= v[:class_name].underscore %>_ids, err := <%= v[:through].to_s.singularize.camelize %>IntCol("<%= v[:class_name].underscore %>_id", "<%= model_name_underscore %>_id = ?", var_<%= model_name_underscore %>.Id)
258
+ if err != nil {
259
+ return err
260
+ }
261
+ var_<%= v[:class_name].underscore.pluralize %>, err := Find<%= v[:class_name].pluralize %>(<%= v[:class_name].underscore %>_ids...)
262
+ <%- else -%>
263
+ <%- if v[:foreign_key] -%>
264
+ var_<%= v[:class_name].underscore.pluralize %>, err := Find<%= v[:class_name].pluralize %>By("<%= v[:foreign_key] %>", var_<%= model_name_underscore %>.Id)
265
+ <%- else -%>
266
+ var_<%= v[:class_name].underscore.pluralize %>, err := Find<%= v[:class_name].pluralize %>By("<%= model_name_underscore %>_id", var_<%= model_name_underscore %>.Id)
267
+ <%- end -%>
240
268
  <%- end -%>
241
269
  if err == nil {
242
270
  var_<%= model_name_underscore %>.<%= k %> = var_<%= v[:class_name].underscore.pluralize %>
243
- }
244
- return err
271
+ }
272
+ return err
245
273
  }
246
274
  <%- end -%>
247
275
  <%- end -%>
@@ -255,7 +283,7 @@ func (var_<%= model_name_underscore %> *<%= @model_name %>) Create<%= v[:class_n
255
283
  <%- else -%>
256
284
  am["<%= model_name_underscore %>_id"] = var_<%= model_name_underscore %>.Id
257
285
  <%- end -%>
258
- err := Create<%= v[:class_name] %>(am)
286
+ _, err := Create<%= v[:class_name] %>(am)
259
287
  return err
260
288
  }
261
289
  <%- end -%>
@@ -270,7 +298,7 @@ func (var_<%= model_name_underscore %> *<%= @model_name %>) Create<%= v[:class_n
270
298
  <%- else -%>
271
299
  am["<%= model_name_underscore %>_id"] = var_<%= model_name_underscore %>.Id
272
300
  <%- end -%>
273
- err := Create<%= v[:class_name] %>(am)
301
+ _, err := Create<%= v[:class_name] %>(am)
274
302
  return err
275
303
  }
276
304
  <%- end -%>
@@ -295,10 +323,25 @@ func Destroy<%= @model_name %>(id int64) error {
295
323
  <%- unless ass_cols.empty? -%>
296
324
  <%- ass_cols.each_value do |opts| -%>
297
325
  <%- if opts.key? :dependent -%>
298
- <%- if opts.key? :foreign_key -%>
299
- Destroy<%= opts[:class_name].pluralize %>Where("<%= opts[:foreign_key] %> = ?", id)
326
+ <%- if opts[:through] -%>
327
+ <%= opts[:class_name].underscore %>_ids, err := <%= opts[:through].to_s.singularize.camelize %>IntCol("<%= opts[:class_name].underscore %>_id", "<%= model_name_underscore %>_id = ?", var_<%= model_name_underscore %>.Id)
328
+ if err != nil {
329
+ return err
330
+ }
331
+ _, err = Destroy<%= opts[:class_name].pluralize %>(<%= opts[:class_name].underscore %>_ids...)
332
+ if err != nil {
333
+ return err
334
+ }
335
+ _, err = Destroy<%= opts[:through].to_s.pluralize.camelize %>Where("<%= model_name_underscore %>_id = ?", var_<%= model_name_underscore %>.Id)
336
+ if err != nil {
337
+ return err
338
+ }
300
339
  <%- else -%>
301
- Destroy<%= opts[:class_name].pluralize %>Where("<%= model_name_underscore %>_id = ?", id)
340
+ <%- if opts.key? :foreign_key -%>
341
+ Destroy<%= opts[:class_name].pluralize %>Where("<%= opts[:foreign_key] %> = ?", id)
342
+ <%- else -%>
343
+ Destroy<%= opts[:class_name].pluralize %>Where("<%= model_name_underscore %>_id = ?", id)
344
+ <%- end -%>
302
345
  <%- end -%>
303
346
  <%- end -%>
304
347
  <%- end -%>
@@ -313,10 +356,14 @@ func Destroy<%= @model_name.pluralize %>(ids ...int64) (int64, error) {
313
356
  log.Println(msg)
314
357
  return 0, errors.New(msg)
315
358
  }
316
- idsStr := strings.Trim(strings.Replace(fmt.Sprint(ids), " ", ",", -1), "[]")
317
- sql := fmt.Sprintf(`DELETE FROM <%= table_name %> WHERE id IN (%s)`, idsStr)
359
+ idsHolder := strings.Repeat(",?", len(ids)-1)
360
+ sql := fmt.Sprintf(`DELETE FROM <%= table_name %> WHERE id IN (?%s)`, idsHolder)
361
+ idsT := []interface{}{}
362
+ for _,id := range ids {
363
+ idsT = append(idsT, interface{}(id))
364
+ }
318
365
  stmt, err := db.Preparex(sql)
319
- result, err := stmt.Exec()
366
+ result, err := stmt.Exec(idsT...)
320
367
  if err != nil {
321
368
  return 0, err
322
369
  }
@@ -330,11 +377,11 @@ func Destroy<%= @model_name.pluralize %>(ids ...int64) (int64, error) {
330
377
  <%- ass_cols.each_value do |opts| -%>
331
378
  <%- if opts.key? :dependent -%>
332
379
  <%- if opts.key? :foreign_key -%>
333
- where := fmt.Sprintf("<%= opts[:foreign_key] %> IN (%s)", idsStr)
334
- Destroy<%= opts[:class_name].pluralize %>Where(where)
380
+ where := fmt.Sprintf("<%= opts[:foreign_key] %> IN (?%s)", idsHolder)
381
+ Destroy<%= opts[:class_name].pluralize %>Where(where, idsT)
335
382
  <%- else -%>
336
- where := fmt.Sprintf("<%= model_name_underscore %>_id IN (%s)", idsStr)
337
- Destroy<%= opts[:class_name].pluralize %>Where(where)
383
+ where := fmt.Sprintf("<%= model_name_underscore %>_id IN (?%s)", idsHolder)
384
+ Destroy<%= opts[:class_name].pluralize %>Where(where, idsT)
338
385
  <%- end -%>
339
386
  <%- end -%>
340
387
  <%- end -%>
@@ -373,7 +420,8 @@ func (var_<%= model_name_underscore %> *<%= @model_name %>) Save() error {
373
420
  var_<%= model_name_underscore %>.UpdatedAt = time.Now()
374
421
  <%- end -%>
375
422
  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)
423
+ <%- save_col_names = col_names - ["created_at"] -%>
424
+ sqlStr := fmt.Sprintf(sqlFmt, "<%= save_col_names.zip(save_col_names).map{|c| c.join(" = :")}.join(", ") %>", var_<%= model_name_underscore %>.Id)
377
425
  _, err := db.NamedExec(sqlStr, var_<%= model_name_underscore %>)
378
426
  return err
379
427
  }
@@ -0,0 +1,14 @@
1
+ namespace :gor do
2
+ desc 'Install dependent Golang packages'
3
+ task :deps do
4
+ puts 'Beginning to install Go deps...'
5
+ system "go get \
6
+ github.com/jmoiron/sqlx \
7
+ github.com/gorilla/handlers \
8
+ github.com/gorilla/mux \
9
+ github.com/mattn/go-sqlite3 \
10
+ github.com/go-sql-driver/mysql \
11
+ github.com/lib/pq"
12
+ puts 'Installation completed!'
13
+ end
14
+ end
metadata CHANGED
@@ -1,19 +1,18 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: go-on-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - B1nj0y
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-04-03 00:00:00.000000000 Z
11
+ date: 2017-04-14 00:00:00.000000000 Z
12
12
  dependencies: []
13
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)
14
+ tools like rails generate, db migration, console etc. It also help integrating some
15
+ api written in Golang to existed Rails app for high performance.
17
16
  email: idegorepl@gmail.com
18
17
  executables: []
19
18
  extensions: []
@@ -31,6 +30,7 @@ files:
31
30
  - lib/generators/gor/templates/home_controller.go
32
31
  - lib/generators/gor/templates/index.tmpl
33
32
  - lib/generators/gor/templates/main.go
33
+ - lib/tasks/gor.rake
34
34
  homepage: https://github.com/goonr/go-on-rails
35
35
  licenses:
36
36
  - MIT