mao 0.0.3
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.
- data/.autotest +2 -0
- data/.gitignore +1 -0
- data/.rspec +1 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +18 -0
- data/README.md +14 -0
- data/Rakefile +8 -0
- data/TODO +5 -0
- data/lib/mao/filter.rb +168 -0
- data/lib/mao/query.rb +381 -0
- data/lib/mao/version.rb +5 -0
- data/lib/mao.rb +180 -0
- data/mao.gemspec +22 -0
- data/spec/filter_spec.rb +173 -0
- data/spec/fixture.sql +38 -0
- data/spec/mao_spec.rb +220 -0
- data/spec/query_spec.rb +417 -0
- data/spec/spec_helper.rb +13 -0
- data/thoughts.rb +42 -0
- metadata +120 -0
data/spec/query_spec.rb
ADDED
@@ -0,0 +1,417 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe Mao::Query do
|
5
|
+
before { prepare_spec }
|
6
|
+
|
7
|
+
let(:empty) { Mao.query(:empty) }
|
8
|
+
let(:one) { Mao.query(:one) }
|
9
|
+
let(:some) { Mao.query(:some) }
|
10
|
+
let(:typey) { Mao.query(:typey) }
|
11
|
+
let(:autoid) { Mao.query(:autoid) }
|
12
|
+
let(:times) { Mao.query(:times) }
|
13
|
+
|
14
|
+
describe ".new" do
|
15
|
+
subject { Mao::Query.new(:table, {}, {}) }
|
16
|
+
|
17
|
+
its(:table) { should be_an_instance_of Symbol }
|
18
|
+
its(:options) { should be_frozen }
|
19
|
+
its(:col_types) { should be_frozen }
|
20
|
+
|
21
|
+
context "no such table" do
|
22
|
+
it { expect { Mao::Query.new("nonextant")
|
23
|
+
}.to raise_exception(ArgumentError) }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "#with_options" do
|
28
|
+
subject { one.with_options(:blah => 99) }
|
29
|
+
|
30
|
+
its(:table) { should be one.table }
|
31
|
+
its(:options) { should eq({:blah => 99}) }
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "#limit" do
|
35
|
+
subject { some.limit(2) }
|
36
|
+
|
37
|
+
its(:options) { should include(:limit => 2) }
|
38
|
+
its(:sql) { should eq 'SELECT * FROM "some" LIMIT 2' }
|
39
|
+
|
40
|
+
context "invalid argument" do
|
41
|
+
it { expect { some.limit("2")
|
42
|
+
}.to raise_exception(ArgumentError) }
|
43
|
+
|
44
|
+
it { expect { some.limit(false)
|
45
|
+
}.to raise_exception(ArgumentError) }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "#order" do
|
50
|
+
let(:asc) { some.order(:id, :asc) }
|
51
|
+
it { asc.options.should include(:order => [:id, 'ASC']) }
|
52
|
+
it { asc.sql.should eq 'SELECT * FROM "some" ORDER BY "id" ASC' }
|
53
|
+
|
54
|
+
let(:desc) { one.order(:value, :desc) }
|
55
|
+
it { desc.options.should include(:order => [:value, 'DESC']) }
|
56
|
+
it { desc.sql.should eq 'SELECT * FROM "one" ORDER BY "value" DESC' }
|
57
|
+
|
58
|
+
it { expect { one.order(:huh, :asc) }.to raise_exception(ArgumentError) }
|
59
|
+
it { expect { one.order(:value) }.to raise_exception(ArgumentError) }
|
60
|
+
it { expect { one.order(:id, 'ASC') }.to raise_exception(ArgumentError) }
|
61
|
+
it { expect { one.order(:id, :xyz) }.to raise_exception(ArgumentError) }
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "#only" do
|
65
|
+
subject { some.only(:id, [:value]) }
|
66
|
+
|
67
|
+
its(:options) { should include(:only => [:id, :value]) }
|
68
|
+
its(:sql) { should eq 'SELECT "id", "value" FROM "some"' }
|
69
|
+
|
70
|
+
context "invalid argument" do
|
71
|
+
it { expect { some.only(42)
|
72
|
+
}.to raise_exception(ArgumentError) }
|
73
|
+
|
74
|
+
it { expect { some.only(nil)
|
75
|
+
}.to raise_exception(ArgumentError) }
|
76
|
+
|
77
|
+
it { expect { some.only("id")
|
78
|
+
}.to raise_exception(ArgumentError) }
|
79
|
+
|
80
|
+
it { expect { some.only(:j)
|
81
|
+
}.to raise_exception(ArgumentError) }
|
82
|
+
end
|
83
|
+
|
84
|
+
context "with #join" do
|
85
|
+
subject { some.join(:one) { one.value == some.value }.
|
86
|
+
only(:one => [:id]) }
|
87
|
+
|
88
|
+
its(:options) { should include(:only => {:one => [:id]}) }
|
89
|
+
its(:sql) { should eq 'SELECT "one"."id" "c3" ' +
|
90
|
+
'FROM "some" ' +
|
91
|
+
'INNER JOIN "one" ' +
|
92
|
+
'ON ("one"."value" = "some"."value")' }
|
93
|
+
its(:select!) { should eq [{:one => {:id => 42}}] }
|
94
|
+
|
95
|
+
context "before #join" do
|
96
|
+
it { expect { some.only(:some => [:id])
|
97
|
+
}.to raise_exception(ArgumentError) }
|
98
|
+
end
|
99
|
+
|
100
|
+
context "poor arguments" do
|
101
|
+
it { expect { some.join(:one) { one.value }.only(:some => :id)
|
102
|
+
}.to raise_exception(ArgumentError) }
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe "#returning" do
|
108
|
+
subject { some.returning([:id], :value).
|
109
|
+
with_options(:insert => [{:value => "q"}]) }
|
110
|
+
|
111
|
+
its(:options) { should include(:returning => [:id, :value]) }
|
112
|
+
its(:sql) { should eq 'INSERT INTO "some" ("value") ' +
|
113
|
+
'VALUES (\'q\') RETURNING "id", "value"' }
|
114
|
+
|
115
|
+
context "invalid argument" do
|
116
|
+
it { expect { some.returning(42)
|
117
|
+
}.to raise_exception(ArgumentError) }
|
118
|
+
|
119
|
+
it { expect { some.returning(nil)
|
120
|
+
}.to raise_exception(ArgumentError) }
|
121
|
+
|
122
|
+
it { expect { some.returning("id")
|
123
|
+
}.to raise_exception(ArgumentError) }
|
124
|
+
|
125
|
+
it { expect { some.returning("j")
|
126
|
+
}.to raise_exception(ArgumentError) }
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
describe "#where" do
|
131
|
+
subject { some.where { (id == 1).or(id > 10_000) } }
|
132
|
+
|
133
|
+
its(:options) do
|
134
|
+
should include(:where => [:Binary,
|
135
|
+
'OR',
|
136
|
+
[:Binary, '=', [:Column, :id], "1"],
|
137
|
+
[:Binary, '>', [:Column, :id], "10000"]])
|
138
|
+
end
|
139
|
+
|
140
|
+
its(:sql) { should eq 'SELECT * FROM "some" WHERE ' \
|
141
|
+
'(("id" = 1) OR ("id" > 10000))' }
|
142
|
+
|
143
|
+
context "non-extant column" do
|
144
|
+
it { expect { some.where { non_extant_column == 42 }
|
145
|
+
}.to raise_exception(ArgumentError) }
|
146
|
+
end
|
147
|
+
|
148
|
+
context "with #join" do
|
149
|
+
subject { some.join(:one) { one.value == some.value }.
|
150
|
+
where { one.id == 42 } }
|
151
|
+
|
152
|
+
its(:options) { should include(:where => [:Binary,
|
153
|
+
'=',
|
154
|
+
[:Column, :one, :id],
|
155
|
+
"42"]) }
|
156
|
+
its(:sql) { should eq 'SELECT "some"."id" "c1", ' +
|
157
|
+
'"some"."value" "c2", ' +
|
158
|
+
'"one"."id" "c3", ' +
|
159
|
+
'"one"."value" "c4" ' +
|
160
|
+
'FROM "some" ' +
|
161
|
+
'INNER JOIN "one" ' +
|
162
|
+
'ON ("one"."value" = "some"."value") ' +
|
163
|
+
'WHERE ("one"."id" = 42)' }
|
164
|
+
|
165
|
+
its(:select!) { should eq(
|
166
|
+
[{:some => {:id => 3, :value => "你好, Dave."},
|
167
|
+
:one => {:id => 42, :value => "你好, Dave."}}]) }
|
168
|
+
end
|
169
|
+
|
170
|
+
context "with time values" do
|
171
|
+
it { times.select_first!.should eq(
|
172
|
+
{:id => 1, :time => Time.new(2012, 11, 10, 19, 45, 0, 0)}) }
|
173
|
+
|
174
|
+
it { times.where { time == Time.new(2012, 11, 11, 6, 45, 0, 11 * 3600) }.
|
175
|
+
select!.length.should eq 1 }
|
176
|
+
it { times.where { time == Time.new(2012, 11, 10, 19, 45, 0, 0) }.
|
177
|
+
select!.length.should eq 1 }
|
178
|
+
it { times.where { time == "2012-11-10 19:45:00" }.
|
179
|
+
select!.length.should eq 1 }
|
180
|
+
it { times.where { time == "2012-11-10 19:45:00 Z" }.
|
181
|
+
select!.length.should eq 1 }
|
182
|
+
it { times.where { time == "2012-11-10 19:45:00 +00" }.
|
183
|
+
select!.length.should eq 1 }
|
184
|
+
it { times.where { time == "2012-11-10 19:45:00 +00:00" }.
|
185
|
+
select!.length.should eq 1 }
|
186
|
+
it { times.where { time == "2012-11-10 19:45:00 -00" }.
|
187
|
+
select!.length.should eq 1 }
|
188
|
+
it { times.where { time == "2012-11-10 19:45:00 -00:00" }.
|
189
|
+
select!.length.should eq 1 }
|
190
|
+
|
191
|
+
it { times.where { time < Time.new(2012, 11, 11, 6, 45, 0, 11 * 3600) }.
|
192
|
+
select!.length.should eq 0 }
|
193
|
+
context "surprising results" do
|
194
|
+
# Timestamps are IGNORED for comparisons with "timestamp without time
|
195
|
+
# zone". See:
|
196
|
+
# http://postgresql.org/docs/9.1/static/datatype-datetime.html#AEN5714
|
197
|
+
it { times.where { time < "2012-11-11 6:45:00 +11" }.
|
198
|
+
select!.length.should eq 1 }
|
199
|
+
it { times.where { time < "2012-11-11 6:45:00 +1100" }.
|
200
|
+
select!.length.should eq 1 }
|
201
|
+
it { times.where { time < "2012-11-11 6:45:00 +11:00" }.
|
202
|
+
select!.length.should eq 1 }
|
203
|
+
end
|
204
|
+
it { times.where { time <= Time.new(2012, 11, 11, 6, 45, 0, 11 * 3600) }.
|
205
|
+
select!.length.should eq 1 }
|
206
|
+
it { times.where { time <= "2012-11-11 6:45:00 +11" }.
|
207
|
+
select!.length.should eq 1 }
|
208
|
+
it { times.where { time <= "2012-11-11 6:45:00 +1100" }.
|
209
|
+
select!.length.should eq 1 }
|
210
|
+
it { times.where { time <= "2012-11-11 6:45:00 +11:00" }.
|
211
|
+
select!.length.should eq 1 }
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
describe "#join" do
|
216
|
+
subject { some.join(:one) { one.value == some.value } }
|
217
|
+
|
218
|
+
its(:options) do
|
219
|
+
should include(:join => [:one,
|
220
|
+
[:Binary,
|
221
|
+
'=',
|
222
|
+
[:Column, :one, :value],
|
223
|
+
[:Column, :some, :value]]])
|
224
|
+
end
|
225
|
+
|
226
|
+
its(:sql) { should eq(
|
227
|
+
'SELECT ' +
|
228
|
+
'"some"."id" "c1", ' +
|
229
|
+
'"some"."value" "c2", ' +
|
230
|
+
'"one"."id" "c3", ' +
|
231
|
+
'"one"."value" "c4" ' +
|
232
|
+
'FROM "some" ' +
|
233
|
+
'INNER JOIN "one" ' +
|
234
|
+
'ON ("one"."value" = "some"."value")') }
|
235
|
+
|
236
|
+
its(:select!) { should eq [{:some => {:id => 3,
|
237
|
+
:value => "你好, Dave."},
|
238
|
+
:one => {:id => 42,
|
239
|
+
:value => "你好, Dave."}}] }
|
240
|
+
|
241
|
+
context "simple Hash joins" do
|
242
|
+
subject { some.join({:one => {:value => :id}}) }
|
243
|
+
|
244
|
+
its(:options) do
|
245
|
+
should include(:join => [:one,
|
246
|
+
[:Binary,
|
247
|
+
'=',
|
248
|
+
[:Column, :some, :value],
|
249
|
+
[:Column, :one, :id]]])
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
describe "#select!" do
|
255
|
+
context "use of #sql" do
|
256
|
+
# HACK: construct empty manually, otherwise it'll try to look up column
|
257
|
+
# info and ruin our assertions.
|
258
|
+
let(:empty) { Mao::Query.new("empty",
|
259
|
+
{},
|
260
|
+
{}) }
|
261
|
+
let(:empty_sure) { double("empty_sure") }
|
262
|
+
let(:empty_sql) { double("empty_sql") }
|
263
|
+
before { empty.should_receive(:with_options).
|
264
|
+
with(:update => nil).
|
265
|
+
and_return(empty_sure) }
|
266
|
+
before { empty_sure.should_receive(:sql).
|
267
|
+
and_return(empty_sql) }
|
268
|
+
before { PG::Connection.any_instance.should_receive(:exec).
|
269
|
+
with(empty_sql).and_return(:ok) }
|
270
|
+
it { empty.select!.should eq :ok }
|
271
|
+
end
|
272
|
+
|
273
|
+
context "no results" do
|
274
|
+
it { empty.select!.should eq [] }
|
275
|
+
end
|
276
|
+
|
277
|
+
context "one result" do
|
278
|
+
subject { one.select! }
|
279
|
+
|
280
|
+
it { should be_an_instance_of Array }
|
281
|
+
it { should have(1).item }
|
282
|
+
its([0]) { should eq({:id => 42, :value => "你好, Dave."}) }
|
283
|
+
end
|
284
|
+
|
285
|
+
context "some results" do
|
286
|
+
subject { some.select! }
|
287
|
+
|
288
|
+
it { should be_an_instance_of Array }
|
289
|
+
it { should have(3).items }
|
290
|
+
|
291
|
+
its([0]) { should eq({:id => 1, :value => "Bah"}) }
|
292
|
+
its([1]) { should eq({:id => 2, :value => "Hah"}) }
|
293
|
+
its([2]) { should eq({:id => 3, :value => "你好, Dave."}) }
|
294
|
+
end
|
295
|
+
|
296
|
+
context "various types" do
|
297
|
+
subject { typey.select! }
|
298
|
+
|
299
|
+
it { should have(2).items }
|
300
|
+
its([0]) { should eq(
|
301
|
+
{:korea => true,
|
302
|
+
:japan => BigDecimal.new("1234567890123456.789"),
|
303
|
+
:china => "WHAT\x00".force_encoding(Encoding::ASCII_8BIT)}) }
|
304
|
+
its([1]) { should eq(
|
305
|
+
{:korea => false,
|
306
|
+
:japan => BigDecimal.new("-1234567890123456.789"),
|
307
|
+
:china => "HUH\x01\x02".force_encoding(Encoding::ASCII_8BIT)}) }
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
describe "#select_first!" do
|
312
|
+
# HACK: construct empty manually, otherwise it'll try to look up column
|
313
|
+
# info and ruin our assertions.
|
314
|
+
let(:empty) { Mao::Query.new("empty",
|
315
|
+
{},
|
316
|
+
{}) }
|
317
|
+
before { empty.should_receive(:limit).with(1).and_return(empty) }
|
318
|
+
before { empty.should_receive(:select!).and_return([:ok]) }
|
319
|
+
it { empty.select_first!.should eq :ok }
|
320
|
+
end
|
321
|
+
|
322
|
+
describe "#update!" do
|
323
|
+
context "use of #sql" do
|
324
|
+
let(:empty) { Mao::Query.new("empty",
|
325
|
+
{},
|
326
|
+
{}) }
|
327
|
+
let(:empty_update) { double("empty_update") }
|
328
|
+
let(:empty_sql) { double("empty_sql") }
|
329
|
+
before { empty.should_receive(:with_options).
|
330
|
+
with(:update => {:x => :y}).
|
331
|
+
and_return(empty_update) }
|
332
|
+
before { empty_update.should_receive(:sql).and_return(empty_sql) }
|
333
|
+
before { PG::Connection.any_instance.should_receive(:exec).
|
334
|
+
with(empty_sql).and_return(:ok) }
|
335
|
+
it { empty.update!(:x => :y).should eq :ok }
|
336
|
+
end
|
337
|
+
|
338
|
+
context "#sql result" do
|
339
|
+
subject { empty.with_options(:update => {:id => 44}).sql }
|
340
|
+
it { should eq 'UPDATE "empty" SET "id" = 44' }
|
341
|
+
end
|
342
|
+
|
343
|
+
context "no matches" do
|
344
|
+
it { empty.update!(:value => "y").should eq 0 }
|
345
|
+
end
|
346
|
+
|
347
|
+
context "no such column" do
|
348
|
+
it { expect { empty.update!(:x => "y")
|
349
|
+
}.to raise_exception(ArgumentError, /is not a column/) }
|
350
|
+
end
|
351
|
+
|
352
|
+
context "some matches" do
|
353
|
+
it { some.where { id <= 2 }.update!(:value => 'Meh').should eq 2 }
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
describe "#insert!" do
|
358
|
+
context "use of #sql" do
|
359
|
+
let(:empty) { Mao::Query.new("empty",
|
360
|
+
{},
|
361
|
+
{}) }
|
362
|
+
let(:empty_insert) { double("empty_insert") }
|
363
|
+
let(:empty_sql) { double("empty_sql") }
|
364
|
+
before { empty.should_receive(:with_options).
|
365
|
+
with(:insert => [{:x => :y}]).
|
366
|
+
and_return(empty_insert) }
|
367
|
+
before { empty_insert.should_receive(:sql).and_return(empty_sql) }
|
368
|
+
before { PG::Connection.any_instance.should_receive(:exec).
|
369
|
+
with(empty_sql).and_return(:ok) }
|
370
|
+
it { empty.insert!([:x => :y]).should eq :ok }
|
371
|
+
end
|
372
|
+
|
373
|
+
context "#sql result" do
|
374
|
+
context "all columns alike" do
|
375
|
+
subject { empty.with_options(
|
376
|
+
:insert => [{:id => 44}, {:id => 38}]).sql }
|
377
|
+
it { should eq 'INSERT INTO "empty" ("id") VALUES (44), (38)' }
|
378
|
+
end
|
379
|
+
|
380
|
+
context "not all columns alike" do
|
381
|
+
subject { empty.with_options(
|
382
|
+
:insert => [{:id => 1}, {:value => 'z', :id => 2}]).sql }
|
383
|
+
it { should eq 'INSERT INTO "empty" ("id", "value") ' +
|
384
|
+
'VALUES (1, DEFAULT), (2, \'z\')' }
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
context "result" do
|
389
|
+
context "number of rows" do
|
390
|
+
it { autoid.insert!(:value => "quox").should eq 1 }
|
391
|
+
it { autoid.insert!({:value => "lol"}, {:value => "x"}).should eq 2 }
|
392
|
+
end
|
393
|
+
|
394
|
+
context "#returning" do
|
395
|
+
it do
|
396
|
+
autoid.returning(:id).insert!(:value => "nanana").
|
397
|
+
should eq([{:id => 1}])
|
398
|
+
autoid.returning(:id).insert!(:value => "ha").
|
399
|
+
should eq([{:id => 2}])
|
400
|
+
autoid.returning(:id).insert!(:value => "bah").
|
401
|
+
should eq([{:id => 3}])
|
402
|
+
autoid.returning(:id).insert!({:value => "a"}, {:value => "b"}).
|
403
|
+
should eq([{:id => 4}, {:id => 5}])
|
404
|
+
end
|
405
|
+
end
|
406
|
+
end
|
407
|
+
end
|
408
|
+
|
409
|
+
describe "reconnection" do
|
410
|
+
it do
|
411
|
+
Mao.query(:one).select!.should be_an_instance_of Array
|
412
|
+
pending
|
413
|
+
end
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
# vim: set sw=2 cc=80 et:
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'mao'
|
2
|
+
|
3
|
+
def relative_to_spec(filename)
|
4
|
+
File.join(File.dirname(File.absolute_path(__FILE__)),
|
5
|
+
filename)
|
6
|
+
end
|
7
|
+
|
8
|
+
def prepare_spec
|
9
|
+
`psql mao_testing -f #{relative_to_spec("fixture.sql")} 2>&1 | grep -v ^NOTICE`
|
10
|
+
Mao.connect!(:dbname => 'mao_testing')
|
11
|
+
end
|
12
|
+
|
13
|
+
# vim: set sw=2 cc=80 et:
|
data/thoughts.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
X.trans do
|
2
|
+
X.query(:tblSamuraiUser).join { ... }.where {
|
3
|
+
upp = tblSamuraiUserProduct
|
4
|
+
|
5
|
+
upp.userProductId == 188...
|
6
|
+
|
7
|
+
|
8
|
+
first_cond = (email == "arlen@noblesamurai.com").and(userId > 10000)
|
9
|
+
second_cond = x.and(y).and(z)
|
10
|
+
|
11
|
+
blah = tblSamuraiUserProduct.columnName == xyzzy
|
12
|
+
|
13
|
+
first_cond.or second_cond.or blah
|
14
|
+
}
|
15
|
+
|
16
|
+
my_new_record = my_old_record.merge(changes)
|
17
|
+
|
18
|
+
X.update(:tblSamuraiUser).where { userId == 610610 }.update(changes)
|
19
|
+
end
|
20
|
+
|
21
|
+
X.query(:tblSamuraiUser).where(lambda {email == "arlen@noblesamurai.com"}, lambda {userId > 10000})
|
22
|
+
|
23
|
+
#Tim's thoughts:
|
24
|
+
#
|
25
|
+
#- We need to know what we think of statically defined r'ships b/w tables vs defining everything in place where the query is performed.
|
26
|
+
# Is the ActiveRecord way of defining r'ships b/w tables a good model for us?
|
27
|
+
# Or do we have some alternative way of statically defining this stuff? Or do we dynamically infer it?
|
28
|
+
#
|
29
|
+
# I am thinking we need a means to join which is based again on a simple hash. For example, the hash
|
30
|
+
# could look like: {:from => :tblSamuraiUser.id, :to => tblSamuraiUserProduct.user_id}
|
31
|
+
# Then, the user could define these hash as constants, eg UserToUserProduct = blah
|
32
|
+
# The joins could then be brought in to the query object (perhaps a .joins method, which can either take a single hash or an array),
|
33
|
+
# as with a :joins key, which might map to an array of joins options hashes.
|
34
|
+
#
|
35
|
+
# Anyway, those are my thoughts for now, we can chat further!
|
36
|
+
|
37
|
+
|
38
|
+
|
39
|
+
# Tenet:
|
40
|
+
#
|
41
|
+
# From the code you have written, it should be sufficiently declarative and map
|
42
|
+
# sufficiently predictably to SQL that you can predict the SQL produced.
|
metadata
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mao
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.3
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Timothy Leslie Allen
|
9
|
+
- Arlen Christian Mart Cuss
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2012-11-15 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: pg
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ! '>='
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '0'
|
31
|
+
- !ruby/object:Gem::Dependency
|
32
|
+
name: rake
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
34
|
+
none: false
|
35
|
+
requirements:
|
36
|
+
- - ! '>='
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '0'
|
39
|
+
type: :development
|
40
|
+
prerelease: false
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rspec
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ! '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
description: Mao Ain't an ORM
|
64
|
+
email:
|
65
|
+
- allen.timothy.email@gmail.com
|
66
|
+
- ar@len.me
|
67
|
+
executables: []
|
68
|
+
extensions: []
|
69
|
+
extra_rdoc_files: []
|
70
|
+
files:
|
71
|
+
- .autotest
|
72
|
+
- .gitignore
|
73
|
+
- .rspec
|
74
|
+
- .travis.yml
|
75
|
+
- Gemfile
|
76
|
+
- Gemfile.lock
|
77
|
+
- README.md
|
78
|
+
- Rakefile
|
79
|
+
- TODO
|
80
|
+
- lib/mao.rb
|
81
|
+
- lib/mao/filter.rb
|
82
|
+
- lib/mao/query.rb
|
83
|
+
- lib/mao/version.rb
|
84
|
+
- mao.gemspec
|
85
|
+
- spec/filter_spec.rb
|
86
|
+
- spec/fixture.sql
|
87
|
+
- spec/mao_spec.rb
|
88
|
+
- spec/query_spec.rb
|
89
|
+
- spec/spec_helper.rb
|
90
|
+
- thoughts.rb
|
91
|
+
homepage: https://github.com/unnali/mao
|
92
|
+
licenses: []
|
93
|
+
post_install_message:
|
94
|
+
rdoc_options: []
|
95
|
+
require_paths:
|
96
|
+
- lib
|
97
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
98
|
+
none: false
|
99
|
+
requirements:
|
100
|
+
- - ! '>='
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
104
|
+
none: false
|
105
|
+
requirements:
|
106
|
+
- - ! '>='
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '0'
|
109
|
+
requirements: []
|
110
|
+
rubyforge_project:
|
111
|
+
rubygems_version: 1.8.23
|
112
|
+
signing_key:
|
113
|
+
specification_version: 3
|
114
|
+
summary: A database access layer. Currently supports PG.
|
115
|
+
test_files:
|
116
|
+
- spec/filter_spec.rb
|
117
|
+
- spec/fixture.sql
|
118
|
+
- spec/mao_spec.rb
|
119
|
+
- spec/query_spec.rb
|
120
|
+
- spec/spec_helper.rb
|