veritas 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. data/.travis.yml +5 -4
  2. data/Gemfile +16 -14
  3. data/Guardfile +0 -4
  4. data/README.md +188 -0
  5. data/Rakefile +2 -2
  6. data/TODO +0 -16
  7. data/config/flay.yml +1 -1
  8. data/config/flog.yml +1 -1
  9. data/config/roodi.yml +4 -4
  10. data/config/site.reek +7 -3
  11. data/lib/veritas/aggregate.rb +18 -0
  12. data/lib/veritas/algebra/extension.rb +2 -29
  13. data/lib/veritas/algebra/projection.rb +2 -29
  14. data/lib/veritas/algebra/rename/aliases.rb +4 -32
  15. data/lib/veritas/algebra/rename.rb +2 -29
  16. data/lib/veritas/algebra/restriction.rb +2 -29
  17. data/lib/veritas/algebra/summarization.rb +2 -31
  18. data/lib/veritas/attribute/time.rb +1 -1
  19. data/lib/veritas/attribute.rb +20 -40
  20. data/lib/veritas/function/binary.rb +2 -3
  21. data/lib/veritas/function/connective/negation.rb +1 -1
  22. data/lib/veritas/function/predicate/enumerable.rb +19 -0
  23. data/lib/veritas/function/predicate/exclusion.rb +1 -1
  24. data/lib/veritas/function/predicate/match.rb +1 -1
  25. data/lib/veritas/function/unary.rb +5 -3
  26. data/lib/veritas/function.rb +1 -41
  27. data/lib/veritas/relation/base.rb +2 -29
  28. data/lib/veritas/relation/empty.rb +30 -2
  29. data/lib/veritas/relation/header.rb +17 -31
  30. data/lib/veritas/relation/materialized.rb +0 -12
  31. data/lib/veritas/relation/operation/limit.rb +2 -29
  32. data/lib/veritas/relation/operation/offset.rb +2 -29
  33. data/lib/veritas/relation/operation/order/direction.rb +3 -29
  34. data/lib/veritas/relation/operation/order/direction_set.rb +18 -34
  35. data/lib/veritas/relation/operation/order.rb +4 -56
  36. data/lib/veritas/relation.rb +8 -36
  37. data/lib/veritas/support/aliasable.rb +20 -7
  38. data/lib/veritas/support/comparator.rb +81 -0
  39. data/lib/veritas/support/evaluator.rb +1 -1
  40. data/lib/veritas/support/immutable.rb +22 -49
  41. data/lib/veritas/support/operation/binary.rb +3 -30
  42. data/lib/veritas/support/operation/unary.rb +3 -29
  43. data/lib/veritas/tuple.rb +19 -29
  44. data/lib/veritas/version.rb +1 -1
  45. data/lib/veritas.rb +1 -0
  46. data/spec/integration/veritas/relation/efficient_enumerable_spec.rb +3 -3
  47. data/spec/shared/hash_method_behavior.rb +7 -2
  48. data/spec/unit/date/pred_spec.rb +1 -1
  49. data/spec/unit/veritas/aggregate/equal_value_spec.rb +52 -0
  50. data/spec/unit/veritas/aggregate/hash_spec.rb +15 -0
  51. data/spec/unit/veritas/aliasable/inheritable_alias_spec.rb +1 -1
  52. data/spec/unit/veritas/comparator/compare_spec.rb +40 -0
  53. data/spec/unit/veritas/comparator/methods/eql_spec.rb +48 -0
  54. data/spec/unit/veritas/evaluator/context/respond_to_spec.rb +1 -1
  55. data/spec/unit/veritas/function/predicate/enumerable/call_spec.rb +36 -0
  56. data/spec/unit/veritas/function/unary/hash_spec.rb +18 -0
  57. data/spec/unit/veritas/immutable/freeze_spec.rb +2 -2
  58. data/spec/unit/veritas/immutable/memoize_spec.rb +13 -0
  59. data/spec/unit/veritas/immutable/module_methods/memoize_spec.rb +1 -1
  60. data/spec/unit/veritas/relation/empty/class_methods/new_spec.rb +30 -0
  61. data/spec/unit/veritas/relation/empty/each_spec.rb +20 -5
  62. data/spec/unit/veritas/relation/empty/size_spec.rb +11 -0
  63. data/spec/unit/veritas/relation/header/hash_spec.rb +1 -1
  64. data/spec/unit/veritas/relation/materialized/empty_spec.rb +0 -10
  65. data/spec/unit/veritas/relation/operation/order/direction_set/class_methods/coerce_spec.rb +12 -3
  66. data/tasks/metrics/heckle.rake +2 -3
  67. data/veritas.gemspec +21 -18
  68. metadata +36 -33
  69. data/README.rdoc +0 -143
  70. data/spec/unit/veritas/function/eql_spec.rb +0 -14
  71. data/spec/unit/veritas/function/equal_value_spec.rb +0 -14
  72. data/spec/unit/veritas/function/hash_spec.rb +0 -13
  73. data/spec/unit/veritas/immutable/memory/element_reference_spec.rb +0 -26
  74. data/spec/unit/veritas/immutable/memory/element_set_spec.rb +0 -19
  75. data/spec/unit/veritas/relation/operation/order/methods/order_spec.rb +0 -54
data/.travis.yml CHANGED
@@ -3,8 +3,9 @@ script: "bundle exec rake spec"
3
3
  rvm:
4
4
  - 1.8.7
5
5
  - 1.9.2
6
- - rbx
7
- # - rbx-2.0
8
- - ree
9
- # - jruby
6
+ - 1.9.3
10
7
  - ruby-head
8
+ - ree
9
+ - jruby
10
+ - rbx
11
+ - rbx-2.0
data/Gemfile CHANGED
@@ -11,10 +11,9 @@ group :development do
11
11
  end
12
12
 
13
13
  group :guard do
14
- gem 'guard', '~> 0.5.1'
14
+ gem 'guard', '~> 0.7.0'
15
15
  gem 'guard-bundler', '~> 0.1.3'
16
- gem 'guard-ego', '~> 0.0.1'
17
- gem 'guard-rspec', '~> 0.4.0'
16
+ gem 'guard-rspec', '~> 0.4.5'
18
17
  end
19
18
 
20
19
  group :benchmarks do
@@ -29,16 +28,19 @@ end
29
28
 
30
29
  platforms :mri_18 do
31
30
  group :metrics do
32
- gem 'flay', '~> 1.4.2'
33
- gem 'flog', '~> 2.5.1'
34
- gem 'heckle', '~> 1.4.3'
35
- gem 'json', '~> 1.5.3'
36
- gem 'metric_fu', '~> 2.1.1'
37
- gem 'mspec', '~> 1.5.17'
38
- gem 'rcov', '~> 0.9.9'
39
- gem 'reek', '~> 1.2.8', :git => 'git://github.com/dkubb/reek.git'
40
- gem 'roodi', '~> 2.1.0'
41
- gem 'ruby2ruby', '= 1.2.2'
42
- gem 'yardstick', '~> 0.4.0'
31
+ gem 'arrayfields', '~> 4.7.4'
32
+ gem 'fattr', '~> 2.2.0'
33
+ gem 'flay', '~> 1.4.2'
34
+ gem 'flog', '~> 2.5.3'
35
+ gem 'heckle', '~> 1.4.3'
36
+ gem 'json', '~> 1.6.1'
37
+ gem 'map', '~> 4.4.0'
38
+ gem 'metric_fu', '~> 2.1.1'
39
+ gem 'mspec', '~> 1.5.17'
40
+ gem 'rcov', '~> 0.9.9'
41
+ gem 'reek', '~> 1.2.8', :git => 'git://github.com/dkubb/reek.git'
42
+ gem 'roodi', '~> 2.1.0'
43
+ gem 'ruby2ruby', '= 1.2.2'
44
+ gem 'yardstick', '~> 0.4.0'
43
45
  end
44
46
  end
data/Guardfile CHANGED
@@ -1,9 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
- guard 'ego' do
4
- watch('Guardfile')
5
- end
6
-
7
3
  guard 'bundler' do
8
4
  watch('Gemfile')
9
5
  end
data/README.md ADDED
@@ -0,0 +1,188 @@
1
+ # Veritas
2
+
3
+ Simplifies querying of structured data using relational algebra
4
+
5
+ [![Build Status](https://secure.travis-ci.org/dkubb/veritas.png)](http://travis-ci.org/dkubb/veritas)
6
+
7
+ ## Installation
8
+
9
+ With Rubygems:
10
+
11
+ ```bash
12
+ $ gem install veritas
13
+ $ irb -rubygems
14
+ >> require 'veritas'
15
+ => true
16
+ ```
17
+
18
+ With git and local working copy:
19
+
20
+ ```bash
21
+ $ git clone git://github.com/dkubb/veritas.git
22
+ $ cd veritas
23
+ $ rake install
24
+ $ irb -rubygems
25
+ >> require 'veritas'
26
+ => true
27
+ ```
28
+
29
+ NOTE: This gem works best with ruby 1.9, however if you are using ruby 1.8 you must also install [backports](https://rubygems.org/gems/backports), then require backports and backports/basic_object, eg:
30
+
31
+ ```bash
32
+ $ ruby -e 'puts RUBY_VERSION'
33
+ => 1.8.7
34
+ $ gem install backports
35
+ $ irb -rubygems
36
+ >> require 'backports'
37
+ => true
38
+ >> require 'backports/basic_object'
39
+ => true
40
+ >> require 'veritas' # assuming it was installed by one of the two methods above
41
+ => true
42
+ ```
43
+
44
+ ## Usage
45
+
46
+ ```ruby
47
+ relation = Veritas::Relation.new(
48
+ [ [ :id, String ], [ :name, String ], [ :color, String ], [ :weight, Float ], [ :city, String ] ],
49
+ [
50
+ [ 'P1', 'Nut', 'Red', 12.0, 'London' ],
51
+ [ 'P2', 'Bolt', 'Green', 17.0, 'Paris' ],
52
+ [ 'P3', 'Screw', 'Blue', 17.0, 'Oslo' ],
53
+ [ 'P4', 'Screw', 'Red', 14.0, 'London' ],
54
+ [ 'P5', 'Cam', 'Blue', 12.0, 'Paris' ],
55
+ [ 'P6', 'Cog', 'Red', 19.0, 'London' ],
56
+ ]
57
+ )
58
+
59
+ # Relational Operators
60
+ # --------------------
61
+
62
+ # projection
63
+ new_relation = relation.project([ :id ])
64
+
65
+ # removal
66
+ new_relation = relation.remove([ :name ])
67
+
68
+ # rename
69
+ new_relation = relation.rename(id: :other_id, name: :other_name)
70
+
71
+ # restriction
72
+ new_relation = relation.restrict { |r| r.name.eq('Screw').or(r.city.eq('London')) }
73
+
74
+ # natural join
75
+ new_relation = relation.join(other) # OR relation + other
76
+
77
+ # product
78
+ new_relation = relation.product(other) # OR relation * other
79
+
80
+ # intersection
81
+ new_relation = relation.intersect(other) # OR relation & other
82
+
83
+ # union
84
+ new_relation = relation.union(other) # OR relation | other
85
+
86
+ # difference
87
+ new_relation = relation.difference(other) # OR relation - other
88
+
89
+ # theta-join
90
+ new_relation = relation.join(other) { |r| r.id.gte(r.other_id) }
91
+
92
+ # NOTE: theta-join is effectively restricting a product of the relations
93
+
94
+ # extend
95
+ new_relation = relation.extend { |r| r.add(:pounds, r.weight * 2.2) }
96
+ new_relation = relation.extend { |r| r.add(:pounds) { |t| t[:weight] * 2.2 } }
97
+
98
+ # summarize
99
+ new_relation = relation.summarize(relation.project([ :city ])) { |r| r.add(:count, r.id.count) }
100
+ new_relation = relation.summarize(relation.project([ :city ])) { |r| r.add(:count) { |acc, t| acc.to_i + 1 } }
101
+
102
+ # Non-Relational Operators
103
+ # ------------------------
104
+
105
+ # returns a set that represents the relation header
106
+ header = relation.header
107
+
108
+ # a relation is Enumerable
109
+ relation = relation.each { |tuple| ... }
110
+
111
+ # order by attribute and direction
112
+ ordered = relation.sort_by { |r| [ r.city.desc, r.name, r.color, r.id, r.weight ] }
113
+
114
+ # reverse the relation (only allowed if ordered)
115
+ new_relation = ordered.reverse
116
+
117
+ # offset (only allowed if ordered)
118
+ new_relation = ordered.drop(5)
119
+
120
+ # limiting (only allowed if ordered)
121
+ new_relation = ordered.take(10)
122
+
123
+ # get the first n tuples (only allowed if ordered)
124
+ new_relation = ordered.first # default is 1
125
+ new_relation = ordered.first(5)
126
+
127
+ # get the last n tuples (only allowed if ordered)
128
+ new_relation = ordered.last # default is 1
129
+ new_relation = ordered.last(5)
130
+ ```
131
+
132
+ ## Goals
133
+
134
+ The purpose of this project is to expand my knowledge of relational algebra by attempting to implement a simple query system using the primitive operations defined in relational algebra.
135
+
136
+ Most of the design is heavily inspired from [koios](https://github.com/carllerche/koios) and [arel](https://github.com/rails/arel). The reason I decided to write my own and not just build on top of those systems was not so much because I don't like the code/API in those projects, it's more because I wanted to gain a depth of understanding that can only be earned by trying to solve the problem myself.
137
+
138
+ I should note though that I don't plan to just re-implement those systems with a different API, or different internals, I plan to make something that surpasses them in several areas. For example, I want to be able to join information from multiple datastores and represent it as a single relation. I want to be able to insert, update or delete from that relation and have those changes propagated back to the right datastore. This is not an easy feat, since it is basically the writable view problem that RDBMS' struggle with. While I do think there are some cases where relations will become read-only, I think it will be possible to propagate writes properly in this manner. I certainly think for the current use cases in DataMapper this should work quite well.
139
+
140
+ The ability to join data from multiple datastores and have it presented in a consistent manner will solve one of the longest standing problems in DataMapper, namely how do we do cross repository joins. It should be possible to construct one query for one datastore, and then another query for another datastore and then join them. Since they are using different engines veritas will know to perform each query *natively* and then join the results in-memory seamlessly. It should also be possible to reorganize the queries so that as much work as possible is done natively as opposed to in-memory, which is considered the last resort.
141
+
142
+ Not only does this work nicely with associations, but it will allow DataMapper to perform mapping in a more powerful way. You'll be able to construct a join from multiple datastores, and set that as the base for your model. Each DM Resource would work as normal, but again writes could be propagated back to the appropriate datastore. You'd be able to split your data up between different datastores, but assemble it into one coherent view.
143
+
144
+ ### Phase 1: In-Memory Operations
145
+
146
+ The first phase of this project will be to implement all the operations listed below using in-memory data structures. I'm focusing on the API, and making sure the specs ensure the desired results are obtained from each operation.
147
+
148
+ This is 100% complete.
149
+
150
+ ### Phase 2: RDBMS Engines
151
+
152
+ The second phase of this project will be to add a RDBMS based engine, and move the in-memory matching to it's own engine. I'll also be working on a system where if the primary engine cannot carry out some operation, that it first look at alternate forms (eg. using a join instead of an intersection), and then fall-back to in-memory matching. I also want to look at re-arranging queries so that all the operations that can be performed natively are "pushed down" the hierarchy and then the in-memory matching is performed last.
153
+
154
+ This is 95% complete. I have completed a first pass on [veritas-sql-generator](https://github.com/dkubb/veritas-sql-generator) which is a visitor that walks the AST and produces SQL for every operatione. More work is needed to write adapters that use the veritas-sql-generator and manage database connections/execution.
155
+
156
+ ### Phase 3: DataMapper Integration
157
+
158
+ The third phase of this project will be to add a few NoSQL engines (like [MongoDB](http://www.mongodb.org/) and [CouchDB](http://couchdb.org/)) and then look at writing a DataMapper adapter that translates Query objects into Veritas relations. I want to make sure all the DM specs pass with this adapter and each engine, and if everything goes well I will look at updating DM to work directly on top of Veritas.
159
+
160
+ ## Related Projects
161
+
162
+ * [veritas-optimizer](https://github.com/dkubb/veritas-optimizer)
163
+
164
+ This is an optimizer that takes a veritas relation, scalar or aggregate function and will transform it into something equivalent but simpler in structure to the original.
165
+
166
+ * [veritas-sql-generator](https://github.com/dkubb/veritas-sql-generator)
167
+
168
+ This is a visitor class that takes a veritas relation and generates valid SQL from it.
169
+
170
+ * [veritas-do-adapter](https://github.com/dkubb/veritas-do-adapter)
171
+
172
+ This is a system that manages the database connections and executes the SQL generated fom the relations.
173
+
174
+ ## Note on Patches/Pull Requests
175
+
176
+ * If you want your code merged into the mainline, please discuss the proposed changes with me before doing any work on it. This library is still in early development, and it may not always be clear the direction it is going. Some features may not be appropriate yet, may need to be deferred until later when the foundation for them is laid, or may be more applicable in a plugin.
177
+ * Fork the project.
178
+ * Make your feature addition or bug fix.
179
+ * Follow this [style guide](https://github.com/dkubb/styleguide).
180
+ * Add specs for it. This is important so I don't break it in a future version unintentionally. Tests must cover all branches within the code, and code must be fully covered.
181
+ * Commit, do not mess with Rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
182
+ * Run "rake ci". This must pass and not show any regressions in the
183
+ metrics for the code to be merged.
184
+ * Send me a pull request. Bonus points for topic branches.
185
+
186
+ ## Copyright
187
+
188
+ Copyright © 2009-2011 Dan Kubb. See LICENSE for details.
data/Rakefile CHANGED
@@ -5,7 +5,7 @@ require 'rake'
5
5
  require File.expand_path('../lib/veritas/version', __FILE__)
6
6
 
7
7
  begin
8
- gem('jeweler', '~> 1.6.2') if respond_to?(:gem, true)
8
+ gem('jeweler', '~> 1.6.4') if respond_to?(:gem, true)
9
9
  require 'jeweler'
10
10
 
11
11
  Jeweler::Tasks.new do |gem|
@@ -23,5 +23,5 @@ begin
23
23
 
24
24
  FileList['tasks/**/*.rake'].each { |task| import task }
25
25
  rescue LoadError
26
- puts 'Jeweler (or a dependency) not available. Install it with: gem install jeweler -v 1.6.2'
26
+ puts 'Jeweler (or a dependency) not available. Install it with: gem install jeweler -v 1.6.4'
27
27
  end
data/TODO CHANGED
@@ -1,8 +1,3 @@
1
- * Materialized relations need to hold a reference to the original relation.
2
- * Especially "empty" relations should hold a reference to the original
3
- relation so that insert/update can be performed on them if they are
4
- empty not because they are valid, but because the source object is empty
5
-
6
1
  * Remove Order, Reverse, Limit and Offset from the Relation inheritance chain
7
2
  * Instead make it so they are proxy classes that wrap Relations, but
8
3
  proxy method calls to the Relation methods, and then wrap the return
@@ -34,17 +29,6 @@
34
29
  like with #hash that accept no args, and #optimize that accepts
35
30
  1 arg.
36
31
 
37
- * Add Relation#antijoin
38
- * Allows "NOT EXISTS/IN" type queries to be executes where every tuple
39
- from the relation is returned that *does not* join with the tuples in
40
- the operand.
41
-
42
- * Inclusion/Exclusion improvements:
43
- * Allow attribute/function expressions to exist within the enumerable part
44
- of the Inclusion and Exclusion operations
45
- * The #call method should propagate the Tuple down to each callable entry
46
- in the Enumerable.
47
-
48
32
  * Within the restriction context, make sure the attributes have aliases for:
49
33
  * Alias #== to #eq (may break alot)
50
34
  * Alias #!= to #ne (in 1.9 only)
data/config/flay.yml CHANGED
@@ -1,3 +1,3 @@
1
1
  ---
2
2
  threshold: 68
3
- total_score: 738
3
+ total_score: 682
data/config/flog.yml CHANGED
@@ -1,2 +1,2 @@
1
1
  ---
2
- threshold: 15.7
2
+ threshold: 23.3
data/config/roodi.yml CHANGED
@@ -1,18 +1,18 @@
1
1
  ---
2
- AbcMetricMethodCheck: { score: 11.8 }
2
+ AbcMetricMethodCheck: { score: 10.3 }
3
3
  AssignmentInConditionalCheck: { }
4
4
  CaseMissingElseCheck: { }
5
- ClassLineCountCheck: { line_count: 390 }
5
+ ClassLineCountCheck: { line_count: 289 }
6
6
  ClassNameCheck: { pattern: !ruby/regexp /\A(?:[A-Z]+|[A-Z][a-z](?:[A-Z]?[a-z])+)\z/ }
7
7
  ClassVariableCheck: { }
8
8
  CyclomaticComplexityBlockCheck: { complexity: 2 }
9
- CyclomaticComplexityMethodCheck: { complexity: 5 }
9
+ CyclomaticComplexityMethodCheck: { complexity: 4 }
10
10
  EmptyRescueBodyCheck: { }
11
11
  ForLoopCheck: { }
12
12
  # TODO: decrease line_count to 5 to 10
13
13
  MethodLineCountCheck: { line_count: 14 }
14
14
  MethodNameCheck: { pattern: !ruby/regexp /\A(?:[a-z\d](?:_?[a-z\d])+[?!=]?|\[\]=?|==|<=>|[+*&|-])\z/ }
15
- ModuleLineCountCheck: { line_count: 392 }
15
+ ModuleLineCountCheck: { line_count: 291 }
16
16
  ModuleNameCheck: { pattern: !ruby/regexp /\A(?:[A-Z]+|[A-Z][a-z](?:[A-Z]?[a-z])+)\z/ }
17
17
  # TODO: decrease parameter_count to 2 or less
18
18
  ParameterNumberCheck: { parameter_count: 3 }
data/config/site.reek CHANGED
@@ -8,10 +8,10 @@ UncommunicativeParameterName:
8
8
  - !ruby/regexp /[0-9]$/
9
9
  - !ruby/regexp /[A-Z]/
10
10
  LargeClass:
11
- max_methods: 15 # TODO: decrease max_methods to 10-15 or less
11
+ max_methods: 14 # TODO: decrease max_methods to 10-15 or less
12
12
  exclude: []
13
13
  enabled: true
14
- max_instance_variables: 5
14
+ max_instance_variables: 4
15
15
  UncommunicativeMethodName:
16
16
  accept: []
17
17
  exclude: []
@@ -46,7 +46,11 @@ UncommunicativeModuleName:
46
46
  - !ruby/regexp /[0-9]$/
47
47
  NestedIterators:
48
48
  ignore_iterators: []
49
- exclude: []
49
+ exclude: [
50
+ # none of these use nested iterators, they use nested blocks only
51
+ Veritas::Comparator#define_comparison_method,
52
+ Veritas::Comparator#define_hash_method
53
+ ]
50
54
  enabled: true
51
55
  max_allowed_nesting: 1
52
56
  LongMethod:
@@ -4,8 +4,11 @@ module Veritas
4
4
 
5
5
  # Abstract class for aggregate functions
6
6
  class Aggregate
7
+ extend Comparator
7
8
  include AbstractClass, Immutable, Visitable, Operation::Unary
8
9
 
10
+ compare :operand
11
+
9
12
  # Return the default accumulator
10
13
  #
11
14
  # @example
@@ -96,6 +99,21 @@ module Veritas
96
99
  raise NotImplementedError, "#{self.class}#type must be implemented"
97
100
  end
98
101
 
102
+ # Compare the aggregate with other aggregate for equivalency
103
+ #
104
+ # @example
105
+ # aggregate == other # => true or false
106
+ #
107
+ # @param [Aggregate] other
108
+ # the other aggregate to compare with
109
+ #
110
+ # @return [Boolean]
111
+ #
112
+ # @api public
113
+ def ==(other)
114
+ cmp?(__method__, other)
115
+ end
116
+
99
117
  private
100
118
 
101
119
  # Extract the value from the operand or tuple
@@ -7,6 +7,8 @@ module Veritas
7
7
  class Extension < Relation
8
8
  include Relation::Operation::Unary
9
9
 
10
+ compare :operand, :extensions
11
+
10
12
  # The extensions for the relation
11
13
  #
12
14
  # @return [Hash]
@@ -52,33 +54,6 @@ module Veritas
52
54
  self
53
55
  end
54
56
 
55
- # Compare the Extension with other relation for equality
56
- #
57
- # @example
58
- # extension.eql?(other) # => true or false
59
- #
60
- # @param [Relation] other
61
- # the other relation to compare with
62
- #
63
- # @return [Boolean]
64
- #
65
- # @api public
66
- def eql?(other)
67
- super && extensions.eql?(other.extensions)
68
- end
69
-
70
- # Return the hash of the projection
71
- #
72
- # @example
73
- # hash = extension.hash
74
- #
75
- # @return [Fixnum]
76
- #
77
- # @api public
78
- def hash
79
- super ^ extensions.hash
80
- end
81
-
82
57
  module Methods
83
58
 
84
59
  # Return an extended relation
@@ -106,8 +81,6 @@ module Veritas
106
81
 
107
82
  Relation.class_eval { include Methods }
108
83
 
109
- memoize :hash
110
-
111
84
  end # class Extension
112
85
  end # module Algebra
113
86
  end # module Veritas
@@ -7,6 +7,8 @@ module Veritas
7
7
  class Projection < Relation
8
8
  include Relation::Operation::Unary
9
9
 
10
+ compare :operand, :header
11
+
10
12
  # Initialize a Projection
11
13
  #
12
14
  # @param [Relation] operand
@@ -46,33 +48,6 @@ module Veritas
46
48
  self
47
49
  end
48
50
 
49
- # Compare the Projection with other relation for equality
50
- #
51
- # @example
52
- # projection.eql?(other) # => true or false
53
- #
54
- # @param [Relation] other
55
- # the other relation to compare with
56
- #
57
- # @return [Boolean]
58
- #
59
- # @api public
60
- def eql?(other)
61
- super && header.eql?(other.header)
62
- end
63
-
64
- # Return the hash of the projection
65
- #
66
- # @example
67
- # hash = projection.hash
68
- #
69
- # @return [Fixnum]
70
- #
71
- # @api public
72
- def hash
73
- super ^ header.hash
74
- end
75
-
76
51
  module Methods
77
52
 
78
53
  # Return a relation with only the attributes specified
@@ -137,8 +112,6 @@ module Veritas
137
112
 
138
113
  Relation.class_eval { include Methods }
139
114
 
140
- memoize :hash
141
-
142
115
  end # class Projection
143
116
  end # module Algebra
144
117
  end # module Veritas
@@ -6,9 +6,11 @@ module Veritas
6
6
 
7
7
  # Aliases that map old attributes to new renamed attributes
8
8
  class Aliases
9
- extend Aliasable
9
+ extend Aliasable, Comparator
10
10
  include Immutable, Enumerable
11
11
 
12
+ compare :to_hash
13
+
12
14
  inheritable_alias(:| => :union)
13
15
 
14
16
  # Instantiate new set of Aliases
@@ -145,35 +147,7 @@ module Veritas
145
147
  #
146
148
  # @api public
147
149
  def ==(other)
148
- to_hash == other.to_hash
149
- end
150
-
151
- # Compare the aliases with other aliases for equality
152
- #
153
- # @example
154
- # aliases.eql?(other) # => true or false
155
- #
156
- # @param [Aliases] other
157
- # the other aliases to compare with
158
- #
159
- # @return [Boolean]
160
- #
161
- # @api public
162
- def eql?(other)
163
- instance_of?(other.class) &&
164
- to_hash.eql?(other.to_hash)
165
- end
166
-
167
- # Return the hash of the aliases
168
- #
169
- # @example
170
- # hash = aliases.hash
171
- #
172
- # @return [Fixnum]
173
- #
174
- # @api public
175
- def hash
176
- self.class.hash ^ @aliases.hash
150
+ cmp?(__method__, other)
177
151
  end
178
152
 
179
153
  # Convert the aliases to a Hash
@@ -226,8 +200,6 @@ module Veritas
226
200
 
227
201
  private_class_method :coerce_alias_pair
228
202
 
229
- memoize :hash
230
-
231
203
  end # class Aliases
232
204
  end # class Rename
233
205
  end # module Algebra
@@ -7,6 +7,8 @@ module Veritas
7
7
  class Rename < Relation
8
8
  include Relation::Operation::Unary
9
9
 
10
+ compare :operand, :aliases
11
+
10
12
  # The aliases for the relation
11
13
  #
12
14
  # @return [Aliases]
@@ -58,33 +60,6 @@ module Veritas
58
60
  self
59
61
  end
60
62
 
61
- # Compare the Rename with other relation for equality
62
- #
63
- # @example
64
- # rename.eql?(other) # => true or false
65
- #
66
- # @param [Relation] other
67
- # the other relation to compare with
68
- #
69
- # @return [Boolean]
70
- #
71
- # @api public
72
- def eql?(other)
73
- super && aliases.eql?(other.aliases)
74
- end
75
-
76
- # Return the hash of the rename
77
- #
78
- # @example
79
- # hash = rename.hash
80
- #
81
- # @return [Fixnum]
82
- #
83
- # @api public
84
- def hash
85
- super ^ aliases.hash
86
- end
87
-
88
63
  module Methods
89
64
 
90
65
  # Return a relation with the header renamed
@@ -106,8 +81,6 @@ module Veritas
106
81
 
107
82
  Relation.class_eval { include Methods }
108
83
 
109
- memoize :hash
110
-
111
84
  end # class Rename
112
85
  end # module Algebra
113
86
  end # module Veritas
@@ -7,6 +7,8 @@ module Veritas
7
7
  class Restriction < Relation
8
8
  include Relation::Operation::Unary
9
9
 
10
+ compare :operand, :predicate
11
+
10
12
  # The predicate for the relation
11
13
  #
12
14
  # @return [Function, #call]
@@ -51,33 +53,6 @@ module Veritas
51
53
  self
52
54
  end
53
55
 
54
- # Compare the Restriction with other relation for equality
55
- #
56
- # @example
57
- # restriction.eql?(other) # => true or false
58
- #
59
- # @param [Relation] other
60
- # the other relation to compare with
61
- #
62
- # @return [Boolean]
63
- #
64
- # @api public
65
- def eql?(other)
66
- super && predicate.eql?(other.predicate)
67
- end
68
-
69
- # Return the hash of the restriction
70
- #
71
- # @example
72
- # hash = restriction.hash
73
- #
74
- # @return [Fixnum]
75
- #
76
- # @api public
77
- def hash
78
- super ^ predicate.hash
79
- end
80
-
81
56
  module Methods
82
57
 
83
58
  # Return a relation with restricted tuples
@@ -106,8 +81,6 @@ module Veritas
106
81
 
107
82
  Relation.class_eval { include Methods }
108
83
 
109
- memoize :hash
110
-
111
84
  end # class Restriction
112
85
  end # module Algebra
113
86
  end # module Veritas