rom-sql 0.3.2 → 0.4.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +55 -18
  4. data/.rubocop_todo.yml +15 -0
  5. data/.travis.yml +10 -5
  6. data/CHANGELOG.md +18 -0
  7. data/Gemfile +8 -1
  8. data/Guardfile +24 -0
  9. data/README.md +14 -22
  10. data/Rakefile +13 -5
  11. data/lib/rom/sql.rb +5 -5
  12. data/lib/rom/sql/commands.rb +7 -49
  13. data/lib/rom/sql/commands/create.rb +29 -0
  14. data/lib/rom/sql/commands/delete.rb +18 -0
  15. data/lib/rom/sql/commands/transaction.rb +17 -0
  16. data/lib/rom/sql/commands/update.rb +54 -0
  17. data/lib/rom/sql/commands_ext/postgres.rb +24 -0
  18. data/lib/rom/sql/header.rb +8 -9
  19. data/lib/rom/sql/migration.rb +26 -0
  20. data/lib/rom/sql/plugin/pagination.rb +93 -0
  21. data/lib/rom/sql/rake_task.rb +2 -0
  22. data/lib/rom/sql/relation.rb +320 -0
  23. data/lib/rom/sql/relation/associations.rb +104 -0
  24. data/lib/rom/sql/relation/class_methods.rb +47 -0
  25. data/lib/rom/sql/relation/inspection.rb +16 -0
  26. data/lib/rom/sql/repository.rb +59 -0
  27. data/lib/rom/sql/support/rails_log_subscriber.rb +1 -1
  28. data/lib/rom/sql/tasks/migration_tasks.rake +56 -0
  29. data/lib/rom/sql/version.rb +1 -1
  30. data/rom-sql.gemspec +2 -3
  31. data/spec/integration/commands/create_spec.rb +66 -8
  32. data/spec/integration/commands/delete_spec.rb +22 -3
  33. data/spec/integration/commands/update_spec.rb +57 -6
  34. data/spec/integration/read_spec.rb +42 -1
  35. data/spec/shared/database_setup.rb +10 -5
  36. data/spec/spec_helper.rb +17 -0
  37. data/spec/support/active_support_notifications_spec.rb +5 -4
  38. data/spec/support/rails_log_subscriber_spec.rb +2 -2
  39. data/spec/unit/logger_spec.rb +5 -3
  40. data/spec/unit/many_to_many_spec.rb +2 -2
  41. data/spec/unit/migration_spec.rb +34 -0
  42. data/spec/unit/migration_tasks_spec.rb +99 -0
  43. data/spec/unit/one_to_many_spec.rb +0 -2
  44. data/spec/unit/plugin/pagination_spec.rb +73 -0
  45. data/spec/unit/relation_spec.rb +49 -3
  46. data/spec/unit/repository_spec.rb +33 -0
  47. data/spec/unit/schema_spec.rb +5 -17
  48. metadata +32 -35
  49. data/lib/rom/sql/adapter.rb +0 -100
  50. data/lib/rom/sql/relation_inclusion.rb +0 -149
  51. data/lib/rom/sql/support/sequel_dataset_ext.rb +0 -33
  52. data/spec/unit/adapter_spec.rb +0 -48
  53. data/spec/unit/config_spec.rb +0 -54
@@ -3,7 +3,8 @@ require 'spec_helper'
3
3
  describe ROM::Relation do
4
4
  include_context 'users and tasks'
5
5
 
6
- subject(:users) { rom.relations.users }
6
+ let(:users) { rom.relations.users }
7
+ let(:tasks) { rom.relations.tasks }
7
8
 
8
9
  before do
9
10
  setup.relation(:users) do
@@ -13,6 +14,39 @@ describe ROM::Relation do
13
14
  end
14
15
  end
15
16
 
17
+ describe '#map' do
18
+ it 'yields tuples' do
19
+ result = []
20
+ users.map { |tuple| result << tuple }
21
+ expect(result).to eql([{ id: 1, name: 'Piotr' }])
22
+ end
23
+ end
24
+
25
+ describe '#inner_join' do
26
+ it 'joins relations using inner join' do
27
+ conn[:users].insert(id: 2, name: 'Jane')
28
+
29
+ result = users.inner_join(:tasks, user_id: :id).select(:name, :title)
30
+
31
+ expect(result.to_a).to match_array([
32
+ { name: 'Piotr', title: 'Finish ROM' }
33
+ ])
34
+ end
35
+ end
36
+
37
+ describe '#left_join' do
38
+ it 'joins relations using left outer join' do
39
+ conn[:users].insert(id: 2, name: 'Jane')
40
+
41
+ result = users.left_join(:tasks, user_id: :id).select(:name, :title)
42
+
43
+ expect(result.to_a).to match_array([
44
+ { name: 'Piotr', title: 'Finish ROM' },
45
+ { name: 'Jane', title: nil }
46
+ ])
47
+ end
48
+ end
49
+
16
50
  describe '#project' do
17
51
  it 'projects the dataset using new column names' do
18
52
  projected = users.sorted.project(:name)
@@ -59,9 +93,21 @@ describe ROM::Relation do
59
93
  end
60
94
 
61
95
  describe '#inspect' do
62
- it 'includes dataset and header' do
63
- expect(users.inspect).to include('header')
96
+ it 'includes dataset' do
64
97
  expect(users.inspect).to include('dataset')
65
98
  end
66
99
  end
100
+
101
+ describe '#unique?' do
102
+ before { tasks.delete }
103
+
104
+ it 'returns true when there is only one tuple matching criteria' do
105
+ expect(tasks.unique?(title: 'Task One')).to be(true)
106
+ end
107
+
108
+ it 'returns true when there are more than one tuple matching criteria' do
109
+ tasks.insert(title: 'Task One')
110
+ expect(tasks.unique?(title: 'Task One')).to be(false)
111
+ end
112
+ end
67
113
  end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ require 'rom/lint/spec'
4
+
5
+ describe ROM::SQL::Repository do
6
+ include_context 'users and tasks'
7
+
8
+ let(:repository) { rom.repositories[:default] }
9
+
10
+ it_behaves_like 'a rom repository' do
11
+ let(:identifier) { :sql }
12
+ let(:repository) { ROM::SQL::Repository }
13
+ let(:uri) { 'postgres://localhost/rom' }
14
+ end
15
+
16
+ describe '#dataset?' do
17
+ it 'returns true if a table exists' do
18
+ expect(repository.dataset?(:users)).to be(true)
19
+ end
20
+
21
+ it 'returns false if a table does not exist' do
22
+ expect(repository.dataset?(:not_here)).to be(false)
23
+ end
24
+ end
25
+
26
+ describe '#disconnect' do
27
+ it 'disconnects via sequel connection' do
28
+ # FIXME: no idea how to test it in a different way
29
+ expect(repository.connection).to receive(:disconnect)
30
+ repository.disconnect
31
+ end
32
+ end
33
+ end
@@ -1,32 +1,20 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe 'Inferring schema from database' do
4
- let(:setup) { ROM.setup(postgres: "postgres://localhost/rom") }
4
+ include_context 'database setup'
5
5
 
6
6
  context "when database schema exists" do
7
- after { rom.postgres.connection.drop_table?(:people) }
8
-
9
- let(:rom) { setup.finalize }
10
-
11
7
  it "infers the schema from the database relations" do
12
- setup.postgres.connection.create_table :people do
13
- primary_key :id
14
- String :name
15
- end
16
-
17
- schema = rom.schema
18
-
19
- expect(schema.people.to_a).to eql(rom.postgres.people.to_a)
20
- expect(schema.people.header).to eql([:id, :name])
8
+ expect(rom.relations.users.to_a)
9
+ .to eql(rom.repositories[:default][:users].to_a)
21
10
  end
22
11
  end
23
12
 
24
13
  context "for empty database schemas" do
25
14
  it "returns an empty schema" do
26
- rom = setup.finalize
27
- schema = rom.schema
15
+ drop_tables
28
16
 
29
- expect { schema.postgres }.to raise_error(NoMethodError)
17
+ expect { rom.not_here }.to raise_error(NoMethodError)
30
18
  end
31
19
  end
32
20
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rom-sql
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.4.0.beta1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr Solnica
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-01 00:00:00.000000000 Z
11
+ date: 2015-02-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sequel
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '4.17'
19
+ version: '4.18'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '4.17'
26
+ version: '4.18'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: equalizer
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -50,20 +50,14 @@ dependencies:
50
50
  requirements:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
- version: '0.5'
54
- - - ">="
55
- - !ruby/object:Gem::Version
56
- version: 0.5.0
53
+ version: 0.6.0.beta1
57
54
  type: :runtime
58
55
  prerelease: false
59
56
  version_requirements: !ruby/object:Gem::Requirement
60
57
  requirements:
61
58
  - - "~>"
62
59
  - !ruby/object:Gem::Version
63
- version: '0.5'
64
- - - ">="
65
- - !ruby/object:Gem::Version
66
- version: 0.5.0
60
+ version: 0.6.0.beta1
67
61
  - !ruby/object:Gem::Dependency
68
62
  name: bundler
69
63
  requirement: !ruby/object:Gem::Requirement
@@ -92,20 +86,6 @@ dependencies:
92
86
  - - "~>"
93
87
  - !ruby/object:Gem::Version
94
88
  version: '10.0'
95
- - !ruby/object:Gem::Dependency
96
- name: rubocop
97
- requirement: !ruby/object:Gem::Requirement
98
- requirements:
99
- - - "~>"
100
- - !ruby/object:Gem::Version
101
- version: 0.28.0
102
- type: :development
103
- prerelease: false
104
- version_requirements: !ruby/object:Gem::Requirement
105
- requirements:
106
- - - "~>"
107
- - !ruby/object:Gem::Version
108
- version: 0.28.0
109
89
  description: SQL databases support for ROM
110
90
  email:
111
91
  - piotr.solnica@gmail.com
@@ -116,22 +96,35 @@ files:
116
96
  - ".gitignore"
117
97
  - ".rspec"
118
98
  - ".rubocop.yml"
99
+ - ".rubocop_todo.yml"
119
100
  - ".travis.yml"
120
101
  - CHANGELOG.md
121
102
  - Gemfile
103
+ - Guardfile
122
104
  - LICENSE.txt
123
105
  - README.md
124
106
  - Rakefile
125
107
  - lib/rom-sql.rb
126
108
  - lib/rom/sql.rb
127
- - lib/rom/sql/adapter.rb
128
109
  - lib/rom/sql/commands.rb
110
+ - lib/rom/sql/commands/create.rb
111
+ - lib/rom/sql/commands/delete.rb
112
+ - lib/rom/sql/commands/transaction.rb
113
+ - lib/rom/sql/commands/update.rb
114
+ - lib/rom/sql/commands_ext/postgres.rb
129
115
  - lib/rom/sql/header.rb
130
- - lib/rom/sql/relation_inclusion.rb
116
+ - lib/rom/sql/migration.rb
117
+ - lib/rom/sql/plugin/pagination.rb
118
+ - lib/rom/sql/rake_task.rb
119
+ - lib/rom/sql/relation.rb
120
+ - lib/rom/sql/relation/associations.rb
121
+ - lib/rom/sql/relation/class_methods.rb
122
+ - lib/rom/sql/relation/inspection.rb
123
+ - lib/rom/sql/repository.rb
131
124
  - lib/rom/sql/spec/support.rb
132
125
  - lib/rom/sql/support/active_support_notifications.rb
133
126
  - lib/rom/sql/support/rails_log_subscriber.rb
134
- - lib/rom/sql/support/sequel_dataset_ext.rb
127
+ - lib/rom/sql/tasks/migration_tasks.rake
135
128
  - lib/rom/sql/version.rb
136
129
  - log/.gitkeep
137
130
  - rom-sql.gemspec
@@ -144,14 +137,16 @@ files:
144
137
  - spec/spec_helper.rb
145
138
  - spec/support/active_support_notifications_spec.rb
146
139
  - spec/support/rails_log_subscriber_spec.rb
147
- - spec/unit/adapter_spec.rb
148
140
  - spec/unit/combined_associations_spec.rb
149
- - spec/unit/config_spec.rb
150
141
  - spec/unit/logger_spec.rb
151
142
  - spec/unit/many_to_many_spec.rb
152
143
  - spec/unit/many_to_one_spec.rb
144
+ - spec/unit/migration_spec.rb
145
+ - spec/unit/migration_tasks_spec.rb
153
146
  - spec/unit/one_to_many_spec.rb
147
+ - spec/unit/plugin/pagination_spec.rb
154
148
  - spec/unit/relation_spec.rb
149
+ - spec/unit/repository_spec.rb
155
150
  - spec/unit/schema_spec.rb
156
151
  homepage: http://rom-rb.org
157
152
  licenses:
@@ -168,9 +163,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
168
163
  version: '0'
169
164
  required_rubygems_version: !ruby/object:Gem::Requirement
170
165
  requirements:
171
- - - ">="
166
+ - - ">"
172
167
  - !ruby/object:Gem::Version
173
- version: '0'
168
+ version: 1.3.1
174
169
  requirements: []
175
170
  rubyforge_project:
176
171
  rubygems_version: 2.2.2
@@ -187,13 +182,15 @@ test_files:
187
182
  - spec/spec_helper.rb
188
183
  - spec/support/active_support_notifications_spec.rb
189
184
  - spec/support/rails_log_subscriber_spec.rb
190
- - spec/unit/adapter_spec.rb
191
185
  - spec/unit/combined_associations_spec.rb
192
- - spec/unit/config_spec.rb
193
186
  - spec/unit/logger_spec.rb
194
187
  - spec/unit/many_to_many_spec.rb
195
188
  - spec/unit/many_to_one_spec.rb
189
+ - spec/unit/migration_spec.rb
190
+ - spec/unit/migration_tasks_spec.rb
196
191
  - spec/unit/one_to_many_spec.rb
192
+ - spec/unit/plugin/pagination_spec.rb
197
193
  - spec/unit/relation_spec.rb
194
+ - spec/unit/repository_spec.rb
198
195
  - spec/unit/schema_spec.rb
199
196
  has_rdoc:
@@ -1,100 +0,0 @@
1
- require 'logger'
2
-
3
- require 'rom/sql/commands'
4
-
5
- module ROM
6
- module SQL
7
- class Adapter < ROM::Adapter
8
- attr_reader :logger
9
-
10
- def self.schemes
11
- [:ado, :amalgalite, :cubrid, :db2, :dbi, :do, :fdbsql, :firebird,
12
- :ibmdb, :informix, :jdbc, :mysql, :mysql2, :odbc, :openbase, :oracle,
13
- :postgres, :sqlanywhere, :sqlite, :sqlite3, :swift, :tinytds]
14
- end
15
-
16
- def self.normalize_scheme(input)
17
- scheme = input.dup
18
- scheme = 'sqlite' if scheme == 'sqlite3'
19
-
20
- if RUBY_ENGINE == 'jruby' && scheme != 'postgres'
21
- scheme.prepend('jdbc:')
22
- end
23
-
24
- scheme
25
- end
26
-
27
- def self.database_file?(scheme)
28
- scheme.to_s.include?('sqlite')
29
- end
30
-
31
- def initialize(*args)
32
- super
33
- @connection = ::Sequel.connect(uri.to_s, options)
34
- end
35
-
36
- def disconnect
37
- connection.disconnect
38
- end
39
-
40
- def [](name)
41
- connection[name]
42
- end
43
-
44
- def logger=(logger)
45
- @logger = logger
46
- connection.loggers << logger
47
- end
48
-
49
- def schema
50
- tables.map { |table| [table, dataset(table), columns(table)] }
51
- end
52
-
53
- def dataset?(name)
54
- tables.include?(name)
55
- end
56
-
57
- def extend_relation_class(klass)
58
- klass.send(:include, RelationInclusion)
59
- end
60
-
61
- def extend_relation_instance(relation)
62
- model = relation.model
63
- model.set_dataset(relation.dataset)
64
- model.dataset.naked!
65
- end
66
-
67
- def command_namespace
68
- SQL::Commands
69
- end
70
-
71
- private
72
-
73
- def tables
74
- connection.tables
75
- end
76
-
77
- def columns(table)
78
- dataset(table).columns
79
- end
80
-
81
- def dataset(table)
82
- connection[table]
83
- end
84
-
85
- def attributes(table)
86
- map_attribute_types connection.schema(table)
87
- end
88
-
89
- def map_attribute_types(attrs)
90
- attrs.map do |column, opts|
91
- [column, { type: map_schema_type(opts[:type]) }]
92
- end.to_h
93
- end
94
-
95
- def map_schema_type(type)
96
- connection.class::SCHEMA_TYPE_CLASSES.fetch(type)
97
- end
98
- end
99
- end
100
- end
@@ -1,149 +0,0 @@
1
- module ROM
2
- module SQL
3
- # Sequel-specific relation extensions
4
- #
5
- module RelationInclusion
6
- def self.included(klass)
7
- klass.extend(AssociationDSL)
8
-
9
- klass.send(:undef_method, :select)
10
- klass.send(:attr_reader, :model)
11
-
12
- klass.class_eval do
13
- class << self
14
- attr_accessor :model
15
- end
16
-
17
- self.model = Class.new(Sequel::Model)
18
- end
19
- end
20
-
21
- def initialize(*args)
22
- super
23
- @model = self.class.model
24
- @header = dataset.header
25
- end
26
-
27
- # Join configured association.
28
- #
29
- # Uses INNER JOIN type.
30
- #
31
- # @example
32
- #
33
- # setup.relation(:tasks)
34
- #
35
- # setup.relations(:users) do
36
- # one_to_many :tasks, key: :user_id
37
- #
38
- # def with_tasks
39
- # association_join(:tasks, select: [:title])
40
- # end
41
- # end
42
- #
43
- # @api public
44
- def association_join(name, options = {})
45
- graph_join(name, :inner, options)
46
- end
47
-
48
- # Join configured association
49
- #
50
- # Uses LEFT JOIN type.
51
- #
52
- # @example
53
- #
54
- # setup.relation(:tasks)
55
- #
56
- # setup.relations(:users) do
57
- # one_to_many :tasks, key: :user_id
58
- #
59
- # def with_tasks
60
- # association_left_join(:tasks, select: [:title])
61
- # end
62
- # end
63
- #
64
- # @api public
65
- def association_left_join(name, options = {})
66
- graph_join(name, :left_outer, options)
67
- end
68
-
69
- # @api private
70
- def primary_key
71
- model.primary_key
72
- end
73
-
74
- # @api private
75
- def graph_join(name, join_type, options = {})
76
- assoc = model.association_reflection(name)
77
-
78
- key = assoc[:key]
79
- type = assoc[:type]
80
-
81
- if type == :many_to_many
82
- select = options[:select] || {}
83
-
84
- l_select, r_select =
85
- if select.is_a?(Hash)
86
- [select[assoc[:join_table]] || [], select[name]]
87
- else
88
- [[], select]
89
- end
90
-
91
- l_graph = graph(
92
- assoc[:join_table],
93
- { assoc[:left_key] => primary_key },
94
- select: l_select, implicit_qualifier: self.name
95
- )
96
-
97
- l_graph.graph(
98
- name, { primary_key => assoc[:right_key] }, select: r_select
99
- )
100
- else
101
- join_keys =
102
- if type == :many_to_one
103
- { primary_key => key }
104
- else
105
- { key => primary_key }
106
- end
107
-
108
- graph(
109
- name,
110
- join_keys,
111
- options.merge(join_type: join_type, implicit_qualifier: self.name)
112
- )
113
- end
114
- end
115
-
116
- module AssociationDSL
117
- def one_to_many(name, options)
118
- associations << [__method__, name, options.merge(relation: name)]
119
- end
120
-
121
- def many_to_many(name, options = {})
122
- associations << [__method__, name, options.merge(relation: name)]
123
- end
124
-
125
- def many_to_one(name, options = {})
126
- new_options = options.merge(relation: Inflecto.pluralize(name).to_sym)
127
- associations << [__method__, name, new_options]
128
- end
129
-
130
- def finalize(relations, relation)
131
- associations.each do |*args, options|
132
- model = relation.model
133
- other = relations[options.fetch(:relation)].model
134
-
135
- model.public_send(*args, options.merge(class: other))
136
- end
137
-
138
- model.freeze
139
-
140
- super
141
- end
142
-
143
- def associations
144
- @associations ||= []
145
- end
146
- end
147
- end
148
- end
149
- end