query-interface-server 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
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