ansr 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/.gitignore +2 -0
  2. data/Gemfile +3 -0
  3. data/Gemfile.lock +127 -0
  4. data/ansr.gemspec +23 -0
  5. data/ansr_dpla/README.md +59 -0
  6. data/ansr_dpla/ansr_dpla.gemspec +27 -0
  7. data/ansr_dpla/app/models/collection.rb +2 -0
  8. data/ansr_dpla/app/models/item.rb +2 -0
  9. data/ansr_dpla/fixtures/collection.json +1 -0
  10. data/ansr_dpla/fixtures/collection.jsonld +14 -0
  11. data/ansr_dpla/fixtures/collections.json +1 -0
  12. data/ansr_dpla/fixtures/collections.jsonld +65 -0
  13. data/ansr_dpla/fixtures/dpla.yml +2 -0
  14. data/ansr_dpla/fixtures/empty.jsonld +1 -0
  15. data/ansr_dpla/fixtures/item.json +1 -0
  16. data/ansr_dpla/fixtures/item.jsonld +272 -0
  17. data/ansr_dpla/fixtures/kittens.json +1 -0
  18. data/ansr_dpla/fixtures/kittens.jsonld +2477 -0
  19. data/ansr_dpla/fixtures/kittens_faceted.json +1 -0
  20. data/ansr_dpla/fixtures/kittens_faceted.jsonld +2693 -0
  21. data/ansr_dpla/lib/ansr_dpla.rb +6 -0
  22. data/ansr_dpla/lib/ansr_dpla/api.rb +78 -0
  23. data/ansr_dpla/lib/ansr_dpla/arel.rb +8 -0
  24. data/ansr_dpla/lib/ansr_dpla/arel/big_table.rb +104 -0
  25. data/ansr_dpla/lib/ansr_dpla/arel/connection.rb +81 -0
  26. data/ansr_dpla/lib/ansr_dpla/arel/query_builder.rb +131 -0
  27. data/ansr_dpla/lib/ansr_dpla/model.rb +7 -0
  28. data/ansr_dpla/lib/ansr_dpla/model/base.rb +17 -0
  29. data/ansr_dpla/lib/ansr_dpla/model/pseudo_associate.rb +14 -0
  30. data/ansr_dpla/lib/ansr_dpla/model/querying.rb +38 -0
  31. data/ansr_dpla/spec/adpla_test_api.rb +9 -0
  32. data/ansr_dpla/spec/lib/api_spec.rb +110 -0
  33. data/ansr_dpla/spec/lib/item_spec.rb +57 -0
  34. data/ansr_dpla/spec/lib/relation/facet_spec.rb +74 -0
  35. data/ansr_dpla/spec/lib/relation/select_spec.rb +52 -0
  36. data/ansr_dpla/spec/lib/relation/where_spec.rb +74 -0
  37. data/ansr_dpla/spec/lib/relation_spec.rb +305 -0
  38. data/ansr_dpla/spec/spec_helper.rb +36 -0
  39. data/ansr_dpla/test/debug.rb +14 -0
  40. data/ansr_dpla/test/system.rb +50 -0
  41. data/lib/ansr.rb +16 -0
  42. data/lib/ansr/.DS_Store +0 -0
  43. data/lib/ansr/arel.rb +5 -0
  44. data/lib/ansr/arel/big_table.rb +24 -0
  45. data/lib/ansr/base.rb +29 -0
  46. data/lib/ansr/configurable.rb +20 -0
  47. data/lib/ansr/model.rb +159 -0
  48. data/lib/ansr/model/connection.rb +103 -0
  49. data/lib/ansr/model/connection_handler.rb +20 -0
  50. data/lib/ansr/relation.rb +121 -0
  51. data/lib/ansr/relation/arel_methods.rb +14 -0
  52. data/lib/ansr/relation/query_methods.rb +156 -0
  53. data/lib/ansr/sanitization.rb +36 -0
  54. data/lib/ansr/version.rb +6 -0
  55. metadata +196 -0
@@ -0,0 +1,20 @@
1
+ module Ansr
2
+ module Model
3
+ class ConnectionHandler
4
+ def initialize(connection_class)
5
+ @connection_class = connection_class
6
+ end
7
+ def retrieve_connection(klass)
8
+ @connection_class.new(klass)
9
+ end
10
+
11
+ def retrieve_connection_pool(klass)
12
+ retrieve_connection(klass)
13
+ end
14
+
15
+ def connected?(klass)
16
+ true
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,121 @@
1
+ require 'yaml'
2
+ require 'blacklight'
3
+ module Ansr
4
+ class Relation < ::ActiveRecord::Relation
5
+ attr_accessor :filters, :count, :context, :resource
6
+
7
+ DEFAULT_PAGE_SIZE = 10
8
+
9
+ include Sanitization::ClassMethods
10
+ include QueryMethods
11
+
12
+ def initialize(klass, table, values = {})
13
+ raise "Cannot search nil model" if klass.nil?
14
+ super(klass, table, values)
15
+ end
16
+
17
+ def resource
18
+ rsrc = @klass.name.downcase
19
+ rsrc << ((rsrc =~ /s$/) ? 'es' : 's')
20
+ rsrc.to_sym
21
+ end
22
+
23
+ def load
24
+ exec_queries unless loaded?
25
+ self
26
+ end
27
+
28
+ # Converts relation objects to Array.
29
+ def to_a
30
+ load
31
+ @records
32
+ end
33
+
34
+ # Forces reloading of relation.
35
+ def reload
36
+ reset
37
+ load
38
+ end
39
+
40
+ def empty?
41
+ count == 0
42
+ end
43
+
44
+ def many?
45
+ count > 1
46
+ end
47
+
48
+ def offset!(value)
49
+ page_size = self.limit_value || DEFAULT_PAGE_SIZE
50
+ if (value.to_i % page_size.to_i) != 0
51
+ raise "Bad offset #{value} for page size #{page_size}"
52
+ end
53
+ self.offset_value=value
54
+ self
55
+ end
56
+
57
+ def count
58
+ self.load
59
+ @response['count']
60
+ end
61
+
62
+ def filters
63
+ if loaded?
64
+ @filter_cache ||= begin
65
+ f = {}
66
+ (@response['facets'] || {}).inject(f) do |h,(k,v)|
67
+ if v['total'] = 0
68
+ items = v['terms'].collect do |term|
69
+ Blacklight::SolrResponse::Facets::FacetItem.new(:value => term['term'], :hits => term['count'])
70
+ end
71
+ options = {:sort => 'asc', :offset => 0}
72
+ h[k] = Blacklight::SolrResponse::Facets::FacetField.new k, items, options
73
+ end
74
+ h
75
+ end
76
+ f
77
+ end
78
+ else
79
+ @filter_cache ||= begin
80
+ query = self.limit(0)
81
+ query.load
82
+ query.filters
83
+ end
84
+ end
85
+ end
86
+
87
+ def spawn
88
+ s = self.class.new(@klass, @table, @values.dup)
89
+ s.references!(references_values())
90
+ s
91
+ end
92
+
93
+ private
94
+
95
+
96
+ def exec_queries
97
+ default_scoped = with_default_scope
98
+
99
+ if default_scoped.equal?(self)
100
+ @response = model.find_by_nosql(arel, bind_values)
101
+ @records = (@response['docs'] || []).collect do |d|
102
+ model.new(d)
103
+ end
104
+
105
+ # this is ceremonial, it's always true
106
+ readonly = readonly_value.nil? || readonly_value
107
+ @records.each { |record| record.readonly! } if readonly
108
+ else
109
+ @records = default_scoped.to_a
110
+ end
111
+
112
+ self.limit_value = DEFAULT_PAGE_SIZE unless self.limit_value
113
+ self.offset_value = 0 unless self.offset_value
114
+ @filter_cache = nil # unload any cached filters
115
+ @loaded = true
116
+ @records
117
+ end
118
+ end
119
+
120
+
121
+ end
@@ -0,0 +1,14 @@
1
+ module Ansr
2
+ module ArelMethods
3
+ # Returns the Arel object associated with the relation.
4
+ # duplicated to respect access control
5
+ def arel # :nodoc:
6
+ @arel ||= build_arel
7
+ end
8
+
9
+ def arel_table
10
+ model().table
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,156 @@
1
+ require 'active_record'
2
+ module Ansr
3
+ module QueryMethods
4
+ include Ansr::Configurable
5
+ include ActiveRecord::QueryMethods
6
+
7
+ ActiveRecord::QueryMethods::WhereChain.class_eval <<-RUBY
8
+ def or(opts, *rest)
9
+ where_value = @scope.send(:build_where, opts, rest).map do |rel|
10
+ case rel
11
+ when ::Arel::Nodes::In
12
+ next rel
13
+ when ::Arel::Nodes::Equality
14
+ # ::Arel::Nodes::OrEqual.new(rel.left, rel.right)
15
+ ::Arel::Nodes::Or.new(rel.left, rel.right)
16
+ when String
17
+ ::Arel::Nodes::Or.new(::Arel::Nodes::SqlLiteral.new(rel))
18
+ else
19
+ ::Arel::Nodes::Or.new(rel)
20
+ end
21
+ end
22
+ @scope.where_values += where_value.flatten
23
+ @scope
24
+ end
25
+ RUBY
26
+
27
+
28
+ def filter_values
29
+ @values[:filter] ||= []
30
+ end
31
+
32
+ def filter_values=(values)
33
+ raise ImmutableRelation if @loaded
34
+ @values[:filter] = values
35
+ end
36
+
37
+ def filter(args)
38
+ check_if_method_has_arguments!("filter", args)
39
+ spawn.filter!(args)
40
+ end
41
+
42
+ def filter!(args)
43
+ return self if args.empty?
44
+
45
+ filter_where = build_filter(args)
46
+ return self unless filter_where
47
+ filter_name = filter_name(filter_where)
48
+ if (filter_name)
49
+ @klass = @klass.view(*filter_where)
50
+ model().projections += Array(filter_name)
51
+ end
52
+
53
+ self
54
+ end
55
+
56
+ def filter_name(expr)
57
+ connection.sanitize_filter_name(field_name(expr))
58
+ end
59
+
60
+ def field_name(expr)
61
+ if expr.is_a? Array
62
+ return expr.collect{|x| field_name(x)}.compact
63
+ else
64
+ case expr
65
+ when ::Arel::Nodes::Binary
66
+ if expr.left.relation.name != model().name
67
+ # oof, this is really hacky
68
+ field_name = "#{expr.left.relation.name}.#{expr.left.name}".to_sym
69
+ else
70
+ field_name = expr.left.name.to_sym
71
+ end
72
+ when ::Arel::Attributes::Attribute
73
+ if expr.relation.name != model().name
74
+ # oof, this is really hacky
75
+ field_name = "#{expr.relation.name}.#{expr.name}".to_sym
76
+ else
77
+ field_name = expr.name.to_sym
78
+ end
79
+ when ::Arel::Nodes::Unary
80
+ if expr.expr.relation.name != model().name
81
+ # oof, this is really hacky
82
+ field_name = "#{expr.expr.relation.name}.#{expr.expr.name}".to_sym
83
+ else
84
+ field_name = expr.expr.name.to_sym
85
+ end
86
+ else
87
+ field_name = expr.to_sym
88
+ end
89
+ return field_name
90
+ end
91
+ end
92
+
93
+ def all_filter_fields
94
+ FACETS
95
+ end
96
+
97
+ def all_sort_fields
98
+ SORTS
99
+ end
100
+
101
+ def find(id)
102
+ klass = model()
103
+ rel = klass.build_default_scope.where(klass.table.primary_key.name => id).limit(1)
104
+ rel.to_a
105
+ unless rel.to_a[0]
106
+ raise 'Bad ID'
107
+ end
108
+ rel.to_a.first
109
+ end
110
+
111
+ def collapse_wheres(arel, wheres)
112
+ predicates = wheres.map do |where|
113
+ next where if ::Arel::Nodes::Equality === where
114
+ where if String === where
115
+ ::Arel::Nodes::Grouping.new(where)
116
+ end
117
+
118
+ arel.where(::Arel::Nodes::And.new(predicates)) if predicates.present?
119
+ end
120
+
121
+ # cloning from ActiveRecord::QueryMethods.build_where as a first pass
122
+ def build_filter(opts, other=[])
123
+ case opts
124
+ when String, Array
125
+ #TODO: Remove duplication with: /activerecord/lib/active_record/sanitization.rb:113
126
+ values = Hash === other.first ? other.first.values : other
127
+
128
+ values.grep(ActiveRecord::Relation) do |rel|
129
+ self.bind_values += rel.bind_values
130
+ end
131
+ opts = (other.empty? ? opts : ([opts] + other))
132
+ [model().send(:sanitize_sql, opts, model().table_name)]
133
+ when Hash
134
+ attributes = model().send(:expand_hash_conditions_for_sql_aggregates, opts)
135
+
136
+ attributes.keys.each do |k|
137
+ sk = filter_name(k)
138
+ attributes[sk] = attributes.delete(k) unless sk.eql? k.to_s
139
+ end
140
+ attributes.values.grep(ActiveRecord::Relation) do |rel|
141
+ self.bind_values += rel.bind_values
142
+ end
143
+
144
+ ActiveRecord::PredicateBuilder.build_from_hash(model(), attributes, model().table)
145
+ else
146
+ [opts]
147
+ end
148
+ end
149
+
150
+ def find_by_nosql(arel, bind_values)
151
+ query = model.connection.to_nosql(arel, bind_values)
152
+ aliases = model.connection.to_aliases(arel, bind_values)
153
+ model.connection.execute(query, aliases)
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,36 @@
1
+ module Ansr
2
+ module Sanitization
3
+ extend ActiveSupport::Concern
4
+ module ClassMethods
5
+ def reflect_on_association(column_sym)
6
+ DummyReflection.new(column_sym)
7
+ end
8
+
9
+ def expand_hash_conditions_for_sql_aggregates(conditions)
10
+ conditions
11
+ end
12
+
13
+ def sanitize_sql_for_conditions(condition, table_name = table_name())
14
+ condition
15
+ end
16
+
17
+ def sanitize_sql(condition, table_name = table_name())
18
+ sanitize_sql_for_conditions(condition, table_name)
19
+ end
20
+
21
+ end
22
+ class DummyReflection
23
+ def initialize(symbol)
24
+ @symbol = symbol
25
+ end
26
+
27
+ def polymorphic?
28
+ false
29
+ end
30
+
31
+ def foreign_key
32
+ @symbol
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,6 @@
1
+ module Ansr
2
+ VERSION = '0.0.1'
3
+ def self.version
4
+ VERSION
5
+ end
6
+ end
metadata ADDED
@@ -0,0 +1,196 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ansr
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Benjamin Armintor
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-03-13 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: loggable
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: blacklight
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: 5.1.0
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: 5.1.0
46
+ - !ruby/object:Gem::Dependency
47
+ name: rake
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: bundler
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: 1.0.14
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: 1.0.14
78
+ - !ruby/object:Gem::Dependency
79
+ name: rspec
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: yard
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ description: Wrapping the no-sql data sources in Rails-like models and relations
111
+ email:
112
+ - armintor@gmail.com
113
+ executables: []
114
+ extensions: []
115
+ extra_rdoc_files: []
116
+ files:
117
+ - .gitignore
118
+ - Gemfile
119
+ - Gemfile.lock
120
+ - ansr.gemspec
121
+ - ansr_dpla/README.md
122
+ - ansr_dpla/ansr_dpla.gemspec
123
+ - ansr_dpla/app/models/collection.rb
124
+ - ansr_dpla/app/models/item.rb
125
+ - ansr_dpla/fixtures/collection.json
126
+ - ansr_dpla/fixtures/collection.jsonld
127
+ - ansr_dpla/fixtures/collections.json
128
+ - ansr_dpla/fixtures/collections.jsonld
129
+ - ansr_dpla/fixtures/dpla.yml
130
+ - ansr_dpla/fixtures/empty.jsonld
131
+ - ansr_dpla/fixtures/item.json
132
+ - ansr_dpla/fixtures/item.jsonld
133
+ - ansr_dpla/fixtures/kittens.json
134
+ - ansr_dpla/fixtures/kittens.jsonld
135
+ - ansr_dpla/fixtures/kittens_faceted.json
136
+ - ansr_dpla/fixtures/kittens_faceted.jsonld
137
+ - ansr_dpla/lib/ansr_dpla.rb
138
+ - ansr_dpla/lib/ansr_dpla/api.rb
139
+ - ansr_dpla/lib/ansr_dpla/arel.rb
140
+ - ansr_dpla/lib/ansr_dpla/arel/big_table.rb
141
+ - ansr_dpla/lib/ansr_dpla/arel/connection.rb
142
+ - ansr_dpla/lib/ansr_dpla/arel/query_builder.rb
143
+ - ansr_dpla/lib/ansr_dpla/model.rb
144
+ - ansr_dpla/lib/ansr_dpla/model/base.rb
145
+ - ansr_dpla/lib/ansr_dpla/model/pseudo_associate.rb
146
+ - ansr_dpla/lib/ansr_dpla/model/querying.rb
147
+ - ansr_dpla/spec/adpla_test_api.rb
148
+ - ansr_dpla/spec/lib/api_spec.rb
149
+ - ansr_dpla/spec/lib/item_spec.rb
150
+ - ansr_dpla/spec/lib/relation/facet_spec.rb
151
+ - ansr_dpla/spec/lib/relation/select_spec.rb
152
+ - ansr_dpla/spec/lib/relation/where_spec.rb
153
+ - ansr_dpla/spec/lib/relation_spec.rb
154
+ - ansr_dpla/spec/spec_helper.rb
155
+ - ansr_dpla/test/debug.rb
156
+ - ansr_dpla/test/system.rb
157
+ - lib/ansr.rb
158
+ - lib/ansr/.DS_Store
159
+ - lib/ansr/arel.rb
160
+ - lib/ansr/arel/big_table.rb
161
+ - lib/ansr/base.rb
162
+ - lib/ansr/configurable.rb
163
+ - lib/ansr/model.rb
164
+ - lib/ansr/model/connection.rb
165
+ - lib/ansr/model/connection_handler.rb
166
+ - lib/ansr/relation.rb
167
+ - lib/ansr/relation/arel_methods.rb
168
+ - lib/ansr/relation/query_methods.rb
169
+ - lib/ansr/sanitization.rb
170
+ - lib/ansr/version.rb
171
+ homepage: http://github.com/barmintor/ansr
172
+ licenses: []
173
+ post_install_message:
174
+ rdoc_options: []
175
+ require_paths:
176
+ - lib
177
+ required_ruby_version: !ruby/object:Gem::Requirement
178
+ none: false
179
+ requirements:
180
+ - - ! '>='
181
+ - !ruby/object:Gem::Version
182
+ version: '0'
183
+ required_rubygems_version: !ruby/object:Gem::Requirement
184
+ none: false
185
+ requirements:
186
+ - - ! '>='
187
+ - !ruby/object:Gem::Version
188
+ version: '0'
189
+ requirements: []
190
+ rubyforge_project:
191
+ rubygems_version: 1.8.24
192
+ signing_key:
193
+ specification_version: 3
194
+ summary: ActiveRecord-style relations for no-sql data sources
195
+ test_files: []
196
+ has_rdoc: