query-interface-server 0.1.3 → 0.1.4

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fed8b7439d3f2e04a839c1ba53a70b7571a90d17
4
- data.tar.gz: 3baa596556cff58beee39a24b581694ea5a8166c
3
+ metadata.gz: 31d192d0acccf634f378134910fae9a2d0856aa2
4
+ data.tar.gz: d777536d9062e1dfd91017e6749ae92303bd4a21
5
5
  SHA512:
6
- metadata.gz: 0dcbd75eff1e6b87cf0865e28a36596fa313f6661af0cc7573c8974544689820e75d96fe9c6b9277eb059719a47fec8489030ffeef1b36a78e14db316c8fece2
7
- data.tar.gz: 2e37f8e37a7e9fb64a771d650dd231d8c70fd2112e9afbe483eacbe7fa790b29d1d2617a120b329f9001c2dafd4b273746e4ca2ba6e4ae5061bacd92379ec2b3
6
+ metadata.gz: 6f5c49b92e0edc9ab581facf8e74e3f7051e56bd6060fa427baf56378bc38bb23d12b1560b85eadd1cd2ba02a8699920d4b192966173e837c39d9571189fb8e7
7
+ data.tar.gz: 89a73932e4564bb2584de61f094934846dd524cb7f2579604fc812ecb13fe3dae53bc28989f180649bf3b7a4deb96be313c077d80cef75c5a962c06819c8fa66
@@ -1,3 +1,6 @@
1
1
  require 'sequel'
2
2
 
3
3
  require 'query-interface-server/resource'
4
+ require 'query-interface-server/lazy_query'
5
+ require 'query-interface-server/transformations'
6
+ require 'query-interface-server/transformations/sequel_transformer'
@@ -0,0 +1,120 @@
1
+ module QueryInterface
2
+ module Server
3
+ class LazyQuery
4
+
5
+ attr_accessor :model, :result_model, :transformations
6
+
7
+ def initialize(model, transformations=nil, result_model=nil)
8
+ self.model = model
9
+ if transformations
10
+ self.transformations = transformations.map {|item| item.dup}
11
+ else
12
+ self.transformations = []
13
+ end
14
+ self.result_model = result_model
15
+ end
16
+
17
+ def parse(data)
18
+ (self.result_model ? self.result_model.parse(data) : self.model.parse(data))
19
+ end
20
+
21
+ def instantiate(data)
22
+ (self.result_model ? self.result_model.new(data) : self.model.new(data))
23
+ end
24
+
25
+ def instantiate_collection(parsed_data)
26
+ (self.result_model ? self.result_model.new_collection(parsed_data) : self.model.new_collection(parsed_data))
27
+ end
28
+
29
+ def copy(options = {})
30
+ self.class.new(self.model, self.transformations, self.result_model)
31
+ end
32
+
33
+ def add_transformation(type, parameter=nil)
34
+ self.transformations << {'transformation' => type, 'parameter' => parameter}
35
+ end
36
+
37
+ def filter(conditions={})
38
+ self.copy.tap do |query|
39
+ conditions.each do |key, value|
40
+ query.add_transformation("filter", {"field" => key, "value" => value})
41
+ end
42
+ end
43
+ end
44
+
45
+ def instance(id)
46
+ self.copy.tap do |query|
47
+ query.add_transformation("instance", id)
48
+ end
49
+ end
50
+
51
+ def context(association, model=nil)
52
+ self.copy.tap do |query|
53
+ query.result_model = (model ? model : association.to_s.singularize.camelize.constantize)
54
+ query.add_transformation("context", association.to_s)
55
+ end
56
+ end
57
+
58
+ def with(*fields)
59
+ self.copy.tap do |query|
60
+ fields.each do |field|
61
+ query.add_transformation("with", field.to_s)
62
+ end
63
+ end
64
+ end
65
+
66
+ def order(*fields)
67
+ self.copy.tap do |query|
68
+ fields.each do |field|
69
+ query.add_transformation("order", field)
70
+ end
71
+ end
72
+ end
73
+
74
+ def evaluate
75
+ self.do_query
76
+ end
77
+
78
+ def ids
79
+ query = self.copy
80
+ query.add_transformation("map_ids")
81
+ query.do_query
82
+ end
83
+
84
+ def count
85
+ query = self.copy
86
+ query.add_transformation("count")
87
+ query.do_query
88
+ end
89
+
90
+ def do_query
91
+ transformer = Transformations::SequelTransformer.new(self.model.filter)
92
+ transformer.run(self.transformations)
93
+ end
94
+
95
+ def first(*args)
96
+ one("first", *args)
97
+ end
98
+
99
+ def last(*args)
100
+ one("last", *args)
101
+ end
102
+
103
+ def to_json(*args)
104
+ evaluate.to_json(*args)
105
+ end
106
+
107
+ def method_missing(method_name, *args, &block)
108
+ evaluate.send(method_name, *args, &block)
109
+ end
110
+
111
+ protected
112
+
113
+ def one(which, params = {})
114
+ query = self.copy
115
+ query.add_transformation(which)
116
+ query.do_query
117
+ end
118
+ end
119
+ end
120
+ end
@@ -11,121 +11,14 @@ module QueryInterface
11
11
  end
12
12
  end
13
13
 
14
- class UnknownTransformation < Exception; end
15
- class InvalidContextException < Exception; end
16
-
17
14
  module InstanceMethods
18
-
19
- attr_writer :context_type
20
- attr_accessor :context
21
-
22
- def validate_transformation(transformation)
23
- methods = {
24
- filter: {method: :filter_transformation, result: :dataset, accepts: :dataset},
25
- with: {method: :with_transformation, result: :dataset, accepts: :dataset},
26
- order: {method: :order_transformation, result: :dataset, accepts: :dataset},
27
- instance: {method: :instance_transformation, result: :instance, accepts: :dataset},
28
- context: {method: :context_transformation, result: :dataset, accepts: :instance},
29
- map_ids: {method: :map_ids, result: :ids, accepts: :dataset},
30
- paginate: {method: :paginate, result: :page, accepts: :dataset},
31
- first: {method: :first, result: :instance, accepts: :dataset},
32
- last: {method: :last, result: :instance, accepts: :dataset},
33
- count: {method: :count, result: :count, accepts: :dataset}
34
- }
35
- argument_method = transformation['transformation'].to_sym
36
- raise UnknownTransformation, "#{argument_method}" unless methods.has_key?(argument_method)
37
- param = transformation['parameter']
38
- description = methods[argument_method]
39
- raise InvalidContextException, "expected: #{description[:accepts]}, got: #{self.context_type}" unless self.context_type == description[:accepts]
40
- return [description[:method], param, description[:result]]
41
- end
42
-
43
- def context_type
44
- @context_type ||= :dataset
45
- end
46
-
47
- def id_selector
48
- primary_key = self.context.model.primary_key ? self.context.model.primary_key : :id
49
- "#{self.context.model.table_name}__#{primary_key}".to_sym
50
- end
51
-
52
- def query_send(method_name, *args)
53
- if respond_to?(method_name)
54
- send(method_name, *args)
55
- elsif self.context.respond_to?(method_name)
56
- self.context.send(method_name, *args)
57
- elsif block_given?
58
- yield(*args)
59
- else
60
- raise Exception, "method #{method_name} not found"
61
- end
62
- end
63
-
64
- def default_order
65
- order_transformation(self.id_selector.to_s)
66
- end
67
-
68
- def filter_transformation(param)
69
- self.query_send("filter_#{param['field']}", param['value'])
70
- end
71
-
72
- def with_transformation(param)
73
- self.query_send("with_#{param}")
74
- end
75
-
76
- def order_transformation(param)
77
- field = param
78
- direction = :asc
79
- if field.starts_with?('-')
80
- field = field[1..-1]
81
- direction = :desc
82
- end
83
- query_send("order_#{field}_#{direction}") do
84
- self.context.order_append(Sequel.send(direction, field.to_sym))
85
- end
86
- end
87
-
88
- def instance_transformation(param)
89
- self.context.filter(self.id_selector => param).first
90
- end
91
-
92
- def context_transformation(param)
93
- context = query_send("#{param}_dataset")
94
- context.select_all(context.model.table_name)
95
- end
96
-
97
- def map_ids(param)
98
- default_order.select(self.id_selector).map(&:id)
99
- end
100
-
101
- def count(param)
102
- {count: self.context.count}
103
- end
104
-
105
- def paginate(param)
106
- context = default_order
107
- {total: context.count, objects: context.paginate(param['page'].to_i, param['per_page'].to_i)}
108
- end
109
-
110
- def first(param)
111
- default_order.first
112
- end
113
-
114
- def last(param)
115
- default_order.last
116
- end
117
-
118
15
  def query
119
- @context = query_model.filter.select_all(query_model.table_name)
16
+ transformer = Transformations::SequelTransformer.new(self.query_model.filter)
120
17
  transformations = params[:transformations] || []
121
18
  transformations = JSON.parse(transformations) unless transformations.is_a?(Array)
122
- transformations.each do |transformation|
123
- method, param, self.context_type = self.validate_transformation(transformation)
124
- self.context = self.send(method, param)
125
- end
126
- self.context = self.default_order if self.context_type == :dataset
127
- unless self.context.nil?
128
- respond_with(self.context)
19
+ result = transformer.run(transformations)
20
+ unless result.nil?
21
+ respond_with(result)
129
22
  else
130
23
  render text: "", status: :not_found
131
24
  end
@@ -0,0 +1,75 @@
1
+ module QueryInterface
2
+ module Server
3
+ module Transformations
4
+
5
+ def self.included(base)
6
+ base.extend(ClassMethods)
7
+ base.dataset_module do
8
+ def query_transformation(type, name, *args)
9
+ block = model.instance_variable_get(:@query_transformations)[type][name]
10
+ if block
11
+ self.instance_exec(*args, &block)
12
+ elsif type == :order and args.count == 1
13
+ self.order_append(Sequel.send(args[0], name.to_sym))
14
+ else
15
+ raise "No #{type} implementation for #{name}"
16
+ end
17
+ end
18
+ end
19
+ base.instance_variable_set(:@query_transformations, {
20
+ filter: {},
21
+ with: {},
22
+ order: {},
23
+ })
24
+ end
25
+
26
+ module ClassMethods
27
+ def query_transformations(&block)
28
+ scope = TransformationScope.new
29
+ scope.instance_eval(&block)
30
+
31
+ @query_transformations[:filter].merge!(scope.filters)
32
+ @query_transformations[:with].merge!(scope.withs)
33
+ @query_transformations[:order].merge!(scope.orders)
34
+ end
35
+
36
+ def query
37
+ return QueryInterface::Server::LazyQuery.new(self)
38
+ end
39
+
40
+ end
41
+
42
+ class TransformationScope
43
+ attr_accessor :filters, :withs, :orders
44
+
45
+ def initialize
46
+ self.filters = {}
47
+ self.withs = {}
48
+ self.orders = {}
49
+ end
50
+
51
+ def auto_filter(*names)
52
+ names.each do |name|
53
+ self.filters[name] = Proc.new do |param|
54
+ field = "#{model.table_name}__#{name}".to_sym
55
+ filter(field => param)
56
+ end
57
+ end
58
+ end
59
+
60
+ def filter(name, &block)
61
+ self.filters[name] = block
62
+ end
63
+
64
+ def with(name, &block)
65
+ self.withs[name] = block
66
+ end
67
+
68
+ def order(name, &block)
69
+ self.orders[name] = block
70
+ end
71
+ end
72
+
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,111 @@
1
+ module QueryInterface
2
+ module Server
3
+ module Transformations
4
+ class SequelTransformer
5
+ attr_accessor :model, :result
6
+
7
+ def initialize(dataset)
8
+ self.result = dataset.select_all(dataset.model.table_name)
9
+ end
10
+
11
+ def run(transformations)
12
+ transformations.each do |transformation|
13
+ method, param = self.validate(transformation)
14
+ self.result = self.send(method, param)
15
+ end
16
+ (self.result_type == :collection ? self.default_order : self.result)
17
+ end
18
+
19
+ def result_type
20
+ if self.result.is_a?(Sequel::Dataset)
21
+ :collection
22
+ elsif self.result.is_a?(Sequel::Model)
23
+ :instance
24
+ else
25
+ :atomic
26
+ end
27
+ end
28
+
29
+ def validate(transformation)
30
+ contraints = {
31
+ filter: :collection, with: :collection,order: :collection,
32
+ instance: :collection, context: :instance, map_ids: :collection,
33
+ paginate: :collection, first: :collection, last: :collection, count: :collection
34
+ }
35
+ method = transformation['transformation'].to_sym
36
+ raise UnknownTransformation, "#{method}" unless contraints.has_key?(method)
37
+ param = transformation['parameter']
38
+ unless self.result_type == contraints[method]
39
+ raise InvalidContextException, "expected: #{description[:accepts]}, got: #{self.result_type}"
40
+ end
41
+ return [method, param]
42
+ end
43
+
44
+ def table
45
+ self.result.model.table_name
46
+ end
47
+
48
+ def default_order
49
+ self.order(self.result.model.primary_key.to_s)
50
+ end
51
+
52
+ def id_selector
53
+ primary_key = self.result.model.primary_key ? self.result.model.primary_key : :id
54
+ "#{self.result.model.table_name}__#{primary_key}".to_sym
55
+ end
56
+
57
+ def filter(param)
58
+ self.result.query_transformation(:filter, param['field'].to_sym, param['value'])
59
+ end
60
+
61
+ def with(param)
62
+ self.result.query_transformation(:with, param.to_sym)
63
+ end
64
+
65
+ def order(param)
66
+ direction = :asc
67
+ if param.starts_with?('-')
68
+ param = param[1..-1]
69
+ direction = :desc
70
+ end
71
+ self.result.query_transformation(:order, param.to_sym, direction)
72
+ end
73
+
74
+ def instance(param)
75
+ self.result.filter(self.id_selector => param).first
76
+ end
77
+
78
+ def context(param)
79
+ name = "#{param}_dataset"
80
+ if self.result.respond_to?(name)
81
+ result = self.result.send(name)
82
+ else
83
+ raise Exception, "method #{name} not found"
84
+ end
85
+ result.select_all(result.model.table_name)
86
+ end
87
+
88
+ def map_ids(param)
89
+ self.default_order.select(self.id_selector).map(&:id)
90
+ end
91
+
92
+ def count(param)
93
+ {count: self.result.count}
94
+ end
95
+
96
+ def paginate(param)
97
+ context = self.default_order
98
+ {total: context.count, objects: context.paginate(param['page'].to_i, param['per_page'].to_i)}
99
+ end
100
+
101
+ def first(param)
102
+ self.default_order.first
103
+ end
104
+
105
+ def last(param)
106
+ self.default_order.last
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
@@ -1,7 +1,7 @@
1
1
  module QueryInterface
2
2
  module Server
3
3
 
4
- VERSION = '0.1.3'
4
+ VERSION = '0.1.4'
5
5
 
6
6
  end
7
7
  end
@@ -0,0 +1,50 @@
1
+ require "spec_helper"
2
+
3
+ describe QueryInterface::Server::Resource, type: :controller do
4
+
5
+ class Foo
6
+ end
7
+
8
+ controller(ActionController::Base) do
9
+ respond_to :json
10
+ include QueryInterface::Server::Resource.for(Foo)
11
+ end
12
+
13
+ context 'self.for' do
14
+ it 'defines a query_model method' do
15
+ subject.query_model.should eq(Foo)
16
+ end
17
+
18
+ it 'includes the instance methods' do
19
+ subject.should respond_to(:query)
20
+ end
21
+ end
22
+
23
+ context "GET 'query'" do
24
+ before(:each) do
25
+ routes.draw { get "query" => "anonymous#query" }
26
+ end
27
+
28
+ it 'runs the transformations' do
29
+ dataset = double('dataset')
30
+ transformer = double('transformer')
31
+ result = double('result')
32
+ Foo.should_receive(:filter).and_return(dataset)
33
+ QueryInterface::Server::Transformations::SequelTransformer.should_receive(:new).with(dataset).and_return(transformer)
34
+ transformer.should_receive(:run).with([{'my' => 'transformations'}]).and_return(result)
35
+ get :query, transformations: [{'my' => 'transformations'}], format: :json
36
+ response.should be_success
37
+ end
38
+
39
+ it 'returns 404 when result is nil' do
40
+ dataset = double('dataset')
41
+ transformer = double('transformer')
42
+ Foo.should_receive(:filter).and_return(dataset)
43
+ QueryInterface::Server::Transformations::SequelTransformer.should_receive(:new).with(dataset).and_return(transformer)
44
+ transformer.should_receive(:run).with([{'my' => 'transformations'}]).and_return(nil)
45
+ get :query, transformations: [{'my' => 'transformations'}], format: :json
46
+ response.should be_not_found
47
+ end
48
+ end
49
+
50
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: query-interface-server
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andreas Kopecky <andreas.kopecky@radarservices.com>
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2013-10-17 00:00:00.000000000 Z
13
+ date: 2014-01-21 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: sequel
@@ -97,10 +97,13 @@ files:
97
97
  - README.md
98
98
  - Rakefile
99
99
  - lib/query-interface-server.rb
100
+ - lib/query-interface-server/lazy_query.rb
100
101
  - lib/query-interface-server/resource.rb
102
+ - lib/query-interface-server/transformations.rb
103
+ - lib/query-interface-server/transformations/sequel_transformer.rb
101
104
  - lib/query-interface-server/version.rb
102
105
  - query-interface-server.gemspec
103
- - spec/lib/query_interface_spec.rb
106
+ - spec/lib/resource_spec.rb
104
107
  - spec/spec_helper.rb
105
108
  homepage: http://github.com/rs-dev/query-interface-server
106
109
  licenses:
@@ -122,9 +125,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
122
125
  version: '0'
123
126
  requirements: []
124
127
  rubyforge_project:
125
- rubygems_version: 2.0.5
128
+ rubygems_version: 2.1.11
126
129
  signing_key:
127
130
  specification_version: 4
128
131
  summary: Server for the radar query interface
129
132
  test_files: []
130
- has_rdoc:
@@ -1,312 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe QueryInterface, type: :controller do
4
- class Foo
5
- def self.table_name
6
- :foo_table
7
- end
8
- end
9
-
10
- class Nested
11
- def self.table_name
12
- :nested_table
13
- end
14
- end
15
-
16
-
17
- controller(ActionController::Base) do
18
- respond_to :json
19
- include QueryInterface::Server::Resource.for(Foo)
20
- end
21
- let(:foo){ double("Foo instance").as_null_object }
22
- let(:foos){ double('foo instances', to_json: '{}', model: Foo) }
23
-
24
- it "provides query_model as an instance method in the base class" do
25
- controller.query_model.should == Foo
26
- end
27
-
28
- context "GET 'query'" do
29
-
30
- context "transformations" do
31
- it "only allows for a predefined list of transformations" do
32
- expect {
33
- controller.validate_transformation({'transformation' => 'bogus', 'parameter' => nil})
34
- }.to raise_error("bogus")
35
- controller.validate_transformation({'transformation' => 'with', 'parameter' => nil}).should eq([:with_transformation, nil, :dataset])
36
- end
37
-
38
- it "only allows transformations who accept the current content_type to run" do
39
- controller.context_type = :instance
40
- expect {
41
- controller.validate_transformation({'transformation' => 'with', 'parameter' => 'y'})
42
- }.to raise_error("expected: dataset, got: instance")
43
- end
44
-
45
- context "id selector" do
46
- it "creates the id selector qualified from table name and primary key" do
47
- controller.context = double('context', model: double('model', table_name: :table, primary_key: :id))
48
- controller.id_selector.should == :table__id
49
- end
50
- end
51
-
52
- context "context accessor" do
53
- it "returns the existing context" do
54
- context = double("context")
55
- controller.instance_variable_set(:@context, context)
56
- controller.context.should eq(context)
57
- end
58
-
59
- end
60
-
61
- end
62
-
63
- context "transformation methods" do
64
- let(:context) {double("context")}
65
-
66
- it "performs a filter transformation" do
67
- controller.should_receive(:query_send).with('filter_a', 'b').and_return(context)
68
- controller.filter_transformation({'field' => 'a', 'value' => 'b'}).should eq(context)
69
- end
70
-
71
- it "performs a with transformation" do
72
- controller.should_receive(:query_send).with('with_x').and_return(context)
73
- controller.with_transformation('x').should eq(context)
74
- end
75
-
76
- it "performs a instance transformation on an existing context" do
77
- id_selector = :id_selector
78
- controller.context = context
79
- controller.should_receive(:id_selector).and_return(id_selector)
80
- context.should_receive(:filter).with({id_selector => 42}).and_return(context)
81
- context.should_receive(:first).and_return(context)
82
- controller.instance_transformation(42).should eq(context)
83
- end
84
-
85
- it "performs a context transformation" do
86
- controller.should_receive(:query_send).with('context_dataset').and_return(context)
87
- context.should_receive(:model).and_return(double("model", table_name: :foo_table))
88
- context.should_receive(:select_all).with(:foo_table).and_return(context)
89
- controller.context_transformation('context').should eq(context)
90
- end
91
-
92
- context "order transformation" do
93
- it "should call query_send with order_*_* for the supplied order field" do
94
- ordered = double("ordered a")
95
- controller.should_receive(:query_send).with("order_a_asc").and_return(ordered)
96
- controller.order_transformation("a").should eq(ordered)
97
- end
98
-
99
- it "performs descending ordering if appropriate" do
100
- ordered = double("ordered a")
101
- controller.should_receive(:query_send).with("order_a_desc").and_return(ordered)
102
- controller.order_transformation("-a").should eq(ordered)
103
- end
104
-
105
- it "performs a fallback sequel ordering operation when no concrete implementation is available" do
106
- context = double("context")
107
- ordered = double("ordered a")
108
- controller.instance_variable_set(:@context, context)
109
- context.should_receive(:order_append).with(Sequel.asc(:a)).and_return(ordered)
110
- controller.order_transformation("a").should eq(ordered)
111
- end
112
-
113
- it "performs fallback for descending ordering" do
114
- context = double("context")
115
- ordered = double("ordered a")
116
- controller.instance_variable_set(:@context, context)
117
- context.should_receive(:order_append).with(Sequel.desc(:a)).and_return(ordered)
118
- controller.order_transformation("-a").should eq(ordered)
119
- end
120
- end
121
-
122
- end
123
-
124
- context "query" do
125
- before(:each) do
126
- routes.draw { get "query" => "anonymous#query" }
127
- Foo.stub(:filter).and_return(foos)
128
- Foo.stub(:primary_key).and_return(:id)
129
- controller.stub(:order_query)
130
- foos.stub(:select_all).with(:foo_table).and_return(foos)
131
- end
132
-
133
-
134
- context "transformation processing" do
135
- let(:filtered) { double('filtered').as_null_object }
136
-
137
- it "calls the corresponding methods in any transformation" do
138
- controller.should_receive(:filter_foo).with('bar').and_return(filtered)
139
- get :query,
140
- transformations: [
141
- {transformation: :filter, parameter: {field: :foo, value: 'bar'}},
142
- ], format: :json
143
- assigns(:context).should == filtered
144
- response.should be_ok
145
- end
146
-
147
- it "creates a new context if none is present" do
148
- context = double("context")
149
- controller.query_model.should_receive(:filter).and_return(foos)
150
- controller.stub(:default_order).and_return(context)
151
- foos.should_receive(:select_all).with(:foo_table).and_return(context)
152
- get :query, transformations: [], format: :json
153
- controller.context.should eq(context)
154
- assigns(:context).should eq(context)
155
- response.should be_ok
156
- end
157
-
158
- it "should respond with 404 when no result can be reached" do
159
- context = double("context")
160
- controller.query_model.should_receive(:filter).and_return(foos)
161
- controller.stub(:default_order).and_return(nil)
162
- foos.should_receive(:select_all).with(:foo_table).and_return(nil)
163
- get :query, transformations: [], format: :json
164
- controller.context.should eq(nil)
165
- assigns(:context).should eq(nil)
166
- response.should_not be_ok
167
- response.status.should eq(404)
168
- end
169
- end
170
-
171
-
172
- context "end points" do
173
-
174
- it "should return a count of instances when an 'count' transformation is given" do
175
- foos.should_receive(:count).and_return(42)
176
- get :query,
177
- transformations: [
178
- {transformation: :count, parameter: nil}
179
- ], format: :json
180
- response.should be_ok
181
- assigns(:context).should == {count: 42}
182
- end
183
-
184
- it "should return a hash with objects and total when a 'pagination' transformation is given" do
185
- controller.should_receive(:default_order).and_return(foos)
186
- foos.should_receive(:count).and_return(42)
187
- foos.should_receive(:paginate).with(1, 10).and_return('paginated')
188
- get :query,
189
- transformations: [
190
- {transformation: :paginate, parameter: {page: 1, per_page: 10}}
191
- ], format: :json
192
- response.should be_ok
193
- assigns(:context).should == {objects: 'paginated', total: 42}
194
- end
195
-
196
- it "should return a single object when a 'first' transformation is given" do
197
- controller.should_receive(:default_order).and_return(foos)
198
- foos.should_receive(:first).and_return('first object')
199
- get :query,
200
- transformations: [
201
- {transformation: :first, parameter: nil}
202
- ], format: :json
203
- assigns(:context).should == 'first object'
204
- end
205
-
206
- it "should return a single object when a 'last' transformation is given" do
207
- controller.should_receive(:default_order).and_return(foos)
208
- foos.should_receive(:last).and_return('last object')
209
- get :query,
210
- transformations: [
211
- {transformation: :last, parameter: nil}
212
- ], format: :json
213
- assigns(:context).should == 'last object'
214
- end
215
-
216
- it "should return a list of ids when a 'map_ids' transformation is given" do
217
- controller.should_receive(:default_order).and_return(foos)
218
- foos.should_receive(:select).with(:foo_table__id).and_return([double("one", id: 1), double("two", id: 2)])
219
- get :query,
220
- transformations: [
221
- {transformation: :map_ids, parameter: nil}
222
- ], format: :json
223
- assigns(:context).should == [1, 2]
224
- end
225
-
226
-
227
- end
228
- end
229
- end
230
-
231
- context "instance calls" do
232
- before(:each) do
233
- routes.draw { get "query" => "anonymous#query" }
234
- Foo.stub(:filter).and_return(foos)
235
- Foo.stub(:table_name).and_return(:foo_table)
236
- controller.stub(:order_query)
237
- end
238
-
239
- context "instance evaluation" do
240
-
241
- it "queries for the single object supplied by instance" do
242
- foos.should_receive(:select_all).with(:foo_table).and_return(foos)
243
- id_selector = double("id selector")
244
- controller.should_receive(:id_selector).and_return(id_selector)
245
- foos.should_receive(:filter).with(id_selector => 99).and_return(foos)
246
- foos.should_receive(:first).and_return(foo)
247
- get :query, transformations:
248
- [
249
- {transformation: :instance, parameter: 99},
250
- ], format: :json
251
- response.should be_ok
252
- assigns(:context).should eq(foo)
253
- end
254
-
255
- it "assigns an association dataset if a context is supplied" do
256
- foos.should_receive(:select_all).with(:foo_table).and_return(foos)
257
- id_selector = double("id selector")
258
- nested = double("nested things", model: Nested)
259
- controller.should_receive(:id_selector).and_return(id_selector)
260
- foos.should_receive(:filter).with(id_selector => 99).and_return(foos)
261
- foos.should_receive(:first).and_return(foo)
262
- controller.should_receive(:query_send).with("nested_dataset").and_return(nested)
263
- nested.should_receive(:select_all).with(:nested_table).and_return(nested)
264
- controller.should_receive(:default_order).and_return(nested)
265
- get :query, transformations:
266
- [
267
- {transformation: :instance, parameter: 99},
268
- {transformation: :context, parameter: 'nested'},
269
- ], format: :json
270
- assigns(:context).should eq(nested)
271
- response.should be_ok
272
- end
273
- end
274
- end
275
-
276
- context "query send" do
277
- let(:send_result) {double("send result")}
278
-
279
- before(:each) do
280
- @context = double("context")
281
- controller.instance_variable_set(:@context, @context)
282
- end
283
-
284
- it "should call the supplied method name on the controller if it responds to such a message" do
285
- controller.should_receive(:respond_to?).with("method_name_foo").and_return(true)
286
- controller.should_receive(:send).with("method_name_foo", "argument").and_return(send_result)
287
- controller.query_send("method_name_foo", "argument").should eq(send_result)
288
- end
289
-
290
- it "should call the supplied method name on @context if avaiable and controller doesnt provide the method" do
291
- controller.should_receive(:respond_to?).with("method_name_foo").and_return(false)
292
- @context.should_receive(:respond_to?).with("method_name_foo").and_return(true)
293
- @context.should_receive(:send).with("method_name_foo", "argument").and_return(send_result)
294
- controller.query_send("method_name_foo", "argument").should eq(send_result)
295
- end
296
-
297
- it "should yield arguments to a supplied block if neither context nor controller provide the requested method" do
298
- controller.should_receive(:respond_to?).with("method_name_foo").and_return(false)
299
- @context.should_receive(:respond_to?).with("method_name_foo").and_return(false)
300
- controller.query_send("method_name_foo", "argument") {|*args| args[0].should eq("argument")}
301
- end
302
-
303
- it "should raise an exception if non of the above can be done" do
304
- controller.should_receive(:respond_to?).with("method_name_foo").and_return(false)
305
- @context.should_receive(:respond_to?).with("method_name_foo").and_return(false)
306
- expect {
307
- controller.query_send("method_name_foo", "argument")
308
- }.to raise_error(Exception, "method method_name_foo not found")
309
- end
310
- end
311
-
312
- end