goon_model_gen 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/lib/goon_model_gen/builder/abstract_builder.rb +104 -0
  3. data/lib/goon_model_gen/builder/model_builder.rb +74 -0
  4. data/lib/goon_model_gen/builder/store_builder.rb +45 -0
  5. data/lib/goon_model_gen/builder/validation_builder.rb +32 -0
  6. data/lib/goon_model_gen/cli.rb +38 -11
  7. data/lib/goon_model_gen/config.rb +4 -2
  8. data/lib/goon_model_gen/generator.rb +6 -0
  9. data/lib/goon_model_gen/golang/field.rb +1 -0
  10. data/lib/goon_model_gen/golang/packages.rb +5 -0
  11. data/lib/goon_model_gen/golang/struct.rb +2 -2
  12. data/lib/goon_model_gen/golang/type.rb +5 -0
  13. data/lib/goon_model_gen/source/field.rb +1 -2
  14. data/lib/goon_model_gen/source/file.rb +1 -0
  15. data/lib/goon_model_gen/source/loader.rb +19 -1
  16. data/lib/goon_model_gen/source/type.rb +1 -1
  17. data/lib/goon_model_gen/templates/model/enum/02_Map.go.erb +1 -1
  18. data/lib/goon_model_gen/templates/store/goon/01_Binder.go.erb +10 -0
  19. data/lib/goon_model_gen/templates/store/goon/02_Hook.go.erb +10 -0
  20. data/lib/goon_model_gen/templates/store/goon/03_struct.go.erb +4 -0
  21. data/lib/goon_model_gen/templates/store/goon/04_KindName.go.erb +3 -0
  22. data/lib/goon_model_gen/templates/store/goon/05_Query.go.erb +11 -0
  23. data/lib/goon_model_gen/templates/store/goon/06_Run.go.erb +10 -0
  24. data/lib/goon_model_gen/templates/store/goon/07_All.go.erb +8 -0
  25. data/lib/goon_model_gen/templates/store/goon/08_AllBy.go.erb +24 -0
  26. data/lib/goon_model_gen/templates/store/goon/09_Select.go.erb +9 -0
  27. data/lib/goon_model_gen/templates/store/goon/10_FirstBy.go.erb +17 -0
  28. data/lib/goon_model_gen/templates/store/goon/11_CountBy.go.erb +16 -0
  29. data/lib/goon_model_gen/templates/store/goon/12_ByID.go.erb +20 -0
  30. data/lib/goon_model_gen/templates/store/goon/13_ByKey.go.erb +15 -0
  31. data/lib/goon_model_gen/templates/store/goon/14_Get.go.erb +22 -0
  32. data/lib/goon_model_gen/templates/store/goon/15_IsValidKey.go.erb +20 -0
  33. data/lib/goon_model_gen/templates/store/goon/16_Exist.go.erb +28 -0
  34. data/lib/goon_model_gen/templates/store/goon/17_Create.go.erb +24 -0
  35. data/lib/goon_model_gen/templates/store/goon/18_Update.go.erb +24 -0
  36. data/lib/goon_model_gen/templates/store/goon/19_PutWith.go.erb +28 -0
  37. data/lib/goon_model_gen/templates/store/goon/20_Put.go.erb +17 -0
  38. data/lib/goon_model_gen/templates/store/goon/21_Delete.go.erb +20 -0
  39. data/lib/goon_model_gen/templates/store/goon/22_ValidateUniqueness.go.erb +35 -0
  40. data/lib/goon_model_gen/templates/store/goon/23_Validate.go.erb +14 -0
  41. data/lib/goon_model_gen/templates/validation/error/01_struct.go.erb +4 -0
  42. data/lib/goon_model_gen/templates/validation/error/02_Error.go.erb +4 -0
  43. data/lib/goon_model_gen/version.rb +1 -1
  44. metadata +30 -2
  45. data/lib/goon_model_gen/model_builder.rb +0 -137
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f1bc7f66fb836ee7b30fd1aa1d53853c51fd2de8bf18d3a0675ed769b4e09c35
4
- data.tar.gz: 384a9ed52b7f63d4170f06eb6f3f02652178519e09fad4c2b6985909786ecbef
3
+ metadata.gz: 316458bf5f2033fb2e803fc8cb74b8a8ef80a44eb2adf8bec57862a9283b19ad
4
+ data.tar.gz: 57100fe6b8c389a3f0eb7faa8ea4e7ac063e386c9866d9eb24eeb0c0ea82ef55
5
5
  SHA512:
6
- metadata.gz: 64638b0fdf6cc508399c632ce39e20e34536926f5a02df1999bfdd891c15ba1f5cdea474b772e471ddc80775a19f1fc69f64279406dd26a68e076783b46c5de7
7
- data.tar.gz: 27cca1dcb36984d1b276e6b614dd6acce691138d33e85fe39c79f46d15dfe6c0974877f58022b1169986e4b6305ead73c094aead6ed0a5a10d08cfb85fbf0515
6
+ metadata.gz: 9f52397b1dbb695e7f65826cccb701b9cb171bc861b03c50274fd00d94a3a53b5312022f096bedc2fca6d956c0d18748daa2344c673b47c84cfd0b7bbe7ff582
7
+ data.tar.gz: 8226739cfb3a3404a70eb5814e6d0b7ba8169216850ad509f11493bad632bc3ed0392e4b40da811c06f56cdc5378e10a26b7dd8bbbb8cc04557937e4988b2c58
@@ -0,0 +1,104 @@
1
+ require "goon_model_gen"
2
+
3
+ require "goon_model_gen/golang/packages"
4
+
5
+ module GoonModelGen
6
+ module Builder
7
+ class AbstractBuilder
8
+ attr_reader :base_package_path
9
+
10
+ # @param base_package_path [String]
11
+ def initialize(base_package_path)
12
+ @base_package_path = base_package_path
13
+ end
14
+
15
+ # @param context [Source::Context]
16
+ # @return [Golang::Packages]
17
+ def build(context)
18
+ Golang::Packages.new.tap do |r|
19
+ build_sentences = []
20
+ context.files.each do |f|
21
+ package_path = File.join(base_package_path, f.basename)
22
+ pkg, procs = build_package(package_path, f.types)
23
+ r << pkg
24
+ build_sentences.concat(procs)
25
+ end
26
+ resolve_type_names(r)
27
+ build_sentences.each(&:call)
28
+ end
29
+ end
30
+
31
+ # @param package_path [String]
32
+ # @param types [Array<Source::Type>]
33
+ # @return [Golang::Package, Array<Proc>]
34
+ def build_package(package_path, types)
35
+ raise NotImplementedError, "#{self.type.name} doesn't implement build_package method"
36
+ end
37
+
38
+ # @param pkgs [Golang::Packages]
39
+ def resolve_type_names(pkgs)
40
+ raise NotImplementedError, "#{self.type.name} doesn't implement resolve_type_names method"
41
+ end
42
+
43
+ # @param action [string] directory name under templates directory. ex. model, store...
44
+ # @param kind [string] directory name under the directory specified by action. ex. goon, struct, enum, slice
45
+ # @param t [Source::Struct]
46
+ # @param go_type [Golang::Type]
47
+ def build_sentences(action, kind, t, go_type)
48
+ template_base = File.join(action, kind)
49
+ build_sentences_with(template_base, go_type, t.generators[action])
50
+ end
51
+
52
+ # @param template_base [string] template directory path from templates directory. ex. model/enum, store/goon...
53
+ # @param generators [Hash<string,Object>]
54
+ # @param go_type [Golang::Type]
55
+ def build_sentences_with(template_base, go_type, generators)
56
+ m2t = method_to_template_for(template_base)
57
+ generators ||= default_generators_for(template_base)
58
+ generators.each do |name, suffix|
59
+ next if !suffix
60
+ template = m2t[name]
61
+ raise "No template found for #{name.inspect}" unless template
62
+ parts = [go_type.name.underscore]
63
+ custom_suffix = false
64
+ if suffix.is_a?(String)
65
+ parts << suffix
66
+ custom_suffix = true
67
+ end
68
+ filename = parts.join('_') << '.go'
69
+ go_type.package.find_or_new_file(filename).tap do |file|
70
+ file.custom_suffix = custom_suffix
71
+ file.new_sentence(File.join(template_base, template), go_type)
72
+ end
73
+ end
74
+ end
75
+
76
+ def default_generators_for(template_base)
77
+ method_to_template_for(template_base).keys.
78
+ each_with_object({}){|name, d| d[name] = true }
79
+ end
80
+
81
+ def method_to_template_map
82
+ @method_to_template_map ||= {}
83
+ end
84
+
85
+ def method_to_template_for(template_base)
86
+ method_to_template_map[template_base] ||=
87
+ begin
88
+ templates_for(template_base).each_with_object({}) do |filename, d|
89
+ m = filename.sub(/\A\d+\_/, '').sub(/\.go\.erb\z/, '')
90
+ d[m] = filename
91
+ end
92
+ end
93
+ end
94
+
95
+ def templates_for(template_base)
96
+ base_dir = File.join(File.expand_path('../../templates', __FILE__), template_base)
97
+ Dir.chdir(base_dir) do
98
+ Dir.glob('*.go.erb')
99
+ end
100
+ end
101
+
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,74 @@
1
+ require "goon_model_gen"
2
+
3
+ require "goon_model_gen/builder/abstract_builder"
4
+
5
+ require "goon_model_gen/source/struct"
6
+ require "goon_model_gen/source/enum"
7
+ require "goon_model_gen/source/named_slice"
8
+
9
+ require "goon_model_gen/golang/package"
10
+ require "goon_model_gen/golang/packages"
11
+ require "goon_model_gen/golang/datastore_supported"
12
+
13
+ require "active_support/core_ext/string"
14
+
15
+ module GoonModelGen
16
+ module Builder
17
+ class ModelBuilder < AbstractBuilder
18
+
19
+ # @param package_path [String]
20
+ # @param types [Array<Source::Type>]
21
+ # @return [Golang::Package, Array<Proc>]
22
+ def build_package(package_path, types)
23
+ procs = []
24
+ pkg = Golang::Package.new(package_path).tap do |pkg|
25
+ types.each do |t|
26
+ case t
27
+ when Source::Struct then
28
+ go_type = build_struct(t, pkg)
29
+ kind = (t.id_name && t.id_type) ? 'goon' : 'struct'
30
+ procs << Proc.new{ build_sentences('model', kind, t, go_type) }
31
+ when Source::Enum then
32
+ go_type = pkg.new_enum(t.name, t.base_type, t.map)
33
+ procs << Proc.new{ build_sentences('model', 'enum', t, go_type) }
34
+ when Source::NamedSlice then
35
+ go_type = pkg.new_named_slice(t.name, t.base_type_name)
36
+ procs << Proc.new{ build_sentences('model', 'slice', t, go_type) }
37
+ else
38
+ raise "Unsupported type #{t.class.name} #{t.inspect}"
39
+ end
40
+ end
41
+ end
42
+ return pkg, procs
43
+ end
44
+
45
+ # @param pkgs [Golang::Packages]
46
+ def resolve_type_names(pkgs)
47
+ pkgs.resolve_type_names(Golang::DatastoreSupported.packages)
48
+ end
49
+
50
+ # @param t [Source::Struct]
51
+ # @param pkg [Golang::Package]
52
+ # @return [Golang::Struct]
53
+ def build_struct(t, pkg)
54
+ pkg.new_struct(t.name).tap do |s|
55
+ s.ref_name = t.ref_name
56
+ if t.id_name && t.id_type
57
+ tags = {
58
+ 'goon' => ['id'],
59
+ 'datastore' => ['-'],
60
+ 'json' => [t.id_name.underscore],
61
+ }
62
+ s.new_field(t.id_name, t.id_type, tags, goon_id: true)
63
+ end
64
+ t.fields.each do |f|
65
+ s.new_field(f.name, f.type_name, f.build_tags).tap do |field|
66
+ field.unique = f.unique
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,45 @@
1
+ require "goon_model_gen"
2
+
3
+ require "goon_model_gen/builder/abstract_builder"
4
+
5
+ require "goon_model_gen/source/struct"
6
+
7
+ require "goon_model_gen/golang/package"
8
+ require "goon_model_gen/golang/datastore_supported"
9
+
10
+
11
+ module GoonModelGen
12
+ module Builder
13
+ class StoreBuilder < AbstractBuilder
14
+ attr_reader :model_packages
15
+
16
+ # @param base_package_path [String]
17
+ # @param model_packages [Golang::Packages]
18
+ def initialize(base_package_path, model_packages)
19
+ super(base_package_path)
20
+ @model_packages = model_packages
21
+ end
22
+
23
+ # @param package_path [String]
24
+ # @param types [Array<Source::Type>]
25
+ # @return [Golang::Package, Array<Proc>]
26
+ def build_package(package_path, types)
27
+ procs = []
28
+ pkg = Golang::Package.new(package_path).tap do |pkg|
29
+ types.select{|t| t.is_a?(Source::Struct) && t.id_name && t.id_type }.each do |t|
30
+ store_type = pkg.new_struct(t.name + "Store")
31
+ procs << Proc.new{ build_sentences('store', 'goon', t, store_type) }
32
+ store_type.memo[:model] = model_packages.detect_by(t.file.basename).lookup(t.name)
33
+ end
34
+ end
35
+ return pkg, procs
36
+ end
37
+
38
+ # @param pkgs [Golang::Packages]
39
+ def resolve_type_names(pkgs)
40
+ pkgs.resolve_type_names(Golang::DatastoreSupported.packages.dup.add(model_packages))
41
+ end
42
+
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,32 @@
1
+ require "goon_model_gen"
2
+
3
+ require "goon_model_gen/builder/abstract_builder"
4
+
5
+ require "goon_model_gen/golang/packages"
6
+ require "goon_model_gen/golang/datastore_supported"
7
+
8
+
9
+ module GoonModelGen
10
+ module Builder
11
+ class ValidationBuilder < AbstractBuilder
12
+
13
+ # @return [Golang::Packages]
14
+ def build(*)
15
+ Golang::Packages.new.tap do |r|
16
+ r.new_package(base_package_path).tap do |pkg|
17
+ t = pkg.new_struct('ValidationError')
18
+ pkg.new_file('validation_error.go').tap do |f|
19
+ build_sentences_with('validation/error', t, nil)
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ # @param pkgs [Golang::Packages]
26
+ def resolve_type_names(pkgs)
27
+ pkgs.resolve_type_names(Golang::DatastoreSupported.packages)
28
+ end
29
+
30
+ end
31
+ end
32
+ end
@@ -5,7 +5,9 @@ require "yaml"
5
5
  require "thor"
6
6
 
7
7
  require "goon_model_gen/config"
8
- require "goon_model_gen/model_builder"
8
+ require "goon_model_gen/builder/model_builder"
9
+ require "goon_model_gen/builder/store_builder"
10
+ require "goon_model_gen/builder/validation_builder"
9
11
  require "goon_model_gen/source/loader"
10
12
  require "goon_model_gen/generator"
11
13
 
@@ -30,17 +32,29 @@ module GoonModelGen
30
32
  puts YAML.dump(context)
31
33
  end
32
34
 
33
- desc "build FILE1...", "Build golang objects from source YAML files"
34
- def build(*paths)
35
- packages = build_model_objects(paths)
36
- puts YAML.dump(packages)
37
- end
38
-
39
35
  desc "model FILE1...", "Generate model files from source YAML files"
36
+ option :inspect, type: :boolean, desc: "Don't generate any file and show package objects if given"
40
37
  def model(*paths)
41
38
  packages = build_model_objects(paths)
42
- packages.map(&:files).flatten.each do |f|
43
- new_generator(f, packages).run
39
+ if options[:inspect]
40
+ puts YAML.dump(packages)
41
+ else
42
+ packages.map(&:files).flatten.each do |f|
43
+ new_generator(f, packages).run
44
+ end
45
+ end
46
+ end
47
+
48
+ desc "store FILE1...", "Generate store files from source YAML files"
49
+ option :inspect, type: :boolean, desc: "Don't generate any file and show package objects if given"
50
+ def store(*paths)
51
+ packages = build_store_packages(paths).add(*validation_packages)
52
+ if options[:inspect]
53
+ puts YAML.dump(packages)
54
+ else
55
+ packages.map(&:files).flatten.each do |f|
56
+ new_generator(f, packages).run
57
+ end
44
58
  end
45
59
  end
46
60
 
@@ -59,8 +73,16 @@ module GoonModelGen
59
73
  # @return [Array<Golang::Package>]
60
74
  def build_model_objects(paths)
61
75
  context = Source::Loader.new.process(paths)
62
- b = ModelBuilder.new(cfg.model_package_path)
63
- b.build(context)
76
+ Builder::ModelBuilder.new(cfg.model_package_path).build(context)
77
+ end
78
+
79
+ # @param paths [Array<String>] Source::Context
80
+ # @return [Array<Golang::Package>]
81
+ def build_store_packages(paths)
82
+ context = Source::Loader.new.process(paths)
83
+ model_packages = Builder::ModelBuilder.new(cfg.model_package_path).build(context)
84
+ store_packages = Builder::StoreBuilder.new(cfg.store_package_path, model_packages).build(context)
85
+ return store_packages
64
86
  end
65
87
 
66
88
  # @param f [Golang::File]
@@ -74,6 +96,11 @@ module GoonModelGen
74
96
  g.overwrite_custom_file = options[:overwrite_custom_file]
75
97
  return g
76
98
  end
99
+
100
+ # @return [Golang::Package]
101
+ def validation_packages
102
+ Builder::ValidationBuilder.new(cfg.validation_package_path).build
103
+ end
77
104
  end
78
105
  end
79
106
  end
@@ -14,8 +14,8 @@ module GoonModelGen
14
14
  base_package_path
15
15
  model_dir
16
16
  model_package_path
17
- validator_dir
18
- validator_package_path
17
+ validation_dir
18
+ validation_package_path
19
19
  store_dir
20
20
  store_package_path
21
21
  converter_dir
@@ -31,11 +31,13 @@ module GoonModelGen
31
31
  @gofmt_disabled ||= false
32
32
  @model_dir ||= "./model"
33
33
  @store_dir ||= "./stores"
34
+ @validation_dir ||= "./validation"
34
35
  @converter_dir ||= "./converters"
35
36
  @goa_gen_dir ||= "./gen"
36
37
  @base_package_path ||= default_go_package
37
38
  @model_package_path ||= join_paths(@base_package_path, @model_dir)
38
39
  @store_package_path ||= join_paths(@base_package_path, @store_dir)
40
+ @validation_package_path ||= join_paths(@base_package_path, @validation_dir)
39
41
  @converter_package_path ||= join_paths(@base_package_path, @converter_dir)
40
42
  @goa_gen_package_path ||= join_paths(@base_package_path, @goa_gen_dir)
41
43
  @structs_gen_dir ||= "./cmd/structs"
@@ -41,12 +41,15 @@ module GoonModelGen
41
41
  end
42
42
 
43
43
  content = execute(variables)
44
+ return unless content
44
45
 
45
46
  options = {skip: skip, force: force}
46
47
  thor.create_file(output_path, content, options)
47
48
  end
48
49
 
49
50
  def execute(variables = {})
51
+ return nil if file.sentences.empty?
52
+
50
53
  variables.each do |key, val|
51
54
  define_singleton_method(key){ val }
52
55
  end
@@ -57,6 +60,9 @@ module GoonModelGen
57
60
  # local variables used in tempaltes
58
61
  type = sentence.type
59
62
  package = type.package
63
+ type.memo.each do |key, val|
64
+ define_singleton_method(key){ val }
65
+ end
60
66
 
61
67
  erb = ERB.new(File.read(template_path), nil, "-")
62
68
  erb.filename = template_path
@@ -9,6 +9,7 @@ module GoonModelGen
9
9
  attr_reader :type
10
10
  attr_accessor :struct
11
11
  attr_accessor :prepare_method
12
+ attr_accessor :unique
12
13
 
13
14
  def initialize(name, type_name, tags, goon_id: false)
14
15
  @name, @type_name = name, type_name
@@ -1,5 +1,6 @@
1
1
  require "goon_model_gen"
2
2
 
3
+ require "goon_model_gen/golang/package"
3
4
  require "goon_model_gen/golang/modifier"
4
5
 
5
6
  require "active_support/core_ext/string"
@@ -25,6 +26,10 @@ module GoonModelGen
25
26
  self
26
27
  end
27
28
 
29
+ def new_package(path)
30
+ Package.new(path).tap{|pkg| add(pkg)}
31
+ end
32
+
28
33
  def detect_by(basename)
29
34
  detect{|pkg| pkg.basename == basename}
30
35
  end
@@ -12,8 +12,8 @@ module GoonModelGen
12
12
  @fields ||= []
13
13
  end
14
14
 
15
- # @param name [string]
16
- # @param t [Type]
15
+ # @param name [String]
16
+ # @param t [String]
17
17
  # @param tags [Hash<String,Array<String>>]
18
18
  def new_field(name, t, tags, options = {})
19
19
  Field.new(name, t, tags, options).tap do |f|
@@ -24,6 +24,11 @@ module GoonModelGen
24
24
  name
25
25
  end
26
26
  end
27
+
28
+ def memo
29
+ @memo ||= {}
30
+ end
31
+
27
32
  end
28
33
  end
29
34
  end
@@ -29,8 +29,7 @@ module GoonModelGen
29
29
  end
30
30
  r['json'] ||= [name.underscore]
31
31
  if required
32
- r['validate'] ||= []
33
- r['validate'] << 'required'
32
+ r['validate'] = ['required'] + (r['validate'] || [])
34
33
  else
35
34
  r['json'] << 'omitempty'
36
35
  end
@@ -28,6 +28,7 @@ module GoonModelGen
28
28
  def new_struct(name)
29
29
  Struct.new(name).tap do |s|
30
30
  s.context = self.context
31
+ s.file = self
31
32
  types.push(s)
32
33
  end
33
34
  end
@@ -48,7 +48,25 @@ module GoonModelGen
48
48
  else
49
49
  raise "Unsupported type definition named '#{name}': #{t.inspect}"
50
50
  end
51
- source_type.generators = t['generates']
51
+
52
+ source_type.generators =
53
+ case t['generates']
54
+ when false then Hash.new({}) # Return empty Hash not to generate any file
55
+ when nil, true then Hash.new(nil) # Fulfill by default methods
56
+ when Hash then
57
+ t['generates'].each_with_object({}) do |(k,v), d|
58
+ d[k] =
59
+ case v
60
+ when false then {}
61
+ when nil, true then nil
62
+ when Array then v.each_with_object({}){|i,d| d[i] = true}
63
+ when Hash then v
64
+ else raise "Invalid generates value in #{k.inspect}: #{v.inspect}"
65
+ end
66
+ end
67
+ when Array then t['generates'].each_with_object({}){|i,d| d[i] = true}
68
+ else raise "Invalid generates: #{t['generates'].inspect}"
69
+ end
52
70
  end
53
71
  end
54
72
 
@@ -8,7 +8,7 @@ module GoonModelGen
8
8
  include Contextual
9
9
 
10
10
  attr_reader :name
11
- attr_accessor :package
11
+ attr_accessor :file
12
12
  attr_accessor :generators # key: method_name, value: true|false|string(file_suffix)
13
13
 
14
14
  # @param name [string]
@@ -1,5 +1,5 @@
1
1
  var <%= type.name %>Map = map[<%= type.name %>]string{
2
2
  <%- type.map.each do |key, name| -%>
3
- <%= key.inspect %>: <%= name.inspect %>,
3
+ <%= name.camelize %>: <%= name.inspect %>,
4
4
  <%- end -%>
5
5
  }
@@ -0,0 +1,10 @@
1
+ <%-
2
+ import 'google.golang.org/appengine/datastore'
3
+ import model.package
4
+ -%>
5
+
6
+ type <%= type.name %>Binder interface {
7
+ Query(q *datastore.Query) *datastore.Query
8
+ Visible(m *<%= model.qualified_name %>) bool
9
+ Prepare(m *<%= model.qualified_name %>)
10
+ }
@@ -0,0 +1,10 @@
1
+ <%-
2
+ import 'context'
3
+ import model.package
4
+ -%>
5
+
6
+ type <%= type.name %>Hook interface {
7
+ AfterQuery(ctx context.Context, m *[]*<%= model.qualified_name %>) error
8
+ AfterGet(ctx context.Context, m *<%= model.qualified_name %>) error
9
+ BeforeValidation(ctx context.Context, m *<%= model.qualified_name %>) error
10
+ }
@@ -0,0 +1,4 @@
1
+ type <%= type.name %> struct {
2
+ Binder <%= type.name %>Binder
3
+ Hook <%= type.name %>Hook
4
+ }
@@ -0,0 +1,3 @@
1
+ func (s *<%= type.name %>) KindName() string {
2
+ return "<%= model.name %>"
3
+ }
@@ -0,0 +1,11 @@
1
+ <%-
2
+ import 'google.golang.org/appengine/datastore'
3
+ -%>
4
+
5
+ func (s *<%= type.name %>) Query() *datastore.Query {
6
+ q := datastore.NewQuery(s.KindName())
7
+ if s.Binder != nil {
8
+ q = s.Binder.Query(q)
9
+ }
10
+ return q
11
+ }
@@ -0,0 +1,10 @@
1
+ <%-
2
+ import 'context'
3
+ import 'google.golang.org/appengine/datastore'
4
+ import 'github.com/mjibson/goon'
5
+ -%>
6
+
7
+ func (s *<%= type.name %>) Run(ctx context.Context, q *datastore.Query) *goon.Iterator {
8
+ g := goon.FromContext(ctx)
9
+ return g.Run(q)
10
+ }
@@ -0,0 +1,8 @@
1
+ <%-
2
+ import 'context'
3
+ import model.package
4
+ -%>
5
+
6
+ func (s *<%= type.name %>) All(ctx context.Context) ([]*<%= model.qualified_name %>, error) {
7
+ return s.AllBy(ctx, s.Query())
8
+ }
@@ -0,0 +1,24 @@
1
+ <%-
2
+ import 'context'
3
+ import model.package
4
+ import 'google.golang.org/appengine/datastore'
5
+ import 'google.golang.org/appengine/log'
6
+ -%>
7
+
8
+ func (s *<%= type.name %>) AllBy(ctx context.Context, q *datastore.Query) ([]*<%= model.qualified_name %>, error) {
9
+ g := goon.FromContext(ctx)
10
+ r := []*<%= model.qualified_name %>{}
11
+ _, err := g.GetAll(q.EventualConsistency(), &r)
12
+ if err != nil {
13
+ log.Errorf(ctx, "Failed to AllBy <%= model.qualified_name %> because of %v\n", err)
14
+ return nil, err
15
+ }
16
+
17
+ if s.Hook != nil {
18
+ if err := s.Hook.AfterQuery(ctx, &r); err != nil {
19
+ return nil, err
20
+ }
21
+ }
22
+
23
+ return r, nil
24
+ }
@@ -0,0 +1,9 @@
1
+ <%-
2
+ import 'context'
3
+ import model.package
4
+ import 'google.golang.org/appengine/datastore'
5
+ -%>
6
+
7
+ func (s *<%= type.name %>) Select(ctx context.Context, q *datastore.Query) ([]*<%= model.qualified_name %>, error) {
8
+ return s.AllBy(ctx, q)
9
+ }
@@ -0,0 +1,17 @@
1
+ <%-
2
+ import 'context'
3
+ import model.package
4
+ import 'google.golang.org/appengine/datastore'
5
+ -%>
6
+
7
+ func (s *<%= type.name %>) FirstBy(ctx context.Context, q *datastore.Query) (*<%= model.qualified_name %>, error) {
8
+ r, err := s.AllBy(ctx, q.Limit(1))
9
+ if err != nil {
10
+ return nil, err
11
+ }
12
+ if len(r) > 0 {
13
+ return r[0], nil
14
+ } else {
15
+ return nil, nil
16
+ }
17
+ }
@@ -0,0 +1,16 @@
1
+ <%-
2
+ import 'context'
3
+ import 'google.golang.org/appengine/datastore'
4
+ import 'google.golang.org/appengine/log'
5
+ import 'github.com/mjibson/goon'
6
+ -%>
7
+
8
+ func (s *<%= type.name %>) CountBy(ctx context.Context, q *datastore.Query) (int, error) {
9
+ g := goon.FromContext(ctx)
10
+ c, err := g.Count(q)
11
+ if err != nil {
12
+ log.Errorf(ctx, "Failed to count <%= model.qualified_name %> with %v because of %v\n", q, err)
13
+ return 0, err
14
+ }
15
+ return c, nil
16
+ }
@@ -0,0 +1,20 @@
1
+ <%-
2
+ import 'context'
3
+ import model.package
4
+ -%>
5
+
6
+ func (s *<%= type.name %>) ByID(ctx context.Context, iD int64) (*<%= model.qualified_name %>, error) {
7
+ r := <%= model.qualified_name %>{ID: iD}
8
+ err := s.Get(ctx, &r)
9
+ if err != nil {
10
+ return nil, err
11
+ }
12
+
13
+ if s.Hook != nil {
14
+ if err := s.Hook.AfterGet(ctx, &r); err != nil {
15
+ return nil, err
16
+ }
17
+ }
18
+
19
+ return &r, nil
20
+ }
@@ -0,0 +1,15 @@
1
+ <%-
2
+ import 'context'
3
+ import model.package
4
+ import 'google.golang.org/appengine/datastore'
5
+ import 'google.golang.org/appengine/log'
6
+ -%>
7
+
8
+ func (s *<%= type.name %>) ByKey(ctx context.Context, key *datastore.Key) (*<%= model.qualified_name %>, error) {
9
+ if err := s.IsValidKey(ctx, key); err != nil {
10
+ log.Errorf(ctx, "<%= type.name %>.ByKey got Invalid key: %v because of %v\n", key, err)
11
+ return nil, err
12
+ }
13
+
14
+ return s.ByID(ctx, key.IntID())
15
+ }
@@ -0,0 +1,22 @@
1
+ <%-
2
+ import 'context'
3
+ import model.package
4
+ import 'google.golang.org/appengine/datastore'
5
+ import 'google.golang.org/appengine/log'
6
+ import 'github.com/mjibson/goon'
7
+ -%>
8
+
9
+ func (s *<%= type.name %>) Get(ctx context.Context, m *<%= model.qualified_name %>) error {
10
+ g := goon.FromContext(ctx)
11
+ err := g.Get(m)
12
+ if err != nil {
13
+ log.Errorf(ctx, "Failed to Get <%= model.qualified_name %> because of %v\n", err)
14
+ return err
15
+ }
16
+
17
+ if s.Binder != nil && !s.Binder.Visible(m) {
18
+ return datastore.ErrNoSuchEntity
19
+ }
20
+
21
+ return nil
22
+ }
@@ -0,0 +1,20 @@
1
+ <%-
2
+ import 'context'
3
+ import 'fmt'
4
+ import model.package
5
+ import 'google.golang.org/appengine/datastore'
6
+ import 'google.golang.org/appengine/log'
7
+ import 'github.com/mjibson/goon'
8
+ -%>
9
+
10
+ func (s *<%= type.name %>) IsValidKey(ctx context.Context, key *datastore.Key) error {
11
+ if key == nil {
12
+ return fmt.Errorf("key is nil")
13
+ }
14
+ g := goon.FromContext(ctx)
15
+ expected := g.Kind(&<%= model.qualified_name %>{})
16
+ if key.Kind() != expected {
17
+ return fmt.Errorf("key kind must be %s but was %s", expected, key.Kind())
18
+ }
19
+ return nil
20
+ }
@@ -0,0 +1,28 @@
1
+ <%-
2
+ import 'context'
3
+ import model.package
4
+ import 'google.golang.org/appengine/datastore'
5
+ import 'google.golang.org/appengine/log'
6
+ import 'github.com/mjibson/goon'
7
+ -%>
8
+
9
+ func (s *<%= type.name %>) Exist(ctx context.Context, m *<%= model.qualified_name %>) (bool, error) {
10
+ if m.ID == 0 {
11
+ return false, nil
12
+ }
13
+ g := goon.FromContext(ctx)
14
+ key, err := g.KeyError(m)
15
+ if err != nil {
16
+ log.Errorf(ctx, "Failed to Get Key of %v because of %v\n", m, err)
17
+ return false, err
18
+ }
19
+ _, err = s.ByKey(ctx, key)
20
+ if err == datastore.ErrNoSuchEntity {
21
+ return false, nil
22
+ } else if err != nil {
23
+ log.Errorf(ctx, "Failed to get existance of %v because of %v\n", m, err)
24
+ return false, err
25
+ } else {
26
+ return true, nil
27
+ }
28
+ }
@@ -0,0 +1,24 @@
1
+ <%-
2
+ import 'context'
3
+ import 'fmt'
4
+ import model.package
5
+ import 'google.golang.org/appengine/datastore'
6
+ import 'google.golang.org/appengine/log'
7
+ -%>
8
+
9
+ func (s *<%= type.name %>) Create(ctx context.Context, m *<%= model.qualified_name %>) (*datastore.Key, error) {
10
+ if err := m.PrepareToCreate(); err != nil {
11
+ return nil, err
12
+ }
13
+ return s.PutWith(ctx, m, func() error {
14
+ exist, err := s.Exist(ctx, m)
15
+ if err != nil {
16
+ return err
17
+ }
18
+ if exist {
19
+ log.Errorf(ctx, "Failed to create %v because of another entity has same key\n", m)
20
+ return fmt.Errorf("Duplicate ID error: %q of %v\n", m.ID, m)
21
+ }
22
+ return nil
23
+ })
24
+ }
@@ -0,0 +1,24 @@
1
+ <%-
2
+ import 'context'
3
+ import 'fmt'
4
+ import model.package
5
+ import 'google.golang.org/appengine/datastore'
6
+ import 'google.golang.org/appengine/log'
7
+ -%>
8
+
9
+ func (s *<%= type.name %>) Update(ctx context.Context, m *<%= model.qualified_name %>) (*datastore.Key, error) {
10
+ if err := m.PrepareToUpdate(); err != nil {
11
+ return nil, err
12
+ }
13
+ return s.PutWith(ctx, m, func() error {
14
+ exist, err := s.Exist(ctx, m)
15
+ if err != nil {
16
+ return err
17
+ }
18
+ if !exist {
19
+ log.Errorf(ctx, "Failed to update %v because it doesn't exist\n", m)
20
+ return fmt.Errorf("No data to update %q of %v\n", m.ID, m)
21
+ }
22
+ return nil
23
+ })
24
+ }
@@ -0,0 +1,28 @@
1
+ <%-
2
+ import 'context'
3
+ import model.package
4
+ import 'google.golang.org/appengine/datastore'
5
+ -%>
6
+
7
+ func (s *<%= type.name %>) PutWith(ctx context.Context, m *<%= model.qualified_name %>, f func() error) (*datastore.Key, error) {
8
+ if s.Binder != nil {
9
+ s.Binder.Prepare(m)
10
+ }
11
+
12
+ if s.Hook != nil {
13
+ if err := s.Hook.BeforeValidation(ctx, m); err != nil {
14
+ return nil, err
15
+ }
16
+ }
17
+
18
+ if err := s.Validate(ctx, m); err != nil {
19
+ return nil, err
20
+ }
21
+ if f != nil {
22
+ if err := f(); err != nil {
23
+ return nil, err
24
+ }
25
+ }
26
+
27
+ return s.Put(ctx, m)
28
+ }
@@ -0,0 +1,17 @@
1
+ <%-
2
+ import 'context'
3
+ import model.package
4
+ import 'google.golang.org/appengine/datastore'
5
+ import 'google.golang.org/appengine/log'
6
+ import 'github.com/mjibson/goon'
7
+ -%>
8
+
9
+ func (s *<%= type.name %>) Put(ctx context.Context, m *<%= model.qualified_name %>) (*datastore.Key, error) {
10
+ g := goon.FromContext(ctx)
11
+ key, err := g.Put(m)
12
+ if err != nil {
13
+ log.Errorf(ctx, "Failed to Put %v because of %v\n", m, err)
14
+ return nil, err
15
+ }
16
+ return key, nil
17
+ }
@@ -0,0 +1,20 @@
1
+ <%-
2
+ import 'context'
3
+ import model.package
4
+ import 'google.golang.org/appengine/log'
5
+ import 'github.com/mjibson/goon'
6
+ -%>
7
+
8
+ func (s *<%= type.name %>) Delete(ctx context.Context, m *<%= model.qualified_name %>) error {
9
+ g := goon.FromContext(ctx)
10
+ key, err := g.KeyError(m)
11
+ if err != nil {
12
+ log.Errorf(ctx, "Failed to Get key of %v because of %v\n", m, err)
13
+ return err
14
+ }
15
+ if err := g.Delete(key); err != nil {
16
+ log.Errorf(ctx, "Failed to Delete %v because of %v\n", m, err)
17
+ return err
18
+ }
19
+ return nil
20
+ }
@@ -0,0 +1,35 @@
1
+ <%-
2
+ import 'context'
3
+ import 'fmt'
4
+ import model.package
5
+
6
+ validation_error = packages.type_for('ValidationError')
7
+ raise "ValidationError not found" unless validation_error
8
+ import validation_error.package
9
+ -%>
10
+
11
+ func (s *<%= type.name %>) ValidateUniqueness(ctx context.Context, m *<%= model.qualified_name %>) error {
12
+ conditions := map[string]interface{}{
13
+ <%- model.fields.select(&:unique).each do |field| -%>
14
+ "<%= field.name %>": m.<%= field.name %>,
15
+ <%- end -%>
16
+ }
17
+ for field, value := range conditions {
18
+ q := s.Query().Filter(field+" =", value)
19
+ c, err := s.CountBy(ctx, q)
20
+ if err != nil {
21
+ return err
22
+ }
23
+ b := 0
24
+ if m.IsPersisted() {
25
+ b = 1
26
+ }
27
+ if c > b {
28
+ return &<%= validation_error.qualified_name %>{
29
+ Field: field,
30
+ Message: fmt.Sprintf("%v has already been taken", value),
31
+ }
32
+ }
33
+ }
34
+ return nil
35
+ }
@@ -0,0 +1,14 @@
1
+ <%-
2
+ import 'context'
3
+ import model.package
4
+ -%>
5
+
6
+ func (s *<%= type.name %>) Validate(ctx context.Context, m *<%= model.qualified_name %>) error {
7
+ if err := m.Validate(ctx); err != nil {
8
+ return err
9
+ }
10
+ if err := s.ValidateUniqueness(ctx, m); err != nil {
11
+ return err
12
+ }
13
+ return nil
14
+ }
@@ -0,0 +1,4 @@
1
+ type <%= type.name %> struct {
2
+ Field string
3
+ Message string
4
+ }
@@ -0,0 +1,4 @@
1
+ <%- import 'fmt' -%>
2
+ func (err *<%= type.name %>) Error() string {
3
+ return fmt.Sprintf("Invalid %s: %s", err.Field, err.Message)
4
+ }
@@ -1,3 +1,3 @@
1
1
  module GoonModelGen
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.2"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: goon_model_gen
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - akm
@@ -143,6 +143,10 @@ files:
143
143
  - exe/goon_model_gen
144
144
  - goon_model_gen.gemspec
145
145
  - lib/goon_model_gen.rb
146
+ - lib/goon_model_gen/builder/abstract_builder.rb
147
+ - lib/goon_model_gen/builder/model_builder.rb
148
+ - lib/goon_model_gen/builder/store_builder.rb
149
+ - lib/goon_model_gen/builder/validation_builder.rb
146
150
  - lib/goon_model_gen/cli.rb
147
151
  - lib/goon_model_gen/config.rb
148
152
  - lib/goon_model_gen/generator.rb
@@ -160,7 +164,6 @@ files:
160
164
  - lib/goon_model_gen/golang/sentence.rb
161
165
  - lib/goon_model_gen/golang/struct.rb
162
166
  - lib/goon_model_gen/golang/type.rb
163
- - lib/goon_model_gen/model_builder.rb
164
167
  - lib/goon_model_gen/source/context.rb
165
168
  - lib/goon_model_gen/source/contextual.rb
166
169
  - lib/goon_model_gen/source/enum.rb
@@ -187,6 +190,31 @@ files:
187
190
  - lib/goon_model_gen/templates/model/goon/06_IsPersisted.go.erb
188
191
  - lib/goon_model_gen/templates/model/slice/01_base.go.erb
189
192
  - lib/goon_model_gen/templates/model/struct/01_struct.go.erb
193
+ - lib/goon_model_gen/templates/store/goon/01_Binder.go.erb
194
+ - lib/goon_model_gen/templates/store/goon/02_Hook.go.erb
195
+ - lib/goon_model_gen/templates/store/goon/03_struct.go.erb
196
+ - lib/goon_model_gen/templates/store/goon/04_KindName.go.erb
197
+ - lib/goon_model_gen/templates/store/goon/05_Query.go.erb
198
+ - lib/goon_model_gen/templates/store/goon/06_Run.go.erb
199
+ - lib/goon_model_gen/templates/store/goon/07_All.go.erb
200
+ - lib/goon_model_gen/templates/store/goon/08_AllBy.go.erb
201
+ - lib/goon_model_gen/templates/store/goon/09_Select.go.erb
202
+ - lib/goon_model_gen/templates/store/goon/10_FirstBy.go.erb
203
+ - lib/goon_model_gen/templates/store/goon/11_CountBy.go.erb
204
+ - lib/goon_model_gen/templates/store/goon/12_ByID.go.erb
205
+ - lib/goon_model_gen/templates/store/goon/13_ByKey.go.erb
206
+ - lib/goon_model_gen/templates/store/goon/14_Get.go.erb
207
+ - lib/goon_model_gen/templates/store/goon/15_IsValidKey.go.erb
208
+ - lib/goon_model_gen/templates/store/goon/16_Exist.go.erb
209
+ - lib/goon_model_gen/templates/store/goon/17_Create.go.erb
210
+ - lib/goon_model_gen/templates/store/goon/18_Update.go.erb
211
+ - lib/goon_model_gen/templates/store/goon/19_PutWith.go.erb
212
+ - lib/goon_model_gen/templates/store/goon/20_Put.go.erb
213
+ - lib/goon_model_gen/templates/store/goon/21_Delete.go.erb
214
+ - lib/goon_model_gen/templates/store/goon/22_ValidateUniqueness.go.erb
215
+ - lib/goon_model_gen/templates/store/goon/23_Validate.go.erb
216
+ - lib/goon_model_gen/templates/validation/error/01_struct.go.erb
217
+ - lib/goon_model_gen/templates/validation/error/02_Error.go.erb
190
218
  - lib/goon_model_gen/version.rb
191
219
  homepage: https://github.com/akm/goon_model_gen
192
220
  licenses:
@@ -1,137 +0,0 @@
1
- require "goon_model_gen"
2
-
3
- require "goon_model_gen/source/context"
4
- require "goon_model_gen/source/struct"
5
- require "goon_model_gen/source/enum"
6
- require "goon_model_gen/source/named_slice"
7
-
8
-
9
- require "goon_model_gen/golang/package"
10
- require "goon_model_gen/golang/packages"
11
- require "goon_model_gen/golang/datastore_supported"
12
-
13
- require "active_support/core_ext/string"
14
-
15
- module GoonModelGen
16
- class ModelBuilder
17
- attr_reader :base_package_path
18
-
19
- def initialize(base_package_path)
20
- @base_package_path = base_package_path
21
- end
22
-
23
-
24
- # @param context [Source::Context]
25
- # @return [Golang::Packages]
26
- def build(context)
27
- Golang::Packages.new.tap do |r|
28
- build_sentences = []
29
- context.files.each do |f|
30
- package_path = File.join(base_package_path, f.basename)
31
- pkg, procs = build_package(package_path, f.types)
32
- r << pkg
33
- build_sentences.concat(procs)
34
- end
35
- r.resolve_type_names(Golang::DatastoreSupported.packages)
36
- build_sentences.each(&:call)
37
- end
38
- end
39
-
40
- # @param package_path [String]
41
- # @param types [Array<Source::Type>]
42
- # @return [Golang::Package, Array<Proc>]
43
- def build_package(package_path, types)
44
- procs = []
45
- pkg = Golang::Package.new(package_path).tap do |pkg|
46
- types.each do |t|
47
- case t
48
- when Source::Struct then
49
- go_type = build_struct(t, pkg)
50
- template = (t.id_name && t.id_type) ? "model/goon" : "model/struct"
51
- procs << Proc.new{ build_sentences(template, t, go_type) }
52
- when Source::Enum then
53
- go_type = pkg.new_enum(t.name, t.base_type, t.map)
54
- procs << Proc.new{ build_sentences("model/enum", t, go_type) }
55
- when Source::NamedSlice then
56
- go_type = pkg.new_named_slice(t.name, t.base_type_name)
57
- procs << Proc.new{ build_sentences("model/slice", t, go_type) }
58
- else
59
- raise "Unsupported type #{t.class.name} #{t.inspect}"
60
- end
61
- end
62
- end
63
- return pkg, procs
64
- end
65
-
66
- # @param t [Source::Struct]
67
- # @param pkg [Golang::Package]
68
- # @return [Golang::Struct]
69
- def build_struct(t, pkg)
70
- pkg.new_struct(t.name).tap do |s|
71
- s.ref_name = t.ref_name
72
- if t.id_name && t.id_type
73
- tags = {
74
- 'goon' => ['id'],
75
- 'datastore' => ['-'],
76
- 'json' => [t.id_name.underscore],
77
- }
78
- s.new_field(t.id_name, t.id_type, tags, goon_id: true)
79
- end
80
- t.fields.each do |f|
81
- s.new_field(f.name, f.type_name, f.build_tags)
82
- end
83
- end
84
- end
85
-
86
-
87
- # @param template_base [string]
88
- # @param t [Source::Struct]
89
- # @param go_type [Golang::Type]
90
- def build_sentences(template_base, t, go_type)
91
- m2t = method_to_template_for(template_base)
92
- t.generators ||= default_generators_for(template_base)
93
- t.generators.each do |name, suffix|
94
- next if !suffix
95
- template = m2t[name]
96
- parts = [t.name.underscore]
97
- custom_suffix = false
98
- if suffix.is_a?(String)
99
- parts << suffix
100
- custom_suffix = true
101
- end
102
- filename = parts.join('_') << '.go'
103
- go_type.package.find_or_new_file(filename).tap do |file|
104
- file.custom_suffix = custom_suffix
105
- file.new_sentence(File.join(template_base, template), go_type)
106
- end
107
- end
108
- end
109
-
110
- def default_generators_for(template_base)
111
- method_to_template_for(template_base).keys.
112
- each_with_object({}){|name, d| d[name] = true }
113
- end
114
-
115
- def method_to_template_map
116
- @method_to_template_map ||= {}
117
- end
118
-
119
- def method_to_template_for(template_base)
120
- method_to_template_map[template_base] ||=
121
- begin
122
- templates_for(template_base).each_with_object({}) do |filename, d|
123
- m = filename.sub(/\A\d+\_/, '').sub(/\.go\.erb\z/, '')
124
- d[m] = filename
125
- end
126
- end
127
- end
128
-
129
- def templates_for(template_base)
130
- base_dir = File.join(File.expand_path('../templates', __FILE__), template_base)
131
- Dir.chdir(base_dir) do
132
- Dir.glob('*.go.erb')
133
- end
134
- end
135
-
136
- end
137
- end