volt-sql 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,22 @@
1
+ module Volt
2
+ module Spec
3
+ module Helpers
4
+
5
+ def reconcile!
6
+ # trigger the reconcile
7
+ db_adaptor.db
8
+ end
9
+
10
+ def remove_model(klass)
11
+ klass_name = klass.name.to_sym
12
+ Volt::RootModels.remove_model_class(klass)
13
+ Object.send(:remove_const, klass_name)
14
+ end
15
+
16
+ def indexes(table_name)
17
+ Volt::Sql::Helper.normalized_indexes_from_table(db, table_name)
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,88 @@
1
+ require 'spec_helper'
2
+ require_relative 'helpers'
3
+
4
+ describe Volt::Sql::IndexUpdater do
5
+ let(:db_adaptor) { Volt::DataStore.fetch(volt_app) }
6
+ let(:db) { db_adaptor.db }
7
+ before do
8
+ # Access store, so we trigger cleanup after
9
+ store
10
+ end
11
+
12
+ include Volt::Spec::Helpers
13
+
14
+ it 'should add indexes' do
15
+ class SampleModelIndexes1 < Volt::Model
16
+ temporary
17
+ field :name, String
18
+
19
+ index :name
20
+ end
21
+
22
+ reconcile!
23
+
24
+ expect(indexes(:sample_model_indexes1s)).to eq(
25
+ {:sample_model_indexes1s_name_index=>{:columns=>[:name], :unique=>false}}
26
+ )
27
+ end
28
+
29
+ it 'should drop a removed index' do
30
+ class SampleModelIndexes2 < Volt::Model
31
+ temporary
32
+ field :name, String
33
+
34
+ index :name
35
+ end
36
+
37
+ reconcile!
38
+
39
+ expect(indexes(:sample_model_indexes2s)).to eq(
40
+ {:sample_model_indexes2s_name_index=>{:columns=>[:name], :unique=>false}}
41
+ )
42
+
43
+ remove_model(SampleModelIndexes2)
44
+
45
+ class SampleModelIndexes2 < Volt::Model
46
+ temporary
47
+ field :name, String
48
+ end
49
+
50
+ reconcile!
51
+
52
+ expect(indexes(:sample_model_indexes2s)).to eq({})
53
+ end
54
+
55
+ it 'should rename an index' do
56
+ class SampleModelIndexes3 < Volt::Model
57
+ temporary
58
+ field :name, String
59
+
60
+ index :name, name: :index_for_name
61
+ end
62
+
63
+ reconcile!
64
+
65
+ expect(indexes(:sample_model_indexes3s)).to eq(
66
+ {:index_for_name=>{:columns=>[:name], :unique=>false}}
67
+ )
68
+
69
+ remove_model(SampleModelIndexes3)
70
+
71
+ class SampleModelIndexes3 < Volt::Model
72
+ temporary
73
+ field :name, String
74
+
75
+ index :name, name: :name_index_for_name, unique: true
76
+ end
77
+
78
+ expect(SampleModelIndexes3.indexes).to eq(
79
+ {:name_index_for_name=>{:unique=>true, :columns=>[:name]}}
80
+ )
81
+
82
+ reconcile!
83
+
84
+ expect(indexes(:sample_model_indexes3s)).to eq(
85
+ {:name_index_for_name=>{:columns=>[:name], :unique=>true}}
86
+ )
87
+ end
88
+ end
@@ -0,0 +1,59 @@
1
+ require 'spec_helper'
2
+
3
+ describe Volt::Sql::WhereCall do
4
+ it 'should replay the ast' do
5
+ ast = ["c", "ident", "name"]
6
+
7
+ name_double = double('name')
8
+ ident = double('ident')
9
+ expect(ident).to receive(:name).and_return(name_double)
10
+ result = Volt::Sql::WhereCall.new(ident).call(ast)
11
+
12
+ expect(result).to eq(name_double)
13
+ end
14
+
15
+ it 'should replay the ast with nested' do
16
+ ast = ["c", ["c", "ident", "lat"], ">", 80]
17
+
18
+ ident = double('ident')
19
+ lat = double('lat')
20
+ expect(ident).to receive(:lat).and_return(lat)
21
+
22
+ final = double('final')
23
+ expect(lat).to receive(:>).with(80).and_return(final)
24
+
25
+ result = Volt::Sql::WhereCall.new(ident).call(ast)
26
+
27
+ expect(result).to eq(final)
28
+ end
29
+
30
+ it 'should replay with nested and logical operators' do
31
+ ast = [
32
+ "c",
33
+ ["c", ["c", "ident", "lat"], ">", 80],
34
+ '&',
35
+ ["c", ["c", "ident", "lng"], "<", 50]
36
+ ]
37
+
38
+ ident = double('ident')
39
+ lat = double('lat')
40
+ expect(ident).to receive(:lat).and_return(lat)
41
+
42
+ lng = double('lng')
43
+ expect(ident).to receive(:lng).and_return(lng)
44
+
45
+ left = double('left')
46
+ expect(lat).to receive(:>).with(80).and_return(left)
47
+
48
+ right = double('right')
49
+ expect(lng).to receive(:<).with(50).and_return(right)
50
+
51
+ final = double('final')
52
+ expect(left).to receive(:&).with(right).and_return(final)
53
+
54
+ result = Volt::Sql::WhereCall.new(ident).call(ast)
55
+
56
+ expect(result).to eq(final)
57
+
58
+ end
59
+ end
@@ -0,0 +1,178 @@
1
+ require 'spec_helper'
2
+ require_relative 'helpers'
3
+
4
+ describe Volt::Sql::TableReconcile do
5
+ let(:db_adaptor) { Volt::DataStore.fetch(volt_app) }
6
+ let(:db) { db_adaptor.db }
7
+ before do
8
+ # Access store, so we trigger cleanup after
9
+ store
10
+ end
11
+
12
+ include Volt::Spec::Helpers
13
+
14
+ it 'should create a table when a new model is defined' do
15
+ expect(db.tables).to_not include(:sample_model1)
16
+
17
+ class SampleModel1 < Volt::Model
18
+ temporary
19
+ end
20
+
21
+ reconcile!
22
+
23
+ expect(db.tables).to include(:sample_model1s)
24
+ end
25
+
26
+ it 'should assign the right types to fields' do
27
+ class SampleModel2 < Volt::Model
28
+ temporary
29
+
30
+ field :name, String
31
+ field :title, String, size: 50
32
+ field :place, String, nil: false
33
+ field :created_at, VoltTime
34
+ field :count, Fixnum
35
+ field :cash, Float
36
+ field :is_admin, Volt::Boolean
37
+ end
38
+
39
+ adaptor_name = db_adaptor.adaptor_name
40
+
41
+ reconcile = Volt::Sql::TableReconcile.new(db_adaptor, db, SampleModel2)
42
+ reconcile.run
43
+ db_fields = reconcile.db_fields_for_table(:sample_model2s)
44
+
45
+ schema = {
46
+ :id=>{:db_type=>"text", :default=>nil, :allow_null=>false, :primary_key=>true, :type=>:string, :auto_increment=>false, :ruby_default=>nil},
47
+ :extra=>{:db_type=>"json", :default=>nil, :allow_null=>true, :primary_key=>false, :type=>:json, :ruby_default=>nil},
48
+ :created_at=>{:db_type=>"timestamp without time zone", :default=>nil, :allow_null=>true, :primary_key=>false, :type=>:datetime, :ruby_default=>nil},
49
+ :count=>{:db_type=>"integer", :default=>nil, :allow_null=>true, :primary_key=>false, :type=>:integer, :ruby_default=>nil},
50
+ :cash=>{:db_type=>"double precision", :default=>nil, :allow_null=>true, :primary_key=>false, :type=>:float, :ruby_default=>nil},
51
+ :title => {:db_type=>"character varying(50)", :default=>nil, :allow_null=>true, :primary_key=>false, :type=>:string, :ruby_default=>nil, :max_length=>50},
52
+ :is_admin => {:db_type=>"boolean", :default=>nil, :allow_null=>true, :primary_key=>false, :type=>:boolean, :ruby_default=>nil},
53
+ :place => {:db_type=>"text", :default=>nil, :allow_null=>false, :primary_key=>false, :type=>:string, :ruby_default=>nil}
54
+ }
55
+
56
+ if adaptor_name == 'sqlite'
57
+ schema[:name] = {:db_type=>"text", :default=>nil, :allow_null=>true, :primary_key=>false, :type=>:string, :ruby_default=>nil}
58
+ else
59
+ schema[:name] = {:db_type=>"text", :default=>nil, :allow_null=>true, :primary_key=>false, :type=>:string, :ruby_default=>nil}
60
+ end
61
+
62
+ schema.each_pair do |field_name, attrs|
63
+ expect(db_fields[field_name].without(:oid)).to eq(attrs)
64
+ end
65
+
66
+ # Also check if volt can decode these back to volt field declarations
67
+ klass_and_db_opts = {
68
+ created_at: [[VoltTime, NilClass], {}],
69
+ title: [[String, NilClass], size: 50],
70
+ place: [[String], {}],
71
+ count: [[Fixnum, NilClass], {}],
72
+ cash: [[Float, NilClass], {}],
73
+ is_admin: [[Volt::Boolean, NilClass], {}]
74
+ }
75
+
76
+ klass_and_db_opts.each_pair do |field_name, klasses_and_db_opts|
77
+ expect_klasses, expect_db_opts = klasses_and_db_opts
78
+
79
+ klasses, db_opts = Volt::Sql::Helper.klasses_and_options_from_db(db_fields[field_name])
80
+
81
+ expect(expect_klasses).to eq(klasses)
82
+ expect(expect_db_opts).to eq(db_opts)
83
+ end
84
+
85
+ end
86
+
87
+ it 'should create migrations when a field changes' do
88
+ class SampleModel3 < Volt::Model
89
+ temporary
90
+ field :some_num, Fixnum
91
+ end
92
+
93
+ reconcile!
94
+
95
+ expect(db.tables).to include(:sample_model3s)
96
+
97
+ remove_model(SampleModel3)
98
+
99
+ db_adaptor.skip_reconcile do
100
+ class SampleModel3 < Volt::Model
101
+ temporary
102
+ field :some_num, String
103
+ end
104
+ end
105
+
106
+ reconcile = Volt::Sql::TableReconcile.new(db_adaptor, db, SampleModel3)
107
+
108
+ allow(reconcile.field_updater).to receive(:generate_and_run)
109
+ .with(
110
+ "column_change_sample_model3s_some_num",
111
+ "set_column_type :sample_model3s, :some_num, String, {:allow_null=>true, :text=>true}",
112
+ "set_column_type :sample_model3s, :some_num, Fixnum, {:allow_null=>true}"
113
+ ).and_return(nil)
114
+
115
+ reconcile.run
116
+ end
117
+
118
+ it 'should create a migration when a field is removed' do
119
+ class SampleModel4 < Volt::Model
120
+ temporary
121
+ field :some_num, Fixnum
122
+ end
123
+
124
+ reconcile!
125
+
126
+ expect(db.tables).to include(:sample_model4s)
127
+
128
+ remove_model(SampleModel4)
129
+
130
+ db_adaptor.skip_reconcile do
131
+ class SampleModel4 < Volt::Model
132
+ temporary
133
+ end
134
+ end
135
+
136
+ reconcile = Volt::Sql::TableReconcile.new(db_adaptor, db, SampleModel4)
137
+
138
+ expect(reconcile.field_updater).to receive(:generate_and_run)
139
+ .with(
140
+ "remove_sample_model4s_some_num",
141
+ "drop_column :sample_model4s, :some_num",
142
+ "add_column :sample_model4s, :some_num, Fixnum, {:allow_null=>true}"
143
+ )
144
+
145
+ reconcile.run
146
+ end
147
+
148
+ it 'should create a migration to change the allow null status' do
149
+ class SampleModel5 < Volt::Model
150
+ temporary
151
+ field :some_num, Fixnum
152
+ end
153
+
154
+ reconcile!
155
+
156
+ expect(db.tables).to include(:sample_model5s)
157
+
158
+ remove_model(SampleModel5)
159
+
160
+ db_adaptor.skip_reconcile do
161
+ class SampleModel5 < Volt::Model
162
+ temporary
163
+ field :some_num, Fixnum, nil: false
164
+ end
165
+ end
166
+
167
+ reconcile = Volt::Sql::TableReconcile.new(db_adaptor, db, SampleModel5)
168
+
169
+ expect(reconcile.field_updater).to receive(:generate_and_run)
170
+ .with(
171
+ "column_change_sample_model5s_some_num",
172
+ "set_column_not_null :sample_model5s, :some_num",
173
+ "set_column_allow_null :sample_model5s, :some_num"
174
+ )
175
+
176
+ reconcile.run
177
+ end
178
+ end
@@ -0,0 +1,36 @@
1
+ require 'volt'
2
+
3
+ if ENV['DB'] = 'pg'
4
+ Volt.configure do |config|
5
+ config.db.uri = 'postgres://ryanstout:@localhost:5432/volt_sql_test'
6
+ end
7
+ end
8
+
9
+ require 'volt/spec/setup'
10
+
11
+ unless RUBY_PLATFORM == 'opal'
12
+ begin
13
+ require 'pry-byebug'
14
+ rescue LoadError => e
15
+ # Ignore if not installed
16
+ end
17
+ end
18
+
19
+ # Specs are run against the kitchen sink app
20
+ kitchen_sink_path = File.expand_path(File.join(File.dirname(__FILE__), 'apps/kitchen_sink'))
21
+ Volt.spec_setup(kitchen_sink_path)
22
+
23
+ unless RUBY_PLATFORM == 'opal'
24
+ RSpec.configure do |config|
25
+ config.run_all_when_everything_filtered = true
26
+ config.filter_run :focus
27
+
28
+ # Run specs in random order to surface order dependencies. If you find an
29
+ # order dependency and want to debug it, you can fix the order by providing
30
+ # the seed, which is printed after each run.
31
+ # --seed 1234
32
+ config.order = 'random'
33
+ config.seed = '10780'
34
+ end
35
+
36
+ end
data/volt-sql.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'volt/sql/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "volt-sql"
8
+ spec.version = Volt::Sql::VERSION
9
+ spec.authors = ["Ryan Stout"]
10
+ spec.email = ["ryan@agileproductions.com"]
11
+ spec.summary = %q{sql database drivers for volt}
12
+ spec.homepage = ""
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files -z`.split("\x0")
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_dependency 'sequel', '~> 4.23.0'
21
+ spec.add_development_dependency "rake"
22
+ spec.add_development_dependency "volt"
23
+ end
metadata ADDED
@@ -0,0 +1,122 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: volt-sql
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Ryan Stout
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-11-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: sequel
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 4.23.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 4.23.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: volt
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description:
56
+ email:
57
+ - ryan@agileproductions.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - Gemfile
64
+ - README.md
65
+ - Rakefile
66
+ - app/sql/config/dependencies.rb
67
+ - app/sql/config/initializers/boot.rb
68
+ - app/sql/config/routes.rb
69
+ - app/sql/controllers/main_controller.rb
70
+ - app/sql/lib/field_updater.rb
71
+ - app/sql/lib/helper.rb
72
+ - app/sql/lib/index_updater.rb
73
+ - app/sql/lib/migration.rb
74
+ - app/sql/lib/migration_generator.rb
75
+ - app/sql/lib/reconcile.rb
76
+ - app/sql/lib/sql_adaptor_client.rb
77
+ - app/sql/lib/sql_adaptor_server.rb
78
+ - app/sql/lib/sql_logger.rb
79
+ - app/sql/lib/store_persistor.rb
80
+ - app/sql/lib/table_reconcile.rb
81
+ - app/sql/lib/where_call.rb
82
+ - app/sql/views/main/index.html
83
+ - config/db/development.db
84
+ - config/db/test.db
85
+ - lib/volt/sql.rb
86
+ - lib/volt/sql/version.rb
87
+ - spec/postgres/lib/helpers.rb
88
+ - spec/postgres/lib/index_updater_spec.rb
89
+ - spec/postgres/lib/postgres_where_call_spec.rb
90
+ - spec/postgres/lib/table_reconcile_spec.rb
91
+ - spec/spec_helper.rb
92
+ - volt-sql.gemspec
93
+ homepage: ''
94
+ licenses:
95
+ - MIT
96
+ metadata: {}
97
+ post_install_message:
98
+ rdoc_options: []
99
+ require_paths:
100
+ - lib
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ required_rubygems_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ requirements: []
112
+ rubyforge_project:
113
+ rubygems_version: 2.4.5
114
+ signing_key:
115
+ specification_version: 4
116
+ summary: sql database drivers for volt
117
+ test_files:
118
+ - spec/postgres/lib/helpers.rb
119
+ - spec/postgres/lib/index_updater_spec.rb
120
+ - spec/postgres/lib/postgres_where_call_spec.rb
121
+ - spec/postgres/lib/table_reconcile_spec.rb
122
+ - spec/spec_helper.rb