betterplace-bi 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.semaphore/semaphore.yml +26 -0
  4. data/.tool-versions +2 -0
  5. data/.utilsrc +26 -0
  6. data/Gemfile +5 -0
  7. data/README.md +76 -0
  8. data/Rakefile +37 -0
  9. data/VERSION +1 -0
  10. data/betterplace-bi.gemspec +39 -0
  11. data/lib/betterplace-bi.rb +1 -0
  12. data/lib/bi/ab_test_helper.rb +81 -0
  13. data/lib/bi/api.rb +115 -0
  14. data/lib/bi/commands/base.rb +11 -0
  15. data/lib/bi/commands/collector.rb +32 -0
  16. data/lib/bi/commands/connection.rb +25 -0
  17. data/lib/bi/commands/delete.rb +33 -0
  18. data/lib/bi/commands/serializer.rb +40 -0
  19. data/lib/bi/commands/update.rb +29 -0
  20. data/lib/bi/commands.rb +10 -0
  21. data/lib/bi/commands_job.rb +24 -0
  22. data/lib/bi/event.rb +52 -0
  23. data/lib/bi/planning_value_parser.rb +100 -0
  24. data/lib/bi/planning_value_validations.rb +15 -0
  25. data/lib/bi/railtie.rb +13 -0
  26. data/lib/bi/request_analyzer.rb +64 -0
  27. data/lib/bi/session_id.rb +11 -0
  28. data/lib/bi/shared_value.rb +102 -0
  29. data/lib/bi/tracking.rb +28 -0
  30. data/lib/bi/type_generator.rb +79 -0
  31. data/lib/bi/update_error.rb +4 -0
  32. data/lib/bi/updater.rb +61 -0
  33. data/lib/bi/version.rb +8 -0
  34. data/lib/bi.rb +27 -0
  35. data/lib/tasks/bime.rake +55 -0
  36. data/spec/bi/ab_test_helper_spec.rb +145 -0
  37. data/spec/bi/commands/collector_spec.rb +26 -0
  38. data/spec/bi/commands/connection_spec.rb +15 -0
  39. data/spec/bi/commands_job_spec.rb +24 -0
  40. data/spec/bi/commands_spec.rb +46 -0
  41. data/spec/bi/event_spec.rb +77 -0
  42. data/spec/bi/planning_value_parser_spec.rb +94 -0
  43. data/spec/bi/request_analyzer_spec.rb +75 -0
  44. data/spec/bi/shared_value_spec.rb +47 -0
  45. data/spec/bi/tracking_spec.rb +37 -0
  46. data/spec/bi/type_generator_spec.rb +44 -0
  47. data/spec/bi/updater_spec.rb +61 -0
  48. data/spec/bime_dir/.keep +0 -0
  49. data/spec/config/bi.yml +18 -0
  50. data/spec/spec_helper.rb +31 -0
  51. data/spec/support/models.rb +106 -0
  52. metadata +331 -0
@@ -0,0 +1,145 @@
1
+ require 'spec_helper'
2
+
3
+ describe BI::ABTestHelper do
4
+ before do
5
+ allow(Rails).to receive(:logger).and_return(double('logger').as_null_object)
6
+ end
7
+
8
+ let :helper do
9
+ double('helper').extend described_class
10
+ end
11
+
12
+ let :session do
13
+ double(id: 'deadbeef' * 5, loaded?: true)
14
+ end
15
+
16
+ let :request do
17
+ double(session: session, headers: {}, params: {}, user_agent: nil)
18
+ end
19
+
20
+ let :alternatives do
21
+ %w[ alt1 alt2 alt3 ]
22
+ end
23
+
24
+ describe '#ab_test' do
25
+ it 'can be overriden' do
26
+ allow(helper).to receive(:ab_test_override?).and_return 'alt2'
27
+ expect(helper.ab_test('foo', alternatives, request: request)).to eq 'alt2'
28
+ end
29
+
30
+ it 'can ignore certain users' do
31
+ expect(helper).to receive(:ab_test_ignore_user?).and_return true
32
+ expect(helper.ab_test('foo', alternatives, request: request)).to eq 'alt1'
33
+ end
34
+
35
+ it 'triggers loading of session unless loaded' do
36
+ unloaded_session = double(id: 'deadbeef' * 5, loaded?: false)
37
+ expect(unloaded_session).to receive(:load!)
38
+ allow(request).to receive(:session).and_return unloaded_session
39
+ expect(helper.ab_test('foo', alternatives, request: request)).to eq 'alt2'
40
+ end
41
+
42
+ it 'can choose alternatives based on session id' do
43
+ allow(helper).to receive(:session).and_return session
44
+ expect(helper.ab_test('foo', alternatives, request: request)).to eq 'alt2'
45
+ end
46
+
47
+ it 'does not default even without session_id' do
48
+ allow(request.session).to receive(:id)
49
+ allow(helper).to receive(:rand).and_return(666)
50
+ expect(helper.ab_test('foo', alternatives, request: request)).to eq 'alt1'
51
+ allow(helper).to receive(:rand).and_return(667)
52
+ expect(helper.ab_test('foo', alternatives, request: request)).to eq 'alt2'
53
+ end
54
+
55
+ it 'does not default even without session' do
56
+ allow(request).to receive(:session)
57
+ allow(helper).to receive(:rand).and_return(666)
58
+ expect(helper.ab_test('foo', alternatives, request: request)).to eq 'alt1'
59
+ allow(helper).to receive(:rand).and_return(667)
60
+ expect(helper.ab_test('foo', alternatives, request: request)).to eq 'alt2'
61
+ end
62
+
63
+ it 'can be called with block' do
64
+ allow(helper).to receive(:session).and_return session
65
+ chosen = nil
66
+ expect(helper.ab_test('foo', *alternatives, request: request) {
67
+ |choice| chosen = choice; :result
68
+ }).to eq :result
69
+ expect(chosen).to eq 'alt2'
70
+ end
71
+ end
72
+
73
+ describe '#ab_test_ignore_user?' do
74
+ it 'does not ignore users by default' do
75
+ expect(helper).not_to be_ab_test_ignore_user(request: request)
76
+ end
77
+
78
+ it 'does ignore some users' do
79
+ allow_any_instance_of(BI::RequestAnalyzer).to receive(:ignore?).and_return true
80
+ expect(helper).to be_ab_test_ignore_user(request: request)
81
+ end
82
+ end
83
+
84
+ describe '#ab_test_override?' do
85
+ it 'does not override by default' do
86
+ expect(helper).not_to be_ab_test_override('foo', alternatives, request: request)
87
+ end
88
+
89
+ it 'can be used to choose alternatives for all ab tests' do
90
+ allow(request).to receive(:params).and_return({
91
+ 'ab_test' => 'alternative'
92
+ })
93
+ expect(helper.ab_test_override?('foo', alternatives, request: request)).to eq 'alt2'
94
+ end
95
+
96
+ it 'can be used to choose alternatives for all ab tests with specific name' do
97
+ allow(request).to receive(:params).and_return({
98
+ 'ab_test' => 'alt3'
99
+ })
100
+ expect(helper.ab_test_override?('foo', alternatives, request: request)).to eq 'alt3'
101
+ end
102
+
103
+ it 'can be used to choose alternatives for a specific ab test' do
104
+ allow(request).to receive(:params).and_return({
105
+ 'ab_test' => { 'foo' => 'alternative' },
106
+ })
107
+ expect(helper.ab_test_override?('foo', alternatives, request: request)).to eq 'alt2'
108
+ expect(helper.ab_test_override?('bar', alternatives, request: request)).not_to eq 'alt2'
109
+ end
110
+
111
+ it 'can be used to choose alternatives with specific name' do
112
+ allow(request).to receive(:params).and_return({
113
+ 'ab_test' => { 'foo' => 'alt3' },
114
+ })
115
+ expect(helper.ab_test_override?('foo', alternatives, request: request)).to eq 'alt3'
116
+ expect(helper.ab_test_override?('bar', alternatives, request: request)).not_to eq 'alt3'
117
+ end
118
+ end
119
+
120
+ describe '#ab_test_override_alternative' do
121
+ it 'can choose the control' do
122
+ expect(helper.ab_test_override_alternative('control', alternatives, request: request)).to\
123
+ eq 'alt1'
124
+ end
125
+
126
+ it 'can choose the first alternative' do
127
+ expect(helper.ab_test_override_alternative('alternative', alternatives, request: request)).to\
128
+ eq 'alt2'
129
+ end
130
+
131
+ it 'can choose the nth alternative, starting to count from 0' do
132
+ expect(helper.ab_test_override_alternative('1', alternatives, request: request)).to\
133
+ eq 'alt2'
134
+ end
135
+
136
+ it 'defaults to control if there is no nth alternative' do
137
+ expect(helper.ab_test_override_alternative('42', alternatives, request: request)).to\
138
+ eq 'alt1'
139
+ end
140
+
141
+ it 'defaults to nil in any other case' do
142
+ expect(helper.ab_test_override_alternative('nix', alternatives, request)).to be_nil
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe BI::Commands::Collector do
4
+ let :collector do
5
+ described_class.new
6
+ end
7
+
8
+ it 'can check if job should be scheduled now' do
9
+ object = double(destroyed?: false)
10
+ expect(collector).not_to be_schedule_job(object)
11
+ collector.add(object, double.as_null_object)
12
+ expect(collector).to be_schedule_job(object)
13
+ end
14
+
15
+ it 'can add Update commands' do
16
+ object = double(destroyed?: false, id: 666)
17
+ expect(BI::Commands::Update).to receive(:new).and_call_original
18
+ collector.add(object, double.as_null_object)
19
+ end
20
+
21
+ it 'can add Delete commands' do
22
+ object = double(destroyed?: true, id: 666)
23
+ expect(BI::Commands::Delete).to receive(:new).and_call_original
24
+ collector.add(object, double.as_null_object)
25
+ end
26
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ describe BI::Commands::Connection do
4
+ describe '#connect_to_server' do
5
+ it 'creates one connection' do
6
+ expect(described_class).to receive(:create_connection).once.and_return double.as_null_object
7
+ connection = nil
8
+ described_class.connect_to_server do |c|
9
+ connection = c
10
+ expect(connection).to receive(:reset)
11
+ end
12
+ expect(connection).not_to be_nil
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ describe BI::CommandsJob do
4
+ let :job do
5
+ described_class.new
6
+ end
7
+
8
+ it 'connects to server for commands' do
9
+ expect(job).to receive(:connect_to_server)
10
+ job.perform :something
11
+ end
12
+
13
+ it 'does not connect to server without commands' do
14
+ expect(job).not_to receive(:connect_to_server)
15
+ job.perform
16
+ end
17
+
18
+ it 'performs all given commands on server' do
19
+ command = double
20
+ expect(command).to receive(:perform_via)
21
+ allow(job).to receive(:create_connection).and_return(double.as_null_object)
22
+ job.perform command
23
+ end
24
+ end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+
3
+ describe BI::Commands do
4
+ before do
5
+ allow(Log.instance).to receive(:info)
6
+ end
7
+
8
+ let :object do
9
+ double
10
+ end
11
+
12
+ let :connection do
13
+ double
14
+ end
15
+
16
+ context BI::Commands::Update do
17
+ let :command do
18
+ described_class.new(value: object)
19
+ end
20
+
21
+ it 'can be configured' do
22
+ expect(command.value).to eq object
23
+ end
24
+
25
+ it 'can be performed' do
26
+ allow(object).to receive(:url)
27
+ expect(connection).to receive(:post).and_return double(status: 200)
28
+ command.perform_via(connection)
29
+ end
30
+ end
31
+
32
+ context BI::Commands::Delete do
33
+ let :command do
34
+ described_class.new(url: object)
35
+ end
36
+
37
+ it 'can be configured' do
38
+ expect(command.url).to eq object
39
+ end
40
+
41
+ it 'can be performed' do
42
+ expect(connection).to receive(:delete).and_return double(status: 200)
43
+ command.perform_via(connection)
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,77 @@
1
+ require 'spec_helper'
2
+
3
+ describe BI::Event do
4
+ before do
5
+ allow(Rails).to receive(:logger).and_return(double('logger').as_null_object)
6
+ end
7
+
8
+ class ABEvent
9
+ class << self
10
+ def serialize(*)
11
+ end
12
+
13
+ def create!(*)
14
+ new
15
+ end
16
+ end
17
+
18
+ def attributes
19
+ {}
20
+ end
21
+
22
+ include BI::Tracking
23
+ end
24
+
25
+ let :session_id do
26
+ SecureRandom.hex(32)
27
+ end
28
+
29
+ let :session do
30
+ double('session', loaded?: true, id: session_id)
31
+ end
32
+
33
+ subject do
34
+ described_class.new
35
+ end
36
+
37
+ it 'offers static write method' do
38
+ args = { channel: 'default', name: 'hello', version: 'world', session: session }
39
+ expect(ABEvent).to receive(:create!).with(tracking: { session: session_id } | args).and_call_original
40
+ described_class.write(**args)
41
+ end
42
+
43
+ it 'can handle sessions with string id' do
44
+ args = { channel: 'default', name: 'hello', version: 'world', session: session_id }
45
+ expect(ABEvent).to receive(:create!).with(tracking: args).and_call_original
46
+ described_class.write(**args)
47
+ end
48
+
49
+ it 'ignores unexpected session objects' do
50
+ args = { channel: 'default', name: 'hello', version: 'world', session: Object.new }
51
+ expect(ABEvent).to receive(:create!).with(tracking: { session: nil } | args).and_call_original
52
+ described_class.write(**args)
53
+ end
54
+
55
+ it 'logs any errors during writing and raises again' do
56
+ error = StandardError.new
57
+ allow(ABEvent).to receive(:create!).and_raise error
58
+ expect(Log).to receive(:error).with(error, notify: true, meta: { module: 'bi' })
59
+ expect {
60
+ subject.write(channel: 'default', name: 'hello', version: 'world', session: session)
61
+ }.to raise_error error
62
+ end
63
+
64
+ it 'calls write method on configured event_class' do
65
+ event_data_input = {
66
+ channel: 'default', name: 'hello', version: 'world', session: session,
67
+ my: :data
68
+ }
69
+ event_data_output = {
70
+ channel: 'default', name: 'hello', version: 'world', session: session.id,
71
+ my: :data
72
+ }
73
+ expect(ABEvent).to receive(:create!).with(tracking: event_data_output).and_call_original
74
+ expect(Log).to receive(:info)
75
+ subject.write(**event_data_input)
76
+ end
77
+ end
@@ -0,0 +1,94 @@
1
+ require 'spec_helper'
2
+
3
+ describe BI::PlanningValueParser do
4
+ let :csv do
5
+ <<~end
6
+ product_tracking;amount_in_cents;yearmonth;data_type;data_version
7
+ foo;66600;2019-01;Foo;2018-06
8
+ bar;2300;2019-01;Bar;2018-06
9
+ end
10
+ end
11
+
12
+ let :instance do
13
+ described_class.parse(csv, class_name: 'TestPlanning')
14
+ end
15
+
16
+ context 'correct headers' do
17
+ it 'parses' do
18
+ expect(instance.first).to be_a TestPlanning
19
+ end
20
+ end
21
+
22
+ context 'invalid headers' do
23
+ let :csv do
24
+ <<~end
25
+ product_tracking;amount;yearmonth;data_type;data_version
26
+ foo;66600;2019-01;Foo;2018-06
27
+ end
28
+ end
29
+
30
+ it 'raises ParserError' do
31
+ expect(instance.errors).to eq(
32
+ 2 => 'headers need to be ["amount_in_cents", "data_type", "data_version", "product_tracking", "yearmonth"]',
33
+ )
34
+ end
35
+
36
+ it 'is not valid' do
37
+ expect(instance).to_not be_valid
38
+ end
39
+ end
40
+
41
+ context 'invalid #values' do
42
+ let :csv do
43
+ <<~end
44
+ product_tracking;amount;yearmonth;data_type;data_version
45
+ foo;66600;2019-01;Foo;2018-06;nope
46
+ end
47
+ end
48
+
49
+ it 'raises ParserError' do
50
+ expect(instance.errors).to eq(
51
+ 2 => '#values has to match #headers = 5'
52
+ )
53
+ end
54
+
55
+ it 'is not valid' do
56
+ expect(instance).to_not be_valid
57
+ end
58
+ end
59
+
60
+ context 'correct values' do
61
+ it 'parses' do
62
+ expect(instance.count).to eq 2
63
+ end
64
+ end
65
+
66
+ context 'incorrect values' do
67
+ let :csv do
68
+ <<~end
69
+ product_tracking;amount_in_cents;yearmonth;data_type;data_version
70
+ foo;66600;2019-13;Foo;2018-06
71
+ end
72
+ end
73
+
74
+ let :errors do
75
+ { 2 => [ "yearmonth: is invalid" ] }
76
+ end
77
+
78
+ before do
79
+ allow_any_instance_of(TestPlanning).to\
80
+ receive(:errors).and_return(errors)
81
+ allow(errors).to receive(:messages).and_return errors
82
+ end
83
+
84
+ it 'is not valid' do
85
+ expect(instance).to_not be_valid
86
+ end
87
+
88
+ it 'gives errorrs' do
89
+ expect(instance.errors).to eq(
90
+ 2 => "2: yearmonth: is invalid",
91
+ )
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,75 @@
1
+ require 'spec_helper'
2
+
3
+ describe BI::RequestAnalyzer do
4
+ before do
5
+ described_class.mize_cache_clear
6
+ end
7
+
8
+ let :request do
9
+ double(
10
+ session: double,
11
+ user_agent: 'Agent Smith',
12
+ headers: {},
13
+ )
14
+ end
15
+
16
+ subject do
17
+ described_class.new(request)
18
+ end
19
+
20
+ it 'can figure out user_agent' do
21
+ expect(subject.user_agent).to eq 'Agent Smith'
22
+ end
23
+
24
+ it 'can ignore or not' do
25
+ expect(subject).not_to be_ignore
26
+ allow(subject).to receive(:preview?).and_return true
27
+ expect(subject).to be_ignore
28
+ allow(subject).to receive(:robot?).and_return true
29
+ expect(subject).to be_ignore
30
+ end
31
+
32
+ it 'can figure out if request is a preview' do
33
+ request.headers['x-purpose'] = 'preview'
34
+ expect(subject).to be_preview
35
+ end
36
+
37
+ context 'mobile' do
38
+ it 'attempts to categorize mobile devices' do
39
+ allow(subject).to receive(:user_agent_configuration).and_return\
40
+ double(mobile?: %w[ Foo Mobile Baz ].map { |x| [x] * 2 }.to_h)
41
+ allow(request).to receive(:user_agent).and_return\
42
+ 'Mozilla/5.0 (Linux; Android 6.0.1; SM-G920V Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Mobile Safari/537.36'
43
+ expect(subject).to be_mobile
44
+ expect(subject.device_type).to eq :mobile
45
+ end
46
+
47
+ it 'attempts to categorize desktop devices' do
48
+ allow(request).to receive(:user_agent).and_return\
49
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.246'
50
+ expect(subject).not_to be_mobile
51
+ expect(subject.device_type).to eq :desktop
52
+ end
53
+ end
54
+
55
+ context 'robot' do
56
+ before do
57
+ allow(subject).to receive(:user_agent_configuration).and_return\
58
+ double(mobile?: nil, robot?: %w[ Foo Slurp Baz ].map { |x| [x] * 2 }.to_h)
59
+ end
60
+
61
+ it 'attempts to categorize non robots' do
62
+ allow(request).to receive(:user_agent).and_return\
63
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/601.3.9 (KHTML, like Gecko) Version/9.0.2 Safari/601.3.9'
64
+ expect(subject).not_to be_robot
65
+ expect(subject.device_type).to eq :desktop
66
+ end
67
+
68
+ it 'attempts to categorize robots' do
69
+ allow(request).to receive(:user_agent).and_return\
70
+ 'Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp)'
71
+ expect(subject).to be_robot
72
+ expect(subject.device_type).to eq :bot
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+
3
+ describe BI::SharedValue do
4
+ let :test_value do
5
+ BI::TestModelValue.new('foo')
6
+ end
7
+
8
+ it 'can warp a model' do
9
+ tv = BI::TestModelValue.new(TestModel.new('foo'))
10
+ expect(tv).to be_a described_class
11
+ expect(tv.id).to eq 'foo'
12
+ end
13
+
14
+ it 'can be build for a model with globalid' do
15
+ tv = BI::TestModelValue.find('foo')
16
+ expect(tv).to be_a described_class
17
+ expect(tv.id).to eq 'foo'
18
+ end
19
+
20
+ it 'can intialize for a model found via globalid' do
21
+ tv = BI::TestModelValue.new('foo')
22
+ expect(tv).to be_a described_class
23
+ expect(tv.id).to eq 'foo'
24
+ end
25
+
26
+ it 'haz endpoint url' do
27
+ expect(test_value.url).to eq '/api/v1/tests'
28
+ end
29
+
30
+ it 'can be converted to JSON value' do
31
+ Time.dummy('2011-11-11T11:11:11+01:00') do
32
+ expect(JSON(test_value)).to eq \
33
+ '{"id":"foo","number":10000000000,"created_at":"2011-11-11T11:11:11.000000Z","tags":["foo","bar"]}'
34
+ end
35
+ end
36
+
37
+ it 'can be output as string' do
38
+ expect(test_value.to_s).to eq "#<BI::TestModelValue type=TestModel id=foo>"
39
+ end
40
+
41
+ it 'can clear the models from bi' do
42
+ connection = double
43
+ expect(BI::Commands::Connection).to receive(:connect_to_server).and_yield(connection)
44
+ expect_any_instance_of(BI::Commands::Delete).to receive(:perform_via).with(connection)
45
+ test_value.class.clear
46
+ end
47
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ describe BI::Tracking do
4
+ let :tracked do
5
+ Class.new do
6
+ class << self
7
+ def serialize(*)
8
+ end
9
+ end
10
+
11
+ include BI::Tracking
12
+
13
+ def tracking
14
+ @tracking ||= {}
15
+ end
16
+
17
+ self
18
+ end.new
19
+ end
20
+
21
+ it 'can track foos' do
22
+ expect(tracked.respond_to?(:tracking_foo)).to eq true
23
+ tracked.tracking_foo = :foo
24
+ expect(tracked.tracking_foo).to eq :foo
25
+ end
26
+
27
+ it 'can have a tracking_hash' do
28
+ tracked.tracking_foo = :foo
29
+ expect(tracked.tracking_hash).to eq(foo: :foo)
30
+ end
31
+
32
+ it 'does not answer non_tracking tings' do
33
+ expect {
34
+ tracked.non_tracking_foo = :foo
35
+ }.to raise_error NoMethodError
36
+ end
37
+ end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+ require 'fileutils'
3
+
4
+ describe BI::TypeGenerator do
5
+ before do
6
+ allow_any_instance_of(described_class).to receive(:gofmt)
7
+ end
8
+
9
+ let :go_file do
10
+ Pathname.new(cc.bi.bime_dir).join('test_model.go')
11
+ end
12
+
13
+ after do
14
+ FileUtils.rm_rf go_file
15
+ end
16
+
17
+ it 'Can generate a GO types according to spec in a BI::*Value' do
18
+ described_class.new.generate
19
+ expect(File.read(go_file)).to eq(<<~end)
20
+ package bime
21
+
22
+ import (
23
+ "time"
24
+ "github.com/lib/pq"
25
+ )
26
+
27
+ type TestModel struct {
28
+ Id string `json:"id" gorm:"type:uuid;primary_key"`
29
+ Number *int64 `json:"number" gorm:"type:bigint"`
30
+ CreatedAt *time.Time `json:"created_at" gorm:"-" timestamp:"split"`
31
+ CreatedAtLocal *time.Time `json:"-" gorm:"type:timestamp;index"`
32
+ CreatedAtYearLocal *int `json:"-" gorm:"type:int;index"`
33
+ CreatedAtMonthLocal *int `json:"-" gorm:"type:int;index"`
34
+ CreatedAtDayLocal *int `json:"-" gorm:"type:int;index"`
35
+ CreatedAtHourLocal *int `json:"-" gorm:"type:int;index"`
36
+ CreatedAtCWLocal *int `json:"-" gorm:"type:int;index"`
37
+ CreatedAtDateLocal *string `json:"-" gorm:"type:varchar;index"`
38
+ CreatedAtYearMonthLocal *string `json:"-" gorm:"type:varchar;index"`
39
+ CreatedAtYearCWLocal *string `json:"-" gorm:"type:varchar;index"`
40
+ Tags pq.StringArray `json:"tags" gorm:"type:varchar[]"`
41
+ }
42
+ end
43
+ end
44
+ end