pggraphql 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d1e6b2c6fed6ff27d8df6c047a1a7a00da92d82b
4
+ data.tar.gz: fae12d3c2d83579341ca9d9703bef24c89db4808
5
+ SHA512:
6
+ metadata.gz: fee51a6659a3b61afb46cb3f435450214c1b7a878dc625362b8a1f0196e1e14a7f1d402f1a458fe9625279518bdf4aef6ff45e30287a431c15e96d75c769b571
7
+ data.tar.gz: e8bd53a6028edf19f10a4db5524cc03a2f3fcef3acf027260abb0e97b49b8cbc02956b7dd5bf41ed17ced8bbe325b4bc5fdd8633beb1fe0a22e71c2d6681fc96
data/.gitignore ADDED
@@ -0,0 +1,34 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /test/tmp/
9
+ /test/version_tmp/
10
+ /tmp/
11
+
12
+ ## Specific to RubyMotion:
13
+ .dat*
14
+ .repl_history
15
+ build/
16
+
17
+ ## Documentation cache and generated files:
18
+ /.yardoc/
19
+ /_yardoc/
20
+ /doc/
21
+ /rdoc/
22
+
23
+ ## Environment normalisation:
24
+ /.bundle/
25
+ /lib/bundler/man/
26
+
27
+ # for a library or gem, you might want to ignore these files since the code is
28
+ # intended to run in multiple environments; otherwise, check them in:
29
+ # Gemfile.lock
30
+ # .ruby-version
31
+ # .ruby-gemset
32
+
33
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
34
+ .rvmrc
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in pggraphql.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,35 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ pggraphql (0.0.1)
5
+ activesupport
6
+ json
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ activesupport (4.2.0)
12
+ i18n (~> 0.7)
13
+ json (~> 1.7, >= 1.7.7)
14
+ minitest (~> 5.1)
15
+ thread_safe (~> 0.3, >= 0.3.4)
16
+ tzinfo (~> 1.1)
17
+ i18n (0.7.0)
18
+ json (1.8.2)
19
+ minitest (5.5.1)
20
+ power_assert (0.2.2)
21
+ rake (10.4.2)
22
+ test-unit (3.0.8)
23
+ power_assert
24
+ thread_safe (0.3.4)
25
+ tzinfo (1.2.2)
26
+ thread_safe (~> 0.1)
27
+
28
+ PLATFORMS
29
+ ruby
30
+
31
+ DEPENDENCIES
32
+ bundler (~> 1.7)
33
+ pggraphql!
34
+ rake (~> 10.0)
35
+ test-unit
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Jan Zimmek
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Jan Zimmek
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,2 @@
1
+ # pg_graphql
2
+ A data fetching library build on top of PostgreSQL inspired by Facebook's GraphQL
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rake/testtask'
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.libs << 'lib/pggraphql'
7
+ t.test_files = FileList['test/test_*.rb']
8
+ t.verbose = true
9
+ end
10
+
11
+ task :default => :test
@@ -0,0 +1,3 @@
1
+ module Pggraphql
2
+ VERSION = "0.0.1"
3
+ end
data/lib/pggraphql.rb ADDED
@@ -0,0 +1,126 @@
1
+ require "json"
2
+ require "active_support/all"
3
+ require "pggraphql/version"
4
+
5
+ module PgGraphQl
6
+
7
+ class Schema
8
+ attr_accessor :roots
9
+
10
+ def initialize
11
+ @roots = {}
12
+ @types = {}
13
+ yield(self) if block_given?
14
+
15
+ @types = @types.inject({}) do |memo, e|
16
+ t = memo[e[0]] = Type.new(e[0])
17
+
18
+ e[1].each_pair do |key, val|
19
+ t.send("#{key}=", val) unless key == :block
20
+ end
21
+
22
+ e[1][:block].call(t) if e[1][:block]
23
+ memo
24
+ end
25
+ end
26
+
27
+ def root(name, opts={})
28
+ opts[:type] = name.to_s.singularize.to_sym unless opts[:type]
29
+ @roots[name] = opts
30
+ end
31
+
32
+ def type(name, opts={}, &block)
33
+ opts[:block] = block
34
+ @types[name] = opts
35
+ end
36
+
37
+ def query(query, level=0, parent_link=nil, parent_type=nil)
38
+ requested_type = @types[query[0][0].to_sym]
39
+ requested_ids = query[0][1].is_a?(Array) ? query[0][1] : [query[0][1]].reject{|e| !e}
40
+
41
+ sql = requested_type.sql
42
+
43
+ where_conditions = []
44
+
45
+ if parent_link
46
+ if parent_link[:fk].is_a?(Symbol)
47
+ where_conditions << (parent_link[:invert] ? " #{requested_type.pk} = #{parent_type.as}.#{parent_link[:fk]}" : " #{parent_link[:fk]} = #{parent_type.pk!}")
48
+ elsif parent_link[:fk].is_a?(Proc)
49
+ where_conditions << (" #{requested_type.pk} in (" + parent_link[:fk].call(parent_link) + ")")
50
+ else
51
+ raise "unsupported"
52
+ end
53
+
54
+ where_conditions << parent_link[:filter] if parent_link[:filter]
55
+ end
56
+
57
+ requested_columns = query[1..-1].map do |field|
58
+
59
+ if field.is_a?(Symbol)
60
+ raise "unknown field" unless requested_type.fields.include?(field)
61
+ field.to_s
62
+ elsif field.is_a?(Array)
63
+
64
+ requested_link_field = field[0][0]
65
+ requested_link = requested_type.links[requested_link_field][1]
66
+ requested_link_ids = field[0][1]
67
+ requested_link_type = @types[requested_link[:type]]
68
+
69
+ requested_link_query = field.each_with_index.map do |e2, idx|
70
+ idx == 0 ? [requested_link_type.name, requested_link_ids] : e2
71
+ end
72
+
73
+ "(" + self.query(requested_link_query, level + 1, requested_link, requested_type) + ") as #{requested_link_field}"
74
+ else
75
+ raise "unsupported"
76
+ end
77
+
78
+ end
79
+
80
+ is_many = parent_type && parent_type.links[parent_link[:name]][0] == :many
81
+
82
+ inner_sql = sql.gsub("*", requested_columns.join(", "))
83
+
84
+ where_conditions << " #{requested_type.pk} in (#{requested_ids.map(&:to_s).join(',')})" unless requested_ids.empty?
85
+ where_conditions << (" " + requested_type.filter) if requested_type.filter
86
+
87
+ unless where_conditions.empty?
88
+ inner_sql += " where"
89
+ inner_sql += where_conditions.join(" and ")
90
+ end
91
+
92
+ inner_sql += (is_many ? "" : " limit 1")
93
+
94
+ "select to_json(" + (is_many ? "coalesce(json_agg(x.*), '[]'::json)" : "x.*" ) + ") res from (#{inner_sql}) x"
95
+ end
96
+
97
+ end
98
+
99
+ class Type
100
+ attr_accessor :pk, :sql, :fields, :as, :filter
101
+ attr_reader :links, :name
102
+ def initialize(name)
103
+ @name = name
104
+ @links = {}
105
+ @fields = [:id]
106
+ @as = name.to_s.pluralize.to_sym
107
+ @sql = "select * from #{name.to_s.pluralize}"
108
+ @pk = :id
109
+ end
110
+ def pk!
111
+ :"#{@as}.#{@pk}"
112
+ end
113
+ def one(name, opts={})
114
+ opts[:fk] = :"#{@name}_id" unless opts[:fk]
115
+ opts[:type] = name.to_s.singularize.to_sym unless opts[:type]
116
+ opts[:name] = name
117
+ @links[name] = [:one, opts]
118
+ end
119
+ def many(name, opts={})
120
+ opts[:fk] = :"#{@name}_id" unless opts[:fk]
121
+ opts[:type] = name.to_s.singularize.to_sym unless opts[:type]
122
+ opts[:name] = name
123
+ @links[name] = [:many, opts]
124
+ end
125
+ end
126
+ end
data/pggraphql.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'pggraphql/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "pggraphql"
8
+ spec.version = Pggraphql::VERSION
9
+ spec.authors = ["Jan Zimmek"]
10
+ spec.email = ["jan.zimmek@web.de"]
11
+ spec.summary = %q{PG GraphQL}
12
+ spec.description = %q{A data fetching library build on top of PostgreSQL inspired by Facebook's GraphQL}
13
+ spec.homepage = "https://github.com/jzimmek/pg_graphql"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "json"
22
+ spec.add_dependency "activesupport"
23
+
24
+ spec.add_development_dependency "test-unit"
25
+
26
+ spec.add_development_dependency "bundler", "~> 1.7"
27
+ spec.add_development_dependency "rake", "~> 10.0"
28
+ end
@@ -0,0 +1,346 @@
1
+ require "test-unit"
2
+ require "pggraphql"
3
+
4
+ module PgGraphQl
5
+ class PgGraphQlTest < ::Test::Unit::TestCase
6
+
7
+ def token(sql)
8
+ sql = sql.gsub(/\n/, " ").gsub("=", " = ").gsub(/,/, " , ").gsub("(", " ( ").gsub(")", " ) ").gsub(/[ ]+/, " ")
9
+ sql.strip.split(" ").map{|e| e.strip}.reject{|e| e.empty?}
10
+ end
11
+
12
+ def query(*args, &block)
13
+ Schema.new(&block).query(*args)
14
+ end
15
+
16
+ # schema
17
+
18
+ def test_schema_root_type
19
+ assert_equal :sometype, Schema.new{|e| e.root(:sometype)}.roots[:sometype][:type]
20
+ assert_equal :person, Schema.new{|e| e.root(:people)}.roots[:people][:type]
21
+ end
22
+
23
+ # type
24
+
25
+ def test_pk_prefixed_by_as
26
+ assert_equal :"sometypes.id", Type.new(:sometype).pk!
27
+ end
28
+
29
+ # type - defaults
30
+
31
+ def test_type_default_fields
32
+ assert_equal [:id], Type.new(:sometype).fields
33
+ end
34
+
35
+ def test_type_default_as
36
+ assert_equal :sometypes, Type.new(:sometype).as
37
+ assert_equal :people, Type.new(:person).as
38
+ end
39
+
40
+ def test_type_default_sql
41
+ assert_equal "select * from houses", Type.new(:house).sql
42
+ assert_equal "select * from people", Type.new(:person).sql
43
+ end
44
+
45
+ def test_type_default_pk
46
+ assert_equal :id, Type.new(:sometype).pk
47
+ end
48
+
49
+ def test_type_link_default_fk
50
+ assert_equal :sometype_id, Type.new(:sometype).tap{|e| e.one(:somelink) }.links[:somelink][1][:fk]
51
+ assert_equal :sometype_id, Type.new(:sometype).tap{|e| e.many(:somelink) }.links[:somelink][1][:fk]
52
+ assert_equal :other_fk, Type.new(:sometype).tap{|e| e.one(:somelink, fk: :other_fk) }.links[:somelink][1][:fk]
53
+ assert_equal :other_fk, Type.new(:sometype).tap{|e| e.many(:somelink, fk: :other_fk) }.links[:somelink][1][:fk]
54
+ end
55
+
56
+ def test_type_link_default_type
57
+ assert_equal :somelink, Type.new(:sometype).tap{|e| e.one(:somelink) }.links[:somelink][1][:type]
58
+ assert_equal :somelink, Type.new(:sometype).tap{|e| e.many(:somelink) }.links[:somelink][1][:type]
59
+
60
+ assert_equal :person, Type.new(:sometype).tap{|e| e.one(:people) }.links[:people][1][:type]
61
+ assert_equal :person, Type.new(:sometype).tap{|e| e.many(:people) }.links[:people][1][:type]
62
+
63
+ assert_equal :other_type, Type.new(:sometype).tap{|e| e.one(:somelink, type: :other_type) }.links[:somelink][1][:type]
64
+ assert_equal :other_type, Type.new(:sometype).tap{|e| e.many(:somelink, type: :other_type) }.links[:somelink][1][:type]
65
+ end
66
+
67
+ def test_unknown_field
68
+ assert_raise_message "unknown field" do
69
+ query([[:user, 1], :id, :name]) do |s|
70
+ s.root :user
71
+ s.type :user
72
+ end
73
+ end
74
+ end
75
+
76
+ def test_simple
77
+ res = query([[:user, 1], :id, :name]) do |s|
78
+ s.root :user
79
+ s.type :user, fields: [:id, :name]
80
+ end
81
+
82
+ assert_equal token("select to_json(x.*) res from (select id, name from users where id in (1) limit 1) x"), token(res)
83
+ end
84
+
85
+ def test_simple_filter
86
+ res = query([[:user, 1], :id, :name]) do |s|
87
+ s.root :user
88
+ s.type :user, fields: [:id, :name], filter: "id % 2 = 0"
89
+ end
90
+
91
+ assert_equal token("select to_json(x.*) res from (select id, name from users where id in (1) and id % 2 = 0 limit 1) x"), token(res)
92
+
93
+ res = query([[:user, 1], :id, :name]) do |s|
94
+ s.root :user
95
+ s.type :user, fields: [:id, :name], filter: "id % 2 = 0 and id > 10"
96
+ end
97
+
98
+ assert_equal token("select to_json(x.*) res from (select id, name from users where id in (1) and id % 2 = 0 and id > 10 limit 1) x"), token(res)
99
+ end
100
+
101
+ def test_one
102
+ res = query([[:user, 1], :id, [[:address], :id]]) do |s|
103
+ s.root :user
104
+ s.type :user do |t|
105
+ t.one :address
106
+ end
107
+ s.type :address
108
+ end
109
+
110
+ expected = <<-SQL
111
+ select
112
+ to_json(x.*) res
113
+ from (
114
+ select
115
+ id,
116
+ (select to_json(x.*) res from (select id from addresses where user_id = users.id limit 1) x) as address
117
+ from users
118
+ where id in (1)
119
+ limit 1
120
+ ) x
121
+ SQL
122
+
123
+ assert_equal token(expected), token(res)
124
+ end
125
+
126
+ def test_one_fk_invert
127
+ res = query([[:user, 1], :id, [[:address], :id]]) do |s|
128
+ s.root :user
129
+ s.type :user do |t|
130
+ t.one :address, fk: :address_id, invert: true
131
+ end
132
+ s.type :address
133
+ end
134
+
135
+ expected = <<-SQL
136
+ select
137
+ to_json(x.*) res
138
+ from (
139
+ select
140
+ id,
141
+ (select to_json(x.*) res from (select id from addresses where id = users.address_id limit 1) x) as address
142
+ from users
143
+ where id in (1)
144
+ limit 1
145
+ ) x
146
+ SQL
147
+
148
+ assert_equal token(expected), token(res)
149
+ end
150
+
151
+ # def test_one_polymorph
152
+ # res = query([[:user, 1], :id, [[:address], :id]]) do |s|
153
+ # s.root :user
154
+ # s.type :user do |t|
155
+ # t.one :address, polymorph: [:primary, :secondary]
156
+ # end
157
+ # s.type :address
158
+ # s.type :address_primary
159
+ # s.type :address_secondary
160
+ # end
161
+
162
+ # expected = <<-SQL
163
+ # select
164
+ # to_json(x.*) res
165
+ # from (
166
+ # select
167
+ # id,
168
+ # (select to_json(x.*) res from (
169
+ # select 'primary' as type, id from addresses join addresses_primary using (id) where user_id = users.id and addresses.type = 'primary'
170
+ # union
171
+ # select 'secondary' as type, id from addresses join addresses_secondary using (id) where user_id = users.id and addresses.type = 'secondary'
172
+ # ) x) as address
173
+ # from users
174
+ # where id in (1)
175
+ # limit 1
176
+ # ) x
177
+ # SQL
178
+
179
+ # assert_equal token(expected), token(res)
180
+ # end
181
+
182
+ def test_one_filter
183
+ res = query([[:user, 1], :id, [[:address], :id]]) do |s|
184
+ s.root :user
185
+ s.type :user do |t|
186
+ t.one :address, filter: "is_default = true"
187
+ end
188
+ s.type :address
189
+ end
190
+
191
+ expected = <<-SQL
192
+ select
193
+ to_json(x.*) res
194
+ from (
195
+ select
196
+ id,
197
+ (select to_json(x.*) res from (select id from addresses where user_id = users.id and is_default = true limit 1) x) as address
198
+ from users
199
+ where id in (1)
200
+ limit 1
201
+ ) x
202
+ SQL
203
+
204
+ assert_equal token(expected), token(res)
205
+ end
206
+
207
+ def test_one_fk_through
208
+ res = query([[:user, 1], :id, [[:address], :id]]) do |s|
209
+ s.root :user
210
+ s.type :user do |t|
211
+ t.one :address, fk: ->(l) do
212
+ "select id from some_address_table where user_id = #{t.pk!}"
213
+ end
214
+ end
215
+ s.type :address
216
+ end
217
+
218
+ expected = <<-SQL
219
+ select
220
+ to_json(x.*) res
221
+ from (
222
+ select
223
+ id,
224
+ (select to_json(x.*) res from (select id from addresses where id in (select id from some_address_table where user_id = users.id) limit 1) x) as address
225
+ from users
226
+ where id in (1)
227
+ limit 1
228
+ ) x
229
+ SQL
230
+
231
+ assert_equal token(expected), token(res)
232
+ end
233
+
234
+ def test_one_in_one
235
+ res = query([[:user, 1], :id, [[:address], :id, [[:person], :id]]]) do |s|
236
+ s.root :user
237
+ s.type :user do |t|
238
+ t.one :address
239
+ end
240
+ s.type :address do |t|
241
+ t.one :person
242
+ end
243
+ s.type :person
244
+ end
245
+
246
+ expected = <<-SQL
247
+ select
248
+ to_json(x.*) res
249
+ from (
250
+ select
251
+ id,
252
+ (select to_json(x.*) res from (
253
+ select
254
+ id,
255
+ (select to_json(x.*) res from (select id from people where address_id = addresses.id limit 1) x) as person
256
+ from addresses where user_id = users.id limit 1
257
+ ) x) as address
258
+ from users
259
+ where id in (1)
260
+ limit 1
261
+ ) x
262
+ SQL
263
+
264
+ assert_equal token(expected), token(res)
265
+ end
266
+
267
+ def test_many
268
+ res = query([[:user, 1], :id, [[:addresses], :id]]) do |s|
269
+ s.root :user
270
+ s.type :user do |t|
271
+ t.many :addresses
272
+ end
273
+ s.type :address
274
+ end
275
+
276
+ expected = <<-SQL
277
+ select
278
+ to_json(x.*) res
279
+ from (
280
+ select id,
281
+ (select to_json(coalesce(json_agg(x.*), '[]'::json)) res from (select id from addresses where user_id = users.id) x) as addresses
282
+ from users
283
+ where id in (1) limit 1
284
+ ) x
285
+ SQL
286
+
287
+ assert_equal token(expected), token(res)
288
+ end
289
+
290
+ def test_many_with_ids
291
+ res = query([[:user, 1], :id, [[:addresses, 100], :id]]) do |s|
292
+ s.root :user
293
+ s.type :user do |t|
294
+ t.many :addresses
295
+ end
296
+ s.type :address
297
+ end
298
+
299
+ expected = <<-SQL
300
+ select
301
+ to_json(x.*) res
302
+ from (
303
+ select id,
304
+ (select to_json(coalesce(json_agg(x.*), '[]'::json)) res from (select id from addresses where user_id = users.id and id in (100)) x) as addresses
305
+ from users
306
+ where id in (1) limit 1
307
+ ) x
308
+ SQL
309
+
310
+ assert_equal token(expected), token(res)
311
+ end
312
+
313
+ def test_one_in_many
314
+ res = query([[:user, 1], :id, [[:addresses], :id, [[:person], :id]]]) do |s|
315
+ s.root :user
316
+ s.type :user do |t|
317
+ t.many :addresses
318
+ end
319
+ s.type :address do |t|
320
+ t.one :person
321
+ end
322
+ s.type :person
323
+ end
324
+
325
+ expected = <<-SQL
326
+ select
327
+ to_json(x.*) res
328
+ from (
329
+ select
330
+ id,
331
+ (select to_json(coalesce(json_agg(x.*), '[]'::json)) res from (
332
+ select
333
+ id,
334
+ (select to_json(x.*) res from (select id from people where address_id = addresses.id limit 1) x) as person
335
+ from addresses where user_id = users.id
336
+ ) x) as addresses
337
+ from users
338
+ where id in (1)
339
+ limit 1
340
+ ) x
341
+ SQL
342
+
343
+ assert_equal token(expected), token(res)
344
+ end
345
+ end
346
+ end
metadata ADDED
@@ -0,0 +1,127 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pggraphql
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Jan Zimmek
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-03-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: json
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: test-unit
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.7'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.7'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '10.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '10.0'
83
+ description: A data fetching library build on top of PostgreSQL inspired by Facebook's
84
+ GraphQL
85
+ email:
86
+ - jan.zimmek@web.de
87
+ executables: []
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - ".gitignore"
92
+ - Gemfile
93
+ - Gemfile.lock
94
+ - LICENSE
95
+ - LICENSE.txt
96
+ - README.md
97
+ - Rakefile
98
+ - lib/pggraphql.rb
99
+ - lib/pggraphql/version.rb
100
+ - pggraphql.gemspec
101
+ - test/test_pggraphql.rb
102
+ homepage: https://github.com/jzimmek/pg_graphql
103
+ licenses:
104
+ - MIT
105
+ metadata: {}
106
+ post_install_message:
107
+ rdoc_options: []
108
+ require_paths:
109
+ - lib
110
+ required_ruby_version: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ required_rubygems_version: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ requirements: []
121
+ rubyforge_project:
122
+ rubygems_version: 2.4.5
123
+ signing_key:
124
+ specification_version: 4
125
+ summary: PG GraphQL
126
+ test_files:
127
+ - test/test_pggraphql.rb