pggraphql 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.
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