ansr 0.0.1

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 (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: