payload-api 0.4.1 → 0.6.0
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 +4 -4
- data/.github/workflows/test.yml +2 -0
- data/LICENSE +1 -1
- data/README.md +23 -2
- data/lib/payload/arm/attr.rb +169 -0
- data/lib/payload/arm/object.rb +44 -1
- data/lib/payload/arm/request.rb +66 -6
- data/lib/payload/arm/session.rb +13 -9
- data/lib/payload/exceptions.rb +15 -0
- data/lib/payload/objects.rb +81 -18
- data/lib/payload/version.rb +2 -2
- data/lib/payload.rb +15 -5
- data/spec/objects/v1/access_token_spec.rb +19 -0
- data/spec/objects/v1/account_spec.rb +97 -0
- data/spec/objects/v1/billing_spec.rb +54 -0
- data/spec/objects/v1/invoice_spec.rb +53 -0
- data/spec/objects/v1/payment_link_spec.rb +50 -0
- data/spec/objects/v1/payment_method_spec.rb +106 -0
- data/spec/objects/{payment_spec.rb → v1/payment_spec.rb} +5 -6
- data/spec/objects/v1/session_spec.rb +89 -0
- data/spec/objects/v1/transaction_spec.rb +55 -0
- data/spec/objects/v2/account_spec.rb +211 -0
- data/spec/objects/v2/invoice_spec.rb +53 -0
- data/spec/objects/v2/payment_method_spec.rb +106 -0
- data/spec/objects/v2/transaction_spec.rb +48 -0
- data/spec/payload/arm/arm_request_query_spec.rb +226 -0
- data/spec/payload/arm/attr_spec.rb +216 -0
- data/spec/payload/arm/object_spec.rb +114 -0
- data/spec/payload/arm/request_format_integration_spec.rb +166 -0
- data/spec/payload/arm/request_spec.rb +259 -1
- data/spec/payload/arm/session_spec.rb +40 -0
- data/spec/payload/exceptions_spec.rb +82 -0
- data/spec/support/helpers/v1_helpers.rb +159 -0
- data/spec/support/helpers/v2_helpers.rb +205 -0
- data/spec/support/helpers.rb +15 -0
- data/spec/support/helpers_spec.rb +21 -0
- metadata +28 -6
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "payload"
|
|
4
|
+
require "payload/arm/attr"
|
|
5
|
+
|
|
6
|
+
RSpec.describe Payload::AttrRoot do
|
|
7
|
+
let(:root) { described_class.new }
|
|
8
|
+
|
|
9
|
+
describe "attribute access" do
|
|
10
|
+
it "returns an Attr for any method name" do
|
|
11
|
+
expect(root.id).to be_a(Payload::Attr)
|
|
12
|
+
expect(root.id.to_s).to eq("id")
|
|
13
|
+
expect(root.created_at).to be_a(Payload::Attr)
|
|
14
|
+
expect(root.created_at.to_s).to eq("created_at")
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "returns an Attr for chained property access (non-callable names stay as nested key)" do
|
|
18
|
+
chained = root.sender.account_id
|
|
19
|
+
expect(chained).to be_a(Payload::Attr)
|
|
20
|
+
expect(chained.to_s).to eq("sender[account_id]")
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "treats no-arg access as nested attribute" do
|
|
24
|
+
expect(root.created_at.month.to_s).to eq("created_at[month]")
|
|
25
|
+
expect(root.created_at.year.to_s).to eq("created_at[year]")
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "supports pl.attr.created_at(:month) style (function as symbol arg)" do
|
|
29
|
+
expect(root.created_at(:month).to_s).to eq("month(created_at)")
|
|
30
|
+
expect(root.created_at(:year).to_s).to eq("year(created_at)")
|
|
31
|
+
expect(root.amount(:sum).to_s).to eq("sum(amount)")
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "supports nested attr with symbol: pl.attr.totals.total(:sum) => sum(totals[total])" do
|
|
35
|
+
expect(root.totals.total(:sum).to_s).to eq("sum(totals[total])")
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
RSpec.describe Payload::Attr do
|
|
41
|
+
describe "simple attribute" do
|
|
42
|
+
it "has key and to_s as the param when no parent" do
|
|
43
|
+
attr = Payload::Attr.new("amount")
|
|
44
|
+
expect(attr.key).to eq("amount")
|
|
45
|
+
expect(attr.to_s).to eq("amount")
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
describe "nested attribute" do
|
|
50
|
+
it "builds key and to_s as parent[param]" do
|
|
51
|
+
parent = Payload::Attr.new("totals")
|
|
52
|
+
attr = Payload::Attr.new("total", parent)
|
|
53
|
+
expect(attr.key).to eq("totals[total]")
|
|
54
|
+
expect(attr.to_s).to eq("totals[total]")
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
describe "function form (after .call)" do
|
|
59
|
+
it "serializes as name(parent_key) when marked as method" do
|
|
60
|
+
parent = Payload::Attr.new("created_at")
|
|
61
|
+
attr = Payload::Attr.new("month", parent)
|
|
62
|
+
attr.call
|
|
63
|
+
expect(attr.to_s).to eq("month(created_at)")
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it "serializes nested path in function form" do
|
|
67
|
+
parent = Payload::Attr.new("total", Payload::Attr.new("totals"))
|
|
68
|
+
attr = Payload::Attr.new("sum", parent)
|
|
69
|
+
attr.call
|
|
70
|
+
expect(attr.to_s).to eq("sum(totals[total])")
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
it "raises when chaining after a method" do
|
|
74
|
+
parent = Payload::Attr.new("created_at")
|
|
75
|
+
attr = Payload::Attr.new("month", parent)
|
|
76
|
+
attr.call
|
|
77
|
+
expect { attr.day }.to raise_error(RuntimeError, /cannot get attr of method/)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
describe "#strip" do
|
|
82
|
+
it "returns to_s.strip so Attr works with request.select(*args, **data) and args.map(&:strip)" do
|
|
83
|
+
inner = Payload::Attr.new("created_at")
|
|
84
|
+
year_attr = Payload::Attr.new("year", inner)
|
|
85
|
+
year_attr.call
|
|
86
|
+
expect(year_attr.strip).to eq("year(created_at)")
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
describe "comparisons (return ARMFilter subclasses)" do
|
|
91
|
+
let(:attr_amount) { Payload::Attr.new("amount") }
|
|
92
|
+
let(:attr_status) { Payload::Attr.new("status") }
|
|
93
|
+
|
|
94
|
+
it "== returns ARMEqual with correct attr and opval" do
|
|
95
|
+
f = attr_status == "processed"
|
|
96
|
+
expect(f).to be_a(Payload::ARMEqual)
|
|
97
|
+
expect(f.attr).to eq("status")
|
|
98
|
+
expect(f.opval).to eq("processed")
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it "!= returns ARMNotEqual with ! prefix" do
|
|
102
|
+
f = attr_status != "draft"
|
|
103
|
+
expect(f).to be_a(Payload::ARMNotEqual)
|
|
104
|
+
expect(f.attr).to eq("status")
|
|
105
|
+
expect(f.opval).to eq("!draft")
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
it "> returns ARMGreaterThan" do
|
|
109
|
+
f = attr_amount > 100
|
|
110
|
+
expect(f).to be_a(Payload::ARMGreaterThan)
|
|
111
|
+
expect(f.attr).to eq("amount")
|
|
112
|
+
expect(f.opval).to eq(">100")
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
it "< returns ARMLessThan" do
|
|
116
|
+
f = attr_amount < 500
|
|
117
|
+
expect(f).to be_a(Payload::ARMLessThan)
|
|
118
|
+
expect(f.opval).to eq("<500")
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
it ">= returns ARMGreaterThanEqual" do
|
|
122
|
+
f = attr_amount >= 100
|
|
123
|
+
expect(f).to be_a(Payload::ARMGreaterThanEqual)
|
|
124
|
+
expect(f.opval).to eq(">=100")
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
it "<= returns ARMLessThanEqual" do
|
|
128
|
+
f = attr_amount <= 100
|
|
129
|
+
expect(f).to be_a(Payload::ARMLessThanEqual)
|
|
130
|
+
expect(f.opval).to eq("<=100")
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
it "contains returns ARMContains with ?* op" do
|
|
134
|
+
attr = Payload::Attr.new("description")
|
|
135
|
+
f = attr.contains("INV -")
|
|
136
|
+
expect(f).to be_a(Payload::ARMContains)
|
|
137
|
+
expect(f.attr).to eq("description")
|
|
138
|
+
expect(f.opval).to eq("?*INV -")
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
it "comparisons use Attr key for nested paths" do
|
|
142
|
+
nested = Payload::Attr.new("total", Payload::Attr.new("totals"))
|
|
143
|
+
f = nested > 0
|
|
144
|
+
expect(f.attr).to eq("totals[total]")
|
|
145
|
+
expect(f.opval).to eq(">0")
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
describe "Attr class-level (Payload::Attr.name)" do
|
|
150
|
+
it "returns Attr via method_missing" do
|
|
151
|
+
expect(Payload::Attr.created_at).to be_a(Payload::Attr)
|
|
152
|
+
expect(Payload::Attr.created_at.to_s).to eq("created_at")
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
RSpec.describe Payload::ARMFilter do
|
|
158
|
+
describe "#| (OR)" do
|
|
159
|
+
it "combines two filters on the same attribute and returns ARMEqual with joined opval" do
|
|
160
|
+
left = Payload::ARMGreaterThan.new(Payload::Attr.amount, 100)
|
|
161
|
+
right = Payload::ARMLessThan.new(Payload::Attr.amount, 50)
|
|
162
|
+
combined = left | right
|
|
163
|
+
expect(combined).to be_a(Payload::ARMEqual)
|
|
164
|
+
expect(combined.attr).to eq("amount")
|
|
165
|
+
expect(combined.opval).to eq(">100|<50")
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
it "raises TypeError when other is not an ARMFilter" do
|
|
169
|
+
f = Payload::ARMEqual.new(Payload::Attr.status, "active")
|
|
170
|
+
expect { f | "invalid" }.to raise_error(TypeError, /invalid type/)
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
it "raises ArgumentError when attributes differ" do
|
|
174
|
+
f1 = Payload::ARMEqual.new(Payload::Attr.status, "active")
|
|
175
|
+
f2 = Payload::ARMEqual.new(Payload::Attr.type, "payment")
|
|
176
|
+
expect { f1 | f2 }.to raise_error(ArgumentError, /only works on the same attribute/)
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
describe "filter subclasses op values" do
|
|
181
|
+
it "ARMEqual has empty op" do
|
|
182
|
+
f = Payload::ARMEqual.new("status", "active")
|
|
183
|
+
expect(f.opval).to eq("active")
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
it "ARMNotEqual has ! prefix" do
|
|
187
|
+
f = Payload::ARMNotEqual.new("status", "draft")
|
|
188
|
+
expect(f.opval).to eq("!draft")
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
it "ARMGreaterThan has > prefix" do
|
|
192
|
+
f = Payload::ARMGreaterThan.new("amount", 100)
|
|
193
|
+
expect(f.opval).to eq(">100")
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
it "ARMLessThan has < prefix" do
|
|
197
|
+
f = Payload::ARMLessThan.new("amount", 200)
|
|
198
|
+
expect(f.opval).to eq("<200")
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
it "ARMGreaterThanEqual has >= prefix" do
|
|
202
|
+
f = Payload::ARMGreaterThanEqual.new("amount", 100)
|
|
203
|
+
expect(f.opval).to eq(">=100")
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
it "ARMLessThanEqual has <= prefix" do
|
|
207
|
+
f = Payload::ARMLessThanEqual.new("amount", 100)
|
|
208
|
+
expect(f.opval).to eq("<=100")
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
it "ARMContains has ?* prefix" do
|
|
212
|
+
f = Payload::ARMContains.new("email", "example.com")
|
|
213
|
+
expect(f.opval).to eq("?*example.com")
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
end
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "payload"
|
|
4
|
+
require "payload/arm/object"
|
|
5
|
+
|
|
6
|
+
RSpec.describe Payload::ARMObject do
|
|
7
|
+
describe "method_missing (attribute access)" do
|
|
8
|
+
let(:session) { Payload::Session.new("test_key", "https://api.test.com", "v2") }
|
|
9
|
+
|
|
10
|
+
it "returns value for present key" do
|
|
11
|
+
obj = Payload::Invoice.new({ "id" => "inv_1", "amount" => 100 }, session)
|
|
12
|
+
expect(obj.id).to eq("inv_1")
|
|
13
|
+
expect(obj.amount).to eq(100)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "raises NoMethodError for missing key (strict behavior preserved)" do
|
|
17
|
+
obj = Payload::Invoice.new({ "id" => "inv_1" }, session)
|
|
18
|
+
expect { obj.nonexistent_key }.to raise_error(NoMethodError, /nonexistent_key/)
|
|
19
|
+
expect { obj.amount }.to raise_error(NoMethodError, /amount/)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it "strips trailing = for setter-like names and returns value" do
|
|
23
|
+
obj = Payload::Account.new({ "name" => "Acme" }, session)
|
|
24
|
+
expect(obj.name).to eq("Acme")
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
describe "#json" do
|
|
29
|
+
let(:session) { Payload::Session.new("test_key", "https://api.test.com", "v2") }
|
|
30
|
+
|
|
31
|
+
it "returns same as to_json" do
|
|
32
|
+
obj = Payload::Invoice.new({ "id" => "inv_1", "object" => "invoice" }, session)
|
|
33
|
+
expect(obj.json).to eq(obj.to_json)
|
|
34
|
+
expect(obj.json).to include("inv_1")
|
|
35
|
+
expect(obj.json).to include("invoice")
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
describe ".order_by, .limit, .offset" do
|
|
40
|
+
it "delegates to ARMRequest and returns chainable request" do
|
|
41
|
+
req = Payload::Invoice.order_by("created_at")
|
|
42
|
+
expect(req).to be_a(Payload::ARMRequest)
|
|
43
|
+
expect(req.instance_variable_get(:@order_by)).to include("created_at")
|
|
44
|
+
|
|
45
|
+
req = Payload::Invoice.limit(10)
|
|
46
|
+
expect(req.instance_variable_get(:@limit)).to eq(10)
|
|
47
|
+
|
|
48
|
+
req = Payload::Invoice.offset(20)
|
|
49
|
+
expect(req.instance_variable_get(:@offset)).to eq(20)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
describe ".select" do
|
|
54
|
+
it "delegates to ARMRequest and sets fields filter" do
|
|
55
|
+
req = Payload::Invoice.select("id", "amount")
|
|
56
|
+
expect(req).to be_a(Payload::ARMRequest)
|
|
57
|
+
expect(req.instance_variable_get(:@filters)["fields"]).to eq("id,amount")
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
describe "#[] (bracket access)" do
|
|
62
|
+
let(:session) { Payload::Session.new("test_key", "https://api.test.com", "v2") }
|
|
63
|
+
|
|
64
|
+
it "returns value for string key" do
|
|
65
|
+
obj = Payload::Invoice.new({ "id" => "inv_1", "status" => "open" }, session)
|
|
66
|
+
expect(obj["id"]).to eq("inv_1")
|
|
67
|
+
expect(obj["status"]).to eq("open")
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it "returns value for symbol key (data keys are stored as strings)" do
|
|
71
|
+
obj = Payload::Invoice.new({ "id" => "inv_1" }, session)
|
|
72
|
+
expect(obj[:id]).to eq("inv_1")
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it "returns nil for missing key" do
|
|
76
|
+
obj = Payload::Invoice.new({ "id" => "inv_1" }, session)
|
|
77
|
+
expect(obj["missing"]).to be_nil
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
describe "#to_json" do
|
|
82
|
+
let(:session) { Payload::Session.new("test_key", "https://api.test.com", "v2") }
|
|
83
|
+
|
|
84
|
+
it "includes @data in JSON output" do
|
|
85
|
+
obj = Payload::Invoice.new({ "id" => "inv_1", "object" => "invoice", "amount" => 99 }, session)
|
|
86
|
+
json = obj.to_json
|
|
87
|
+
expect(json).to include("inv_1")
|
|
88
|
+
expect(json).to include("invoice")
|
|
89
|
+
expect(json).to include("99")
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it "merges class poly when present" do
|
|
93
|
+
obj = Payload::Payment.new({ "id" => "txn_1", "object" => "transaction", "type" => "payment" }, session)
|
|
94
|
+
json = obj.to_json
|
|
95
|
+
expect(json).to include("payment")
|
|
96
|
+
expect(json).to include("txn_1")
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
describe "#respond_to_missing?" do
|
|
101
|
+
let(:session) { Payload::Session.new("test_key", "https://api.test.com", "v2") }
|
|
102
|
+
|
|
103
|
+
it "returns true for key present in data" do
|
|
104
|
+
obj = Payload::Invoice.new({ "id" => "inv_1", "amount" => 100 }, session)
|
|
105
|
+
expect(obj.respond_to?(:id)).to be true
|
|
106
|
+
expect(obj.respond_to?(:amount)).to be true
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
it "returns false for key missing from data (so method_missing will call super)" do
|
|
110
|
+
obj = Payload::Invoice.new({ "id" => "inv_1" }, session)
|
|
111
|
+
expect(obj.respond_to?(:nonexistent_key)).to be false
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "payload"
|
|
4
|
+
require "payload/arm/object"
|
|
5
|
+
require_relative "../../support/helpers"
|
|
6
|
+
|
|
7
|
+
RSpec.describe "confirm request format is valid" do
|
|
8
|
+
include_context "test helpers"
|
|
9
|
+
|
|
10
|
+
[1, 2].each do |api_version|
|
|
11
|
+
context "API v#{api_version}" do
|
|
12
|
+
let(:session) { Payload::Session.new(Payload.api_key, Payload.api_url, api_version) }
|
|
13
|
+
let(:pl) { session }
|
|
14
|
+
|
|
15
|
+
context "date functions" do
|
|
16
|
+
it "filter with year(attr) ==" do
|
|
17
|
+
results = pl.Transaction.filter_by(
|
|
18
|
+
pl.attr.type == "payment",
|
|
19
|
+
pl.attr.created_at(:year) == Time.now.year
|
|
20
|
+
).limit(5).all
|
|
21
|
+
expect(results).to be_an(Array)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "filter with month(attr) ==" do
|
|
25
|
+
results = pl.Transaction.filter_by(
|
|
26
|
+
pl.attr.created_at(:month) == Time.now.month
|
|
27
|
+
).limit(5).all
|
|
28
|
+
expect(results).to be_an(Array)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "select with dayname(attr)" do
|
|
32
|
+
results = pl.Transaction.select(
|
|
33
|
+
pl.attr.id,
|
|
34
|
+
pl.attr.created_at(:dayname)
|
|
35
|
+
).limit(5).all
|
|
36
|
+
expect(results).to be_an(Array)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it "group_by year(attr) with count" do
|
|
40
|
+
yearly = pl.Transaction.select(
|
|
41
|
+
pl.attr.created_at(:year),
|
|
42
|
+
pl.attr.id(:count)
|
|
43
|
+
).group_by(pl.attr.created_at(:year)).limit(5).all
|
|
44
|
+
expect(yearly).to be_an(Array)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
context "order_by" do
|
|
49
|
+
it "order_by ascending" do
|
|
50
|
+
results = pl.Transaction.select(pl.attr.id).order_by(pl.attr.created_at).limit(5).all
|
|
51
|
+
expect(results).to be_an(Array)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "order_by descending" do
|
|
55
|
+
results = pl.Transaction.select(pl.attr.id).order_by(pl.attr.created_at(:desc)).limit(5).all
|
|
56
|
+
expect(results).to be_an(Array)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
context "limit, offset, and range" do
|
|
61
|
+
it "limit" do
|
|
62
|
+
results = pl.Transaction.select(pl.attr.id).limit(2).all
|
|
63
|
+
expect(results).to be_an(Array)
|
|
64
|
+
expect(results.length).to be <= 2
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "offset" do
|
|
68
|
+
page1 = pl.Transaction.select(pl.attr.id).limit(3).offset(0).all
|
|
69
|
+
page2 = pl.Transaction.select(pl.attr.id).limit(3).offset(3).all
|
|
70
|
+
expect(page1).to be_an(Array)
|
|
71
|
+
expect(page2).to be_an(Array)
|
|
72
|
+
expect(page1.length).to be <= 3
|
|
73
|
+
expect(page2.length).to be <= 3
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it "range operator []" do
|
|
77
|
+
results = pl.Transaction.select(pl.attr.id)[0..2]
|
|
78
|
+
expect(results).to be_an(Array)
|
|
79
|
+
expect(results.length).to be <= 3
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
context "nested attr" do
|
|
84
|
+
it "select with nested attr (sender.account_id)" do
|
|
85
|
+
results = pl.Transaction.select(
|
|
86
|
+
pl.attr.id,
|
|
87
|
+
pl.attr.sender.account_id
|
|
88
|
+
).filter_by(pl.attr.type == "payment").limit(5).all
|
|
89
|
+
expect(results).to be_an(Array)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
context "filter operators" do
|
|
94
|
+
it "filter with >" do
|
|
95
|
+
results = pl.Transaction.filter_by(
|
|
96
|
+
pl.attr.type == "payment",
|
|
97
|
+
pl.attr.amount > 0
|
|
98
|
+
).select(pl.attr.id, pl.attr.amount).limit(5).all
|
|
99
|
+
expect(results).to be_an(Array)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
it "filter with <" do
|
|
103
|
+
results = pl.Transaction.filter_by(
|
|
104
|
+
pl.attr.type == "payment",
|
|
105
|
+
pl.attr.amount < 1_000_000
|
|
106
|
+
).select(pl.attr.id, pl.attr.amount).limit(5).all
|
|
107
|
+
expect(results).to be_an(Array)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
it "filter with !=" do
|
|
111
|
+
results = pl.Transaction.filter_by(
|
|
112
|
+
pl.attr.type != "nonexistent_type"
|
|
113
|
+
).select(pl.attr.id, pl.attr.type).limit(5).all
|
|
114
|
+
expect(results).to be_an(Array)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it "filter with contains" do
|
|
118
|
+
results = pl.Transaction.filter_by(
|
|
119
|
+
pl.attr.type == "payment",
|
|
120
|
+
pl.attr.description.contains("")
|
|
121
|
+
).select(pl.attr.id, pl.attr.description).limit(5).all
|
|
122
|
+
expect(results).to be_an(Array)
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
context "filter OR (chained conditions)" do
|
|
127
|
+
it "filter with OR (|) on same attribute" do
|
|
128
|
+
or_filter = (pl.attr.amount > 0) | (pl.attr.amount < 1_000_000)
|
|
129
|
+
results = pl.Transaction.filter_by(
|
|
130
|
+
pl.attr.type == "payment",
|
|
131
|
+
or_filter
|
|
132
|
+
).select(pl.attr.id, pl.attr.amount).limit(5).all
|
|
133
|
+
expect(results).to be_an(Array)
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
context "group_by and aggregates" do
|
|
138
|
+
it "group_by with sum and count" do
|
|
139
|
+
results = pl.Transaction.select(
|
|
140
|
+
pl.attr.type,
|
|
141
|
+
pl.attr.amount(:sum),
|
|
142
|
+
pl.attr.id(:count)
|
|
143
|
+
).filter_by(pl.attr.type == "payment").group_by(pl.attr.type).limit(5).all
|
|
144
|
+
expect(results).to be_an(Array)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
it "group_by month(attr) with sum and count" do
|
|
148
|
+
results = pl.Transaction.select(
|
|
149
|
+
pl.attr.created_at(:month),
|
|
150
|
+
pl.attr.amount(:sum),
|
|
151
|
+
pl.attr.id(:count)
|
|
152
|
+
).filter_by(pl.attr.type == "payment").group_by(pl.attr.created_at(:month)).limit(5).all
|
|
153
|
+
expect(results).to be_an(Array)
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
it "group_by year(attr) with count" do
|
|
157
|
+
results = pl.Transaction.select(
|
|
158
|
+
pl.attr.created_at(:year),
|
|
159
|
+
pl.attr.id(:count)
|
|
160
|
+
).filter_by(pl.attr.type == "payment").group_by(pl.attr.created_at(:year)).limit(5).all
|
|
161
|
+
expect(results).to be_an(Array)
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|