sohm 0.0.1 → 0.9.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.
data/test/model.rb CHANGED
@@ -1,18 +1,26 @@
1
+ # coding: utf-8
1
2
  require_relative "helper"
2
3
  require "ostruct"
3
4
 
4
- class Post < Ohm::Model
5
+ class Post < Sohm::Model
6
+ include Sohm::AutoId
7
+
5
8
  attribute :body
6
9
  attribute :published
7
10
  set :related, :Post
8
11
  end
9
12
 
10
- class User < Ohm::Model
13
+ class User < Sohm::Model
14
+ include Sohm::AutoId
15
+
11
16
  attribute :email
12
17
  set :posts, :Post
13
18
  end
14
19
 
15
- class Person < Ohm::Model
20
+ class Person < Sohm::Model
21
+ include Sohm::AutoId
22
+ include Sohm::IndexAll
23
+
16
24
  attribute :name
17
25
  counter :logins
18
26
  index :initial
@@ -22,7 +30,10 @@ class Person < Ohm::Model
22
30
  end
23
31
  end
24
32
 
25
- class Event < Ohm::Model
33
+ class Event < Sohm::Model
34
+ include Sohm::AutoId
35
+ include Sohm::IndexAll
36
+
26
37
  attribute :name
27
38
  counter :votes
28
39
  set :attendees, :Person
@@ -36,16 +47,22 @@ class Event < Ohm::Model
36
47
  end
37
48
 
38
49
  module SomeNamespace
39
- class Foo < Ohm::Model
40
- attribute :name
50
+ class Foo < Sohm::Model
51
+ include Sohm::AutoId
52
+
53
+ attribute :name
41
54
  end
42
55
 
43
- class Bar < Ohm::Model
56
+ class Bar < Sohm::Model
57
+ include Sohm::AutoId
58
+
44
59
  reference :foo, 'SomeNamespace::Foo'
45
60
  end
46
61
  end
47
62
 
48
- class Meetup < Ohm::Model
63
+ class Meetup < Sohm::Model
64
+ include Sohm::AutoId
65
+
49
66
  attribute :name
50
67
  attribute :location
51
68
  end
@@ -60,12 +77,13 @@ test "booleans" do
60
77
 
61
78
  post = Post[post.id]
62
79
 
63
- assert_equal "true", post.body
80
+ assert_equal true, post.body
64
81
  assert_equal nil, post.published
65
82
  end
66
83
 
67
84
  test "empty model is ok" do
68
- class Foo < Ohm::Model
85
+ class Foo < Sohm::Model
86
+ include Sohm::AutoId
69
87
  end
70
88
 
71
89
  Foo.create
@@ -81,29 +99,6 @@ test "counters are cleaned up during deletion" do
81
99
  assert_equal 0, Event.redis.call("EXISTS", e.key[:counters])
82
100
  end
83
101
 
84
- test "get" do
85
- m = Meetup.create(:name => "Foo")
86
- m.name = "Bar"
87
-
88
- assert_equal "Foo", m.get(:name)
89
- assert_equal "Foo", m.name
90
- end
91
-
92
- test "set" do
93
- m = Meetup.create(:name => "Foo")
94
-
95
- m.set :name, "Bar"
96
- assert_equal "Bar", m.name
97
-
98
- m = Meetup[m.id]
99
- assert_equal "Bar", m.name
100
-
101
- # Deletes when value is nil.
102
- m.set :name, nil
103
- m = Meetup[m.id]
104
- assert_equal 0, Meetup.redis.call("HEXISTS", m.key, :name)
105
- end
106
-
107
102
  test "assign attributes from the hash" do
108
103
  event = Event.new(:name => "Ruby Tuesday")
109
104
  assert event.name == "Ruby Tuesday"
@@ -136,7 +131,9 @@ test "delete the attribute if set to nil" do
136
131
  end
137
132
 
138
133
  test "not raise if an attribute is redefined" do
139
- class RedefinedModel < Ohm::Model
134
+ class RedefinedModel < Sohm::Model
135
+ include Sohm::AutoId
136
+
140
137
  attribute :name
141
138
 
142
139
  silence_warnings do
@@ -146,7 +143,9 @@ test "not raise if an attribute is redefined" do
146
143
  end
147
144
 
148
145
  test "not raise if a counter is redefined" do
149
- class RedefinedModel < Ohm::Model
146
+ class RedefinedModel < Sohm::Model
147
+ include Sohm::AutoId
148
+
150
149
  counter :age
151
150
 
152
151
  silence_warnings do
@@ -156,7 +155,9 @@ test "not raise if a counter is redefined" do
156
155
  end
157
156
 
158
157
  test "not raise if a set is redefined" do
159
- class RedefinedModel < Ohm::Model
158
+ class RedefinedModel < Sohm::Model
159
+ include Sohm::AutoId
160
+
160
161
  set :friends, lambda { }
161
162
 
162
163
  silence_warnings do
@@ -166,7 +167,9 @@ test "not raise if a set is redefined" do
166
167
  end
167
168
 
168
169
  test "not raise if a collection is redefined" do
169
- class RedefinedModel < Ohm::Model
170
+ class RedefinedModel < Sohm::Model
171
+ include Sohm::AutoId
172
+
170
173
  set :toys, lambda { }
171
174
 
172
175
  silence_warnings do
@@ -176,7 +179,9 @@ test "not raise if a collection is redefined" do
176
179
  end
177
180
 
178
181
  test "not raise if a index is redefined" do
179
- class RedefinedModel < Ohm::Model
182
+ class RedefinedModel < Sohm::Model
183
+ include Sohm::AutoId
184
+
180
185
  attribute :color
181
186
  index :color
182
187
  index :color
@@ -190,17 +195,9 @@ test "allow arbitrary IDs" do
190
195
  assert Event["abc123"].name == "Concert"
191
196
  end
192
197
 
193
- test "forbid assignment of IDs on a new object" do
194
- event = Event.new(:name => "Concert")
195
-
196
- assert_raise(NoMethodError) do
197
- event.id = "abc123"
198
- end
199
- end
200
-
201
198
  setup do
202
- Ohm.redis.call("SADD", "Event:all", 1)
203
- Ohm.redis.call("HSET", "Event:1", "name", "Concert")
199
+ Sohm.redis.call("SADD", "Event:all", 1)
200
+ Sohm.redis.call("HSET", "Event:1", "name", "Concert")
204
201
  end
205
202
 
206
203
  test "return an instance of Event" do
@@ -210,8 +207,8 @@ test "return an instance of Event" do
210
207
  end
211
208
 
212
209
  setup do
213
- Ohm.redis.call("SADD", "User:all", 1)
214
- Ohm.redis.call("HSET", "User:1", "email", "albert@example.com")
210
+ Sohm.redis.call("SADD", "User:all", 1)
211
+ Sohm.redis.call("HSET", "User:1", "email", "albert@example.com")
215
212
  end
216
213
 
217
214
  test "return an instance of User" do
@@ -225,8 +222,8 @@ test "allow to map key to models" do
225
222
  end
226
223
 
227
224
  setup do
228
- Ohm.redis.call("SADD", "User:all", 1)
229
- Ohm.redis.call("SET", "User:1:email", "albert@example.com")
225
+ Sohm.redis.call("INCR", "User:_id")
226
+ Sohm.redis.call("HSET", "User:1", "_ndata", "\x81\xa5email\xb2albert@example.com")
230
227
 
231
228
  @user = User[1]
232
229
  end
@@ -294,7 +291,10 @@ end
294
291
 
295
292
  # Delete
296
293
  test "delete an existing model" do
297
- class ModelToBeDeleted < Ohm::Model
294
+ class ModelToBeDeleted < Sohm::Model
295
+ include Sohm::AutoId
296
+ include Sohm::IndexAll
297
+
298
298
  attribute :name
299
299
  set :foos, :Post
300
300
  set :bars, :Post
@@ -309,10 +309,10 @@ test "delete an existing model" do
309
309
 
310
310
  @model.delete
311
311
 
312
- assert Ohm.redis.call("GET", ModelToBeDeleted.key[id]).nil?
313
- assert Ohm.redis.call("GET", ModelToBeDeleted.key[id][:name]).nil?
314
- assert Array.new == Ohm.redis.call("SMEMBERS", ModelToBeDeleted.key[id][:foos])
315
- assert Array.new == Ohm.redis.call("LRANGE", ModelToBeDeleted.key[id][:bars], 0, -1)
312
+ assert Sohm.redis.call("GET", ModelToBeDeleted.key[id]).nil?
313
+ assert Sohm.redis.call("GET", ModelToBeDeleted.key[id][:name]).nil?
314
+ assert Array.new == Sohm.redis.call("SMEMBERS", ModelToBeDeleted.key[id][:foos])
315
+ assert Array.new == Sohm.redis.call("LRANGE", ModelToBeDeleted.key[id][:bars], 0, -1)
316
316
 
317
317
  assert ModelToBeDeleted.all.empty?
318
318
  end
@@ -321,33 +321,35 @@ setup do
321
321
  end
322
322
 
323
323
  test "no leftover keys" do
324
- class ::Foo < Ohm::Model
324
+ class ::Foo < Sohm::Model
325
+ include Sohm::AutoId
326
+
325
327
  attribute :name
326
328
  index :name
327
329
  track :notes
328
330
  end
329
331
 
330
- assert_equal [], Ohm.redis.call("KEYS", "*")
332
+ assert_equal [], Sohm.redis.call("KEYS", "*")
331
333
 
332
334
  Foo.create(:name => "Bar")
333
- expected = %w[Foo:1:_indices Foo:1 Foo:all Foo:id Foo:indices:name:Bar]
335
+ expected = %w[Foo:1:_indices Foo:1 Foo:_id Foo:_indices:name:Bar]
334
336
 
335
- assert_equal expected.sort, Ohm.redis.call("KEYS", "*").sort
337
+ assert_equal expected.sort, Sohm.redis.call("KEYS", "*").sort
336
338
 
337
339
  Foo[1].delete
338
- assert ["Foo:id"] == Ohm.redis.call("KEYS", "*")
340
+ assert ["Foo:_id"] == Sohm.redis.call("KEYS", "*")
339
341
 
340
342
  Foo.create(:name => "Baz")
341
343
 
342
- Ohm.redis.call("SET", Foo[2].key[:notes], "something")
344
+ Sohm.redis.call("SET", Foo[2].key[:notes], "something")
343
345
 
344
- expected = %w[Foo:2:_indices Foo:2 Foo:all Foo:id
345
- Foo:indices:name:Baz Foo:2:notes]
346
+ expected = %w[Foo:2:_indices Foo:2 Foo:_id
347
+ Foo:_indices:name:Baz Foo:2:notes]
346
348
 
347
- assert_equal expected.sort, Ohm.redis.call("KEYS", "*").sort
349
+ assert_equal expected.sort, Sohm.redis.call("KEYS", "*").sort
348
350
 
349
351
  Foo[2].delete
350
- assert ["Foo:id"] == Ohm.redis.call("KEYS", "*")
352
+ assert ["Foo:_id"] == Sohm.redis.call("KEYS", "*")
351
353
  end
352
354
 
353
355
  # Listing
@@ -373,55 +375,6 @@ test "fetch ids" do
373
375
  assert_equal [event1, event2], Event.fetch([event1.id, event2.id])
374
376
  end
375
377
 
376
- # Sorting
377
- test "sort all" do
378
- Person.create :name => "D"
379
- Person.create :name => "C"
380
- Person.create :name => "B"
381
- Person.create :name => "A"
382
-
383
- names = Person.all.sort_by(:name, :order => "ALPHA").map { |p| p.name }
384
- assert %w[A B C D] == names
385
- end
386
-
387
- test "return an empty array if there are no elements to sort" do
388
- assert [] == Person.all.sort_by(:name)
389
- end
390
-
391
- test "return the first element sorted by id when using first" do
392
- Person.create :name => "A"
393
- Person.create :name => "B"
394
- assert "A" == Person.all.first.name
395
- end
396
-
397
- test "return the first element sorted by name if first receives a sorting option" do
398
- Person.create :name => "B"
399
- Person.create :name => "A"
400
- assert "A" == Person.all.first(:by => :name, :order => "ALPHA").name
401
- end
402
-
403
- test "return attribute values when the get parameter is specified" do
404
- Person.create :name => "B"
405
- Person.create :name => "A"
406
-
407
- res = Person.all.sort_by(:name, :get => :name, :order => "ALPHA")
408
-
409
- assert_equal ["A", "B"], res
410
- end
411
-
412
- test "work on lists" do
413
- post = Post.create :body => "Hello world!"
414
-
415
- redis = Post.redis
416
-
417
- redis.call("RPUSH", post.related.key, Post.create(:body => "C").id)
418
- redis.call("RPUSH", post.related.key, Post.create(:body => "B").id)
419
- redis.call("RPUSH", post.related.key, Post.create(:body => "A").id)
420
-
421
- res = post.related.sort_by(:body, :order => "ALPHA ASC").map { |r| r.body }
422
- assert_equal ["A", "B", "C"], res
423
- end
424
-
425
378
  # Loading attributes
426
379
  setup do
427
380
  event = Event.new
@@ -429,14 +382,16 @@ setup do
429
382
  event.save.id
430
383
  end
431
384
 
432
- test "load attributes as a strings" do
385
+ test "load attributes as native type" do
433
386
  event = Event.create(:name => 1)
434
387
 
435
- assert "1" == Event[event.id].name
388
+ assert 1 == Event[event.id].name
436
389
  end
437
390
 
438
391
  # Enumerable indices
439
- class Entry < Ohm::Model
392
+ class Entry < Sohm::Model
393
+ include Sohm::AutoId
394
+
440
395
  attribute :tags
441
396
  index :tag
442
397
 
@@ -493,7 +448,7 @@ test "delete elements" do
493
448
  end
494
449
 
495
450
  test "not be available if the model is new" do
496
- assert_raise Ohm::MissingID do
451
+ assert_raise Sohm::MissingID do
497
452
  @event.attendees
498
453
  end
499
454
  end
@@ -545,52 +500,6 @@ test "empty the set" do
545
500
  assert @event.attendees.empty?
546
501
  end
547
502
 
548
- test "replace the values in the set" do
549
- @event.save
550
- @event.attendees.add(@person1)
551
-
552
- assert [@person1] == @event.attendees.to_a
553
-
554
- @event.attendees.replace([@person2, @person3])
555
-
556
- assert [@person2, @person3] == @event.attendees.to_a.sort_by(&:id)
557
- end
558
-
559
- # Sorting lists and sets by model attributes
560
- setup do
561
- @event = Event.create(:name => "Ruby Tuesday")
562
- {'D' => 4, 'C' => 2, 'B' => 5, 'A' => 3}.each_pair do |name, logins|
563
- person = Person.create(:name => name)
564
- person.incr :logins, logins
565
- @event.attendees.add(person)
566
- end
567
- end
568
-
569
- test "sort the model instances by the values provided" do
570
- people = @event.attendees.sort_by(:name, :order => "ALPHA")
571
- assert %w[A B C D] == people.map(&:name)
572
- end
573
-
574
- test "accept a number in the limit parameter" do
575
- people = @event.attendees.sort_by(:name, :limit => [0, 2], :order => "ALPHA")
576
- assert %w[A B] == people.map(&:name)
577
- end
578
-
579
- test "use the start parameter as an offset if the limit is provided" do
580
- people = @event.attendees.sort_by(:name, :limit => [1, 2], :order => "ALPHA")
581
- assert %w[B C] == people.map(&:name)
582
- end
583
-
584
- test "use counter attributes for sorting" do
585
- people = @event.attendees.sort_by(:logins, :limit => [0, 3], :order => "ALPHA")
586
- assert %w[C A D] == people.map(&:name)
587
- end
588
-
589
- test "use counter attributes for sorting with key option" do
590
- people = @event.attendees.sort_by(:logins, :get => :logins, :limit => [0, 3], :order => "ALPHA")
591
- assert %w[2 3 4] == people
592
- end
593
-
594
503
  # Collections initialized with a Model parameter
595
504
  setup do
596
505
  @user = User.create(:email => "albert@example.com")
@@ -670,7 +579,9 @@ test "be comparable to non-models" do
670
579
  end
671
580
 
672
581
  # Debugging
673
- class ::Bar < Ohm::Model
582
+ class ::Bar < Sohm::Model
583
+ include Sohm::AutoId
584
+
674
585
  attribute :name
675
586
  counter :visits
676
587
  set :friends, self
@@ -690,13 +601,19 @@ class ::Bar < Ohm::Model
690
601
  end
691
602
 
692
603
  # Models connected to different databases
693
- class ::Car < Ohm::Model
604
+ class ::Car < Sohm::Model
605
+ include Sohm::AutoId
606
+ include Sohm::IndexAll
607
+
694
608
  attribute :name
695
609
 
696
610
  self.redis = Redic.new
697
611
  end
698
612
 
699
- class ::Make < Ohm::Model
613
+ class ::Make < Sohm::Model
614
+ include Sohm::AutoId
615
+ include Sohm::IndexAll
616
+
700
617
  attribute :name
701
618
  end
702
619
 
@@ -710,11 +627,11 @@ test "save to the selected database" do
710
627
 
711
628
  redis = Redic.new
712
629
 
713
- assert ["1"] == redis.call("SMEMBERS", "Make:all")
714
- assert [] == redis.call("SMEMBERS", "Car:all")
630
+ assert ["1"] == redis.call("SMEMBERS", "Make:_indices:all:all")
631
+ assert [] == redis.call("SMEMBERS", "Car:_indices:all:all")
715
632
 
716
- assert ["1"] == Car.redis.call("SMEMBERS", "Car:all")
717
- assert [] == Car.redis.call("SMEMBERS", "Make:all")
633
+ assert ["1"] == Car.redis.call("SMEMBERS", "Car:_indices:all:all")
634
+ assert [] == Car.redis.call("SMEMBERS", "Make:_indices:all:all")
718
635
 
719
636
  assert car == Car[1]
720
637
  assert make == Make[1]
@@ -741,10 +658,10 @@ test "persist attributes to a hash" do
741
658
  event = Event.create(:name => "Redis Meetup")
742
659
  event.incr(:votes)
743
660
 
744
- assert "hash" == Ohm.redis.call("TYPE", "Event:1")
661
+ assert "hash" == Sohm.redis.call("TYPE", "Event:1")
745
662
 
746
- expected= %w[Event:1 Event:1:counters Event:all Event:id]
747
- assert_equal expected, Ohm.redis.call("KEYS", "Event:*").sort
663
+ expected= %w[Event:1 Event:1:_indices Event:_indices:all:all Event:1:_counters Event:_id]
664
+ assert_equal expected.sort, Sohm.redis.call("KEYS", "Event:*").sort
748
665
 
749
666
  assert "Redis Meetup" == Event[1].name
750
667
  assert 1 == Event[1].votes
@@ -756,14 +673,16 @@ test "be persisted" do
756
673
 
757
674
  SomeNamespace::Bar.create(:foo => SomeNamespace::Foo[1])
758
675
 
759
- assert "hash" == Ohm.redis.call("TYPE", "SomeNamespace::Foo:1")
676
+ assert "hash" == Sohm.redis.call("TYPE", "SomeNamespace::Foo:1")
760
677
 
761
678
  assert "foo" == SomeNamespace::Foo[1].name
762
679
  assert "foo" == SomeNamespace::Bar[1].foo.name
763
680
  end if RUBY_VERSION >= "2.0.0"
764
681
 
765
682
  test "typecast attributes" do
766
- class Option < Ohm::Model
683
+ class Option < Sohm::Model
684
+ include Sohm::AutoId
685
+
767
686
  attribute :votes, lambda { |x| x.to_i }
768
687
  end
769
688
 
@@ -775,7 +694,9 @@ end
775
694
 
776
695
  test "poster-example for overriding writers" do
777
696
  silence_warnings do
778
- class Advertiser < Ohm::Model
697
+ class Advertiser < Sohm::Model
698
+ include Sohm::AutoId
699
+
779
700
  attribute :email
780
701
 
781
702
  def email=(e)
data/test/set.rb CHANGED
@@ -1,9 +1,13 @@
1
1
  require_relative 'helper'
2
2
 
3
- class Post < Ohm::Model
3
+ class Post < Sohm::Model
4
+ include Sohm::AutoId
4
5
  end
5
6
 
6
- class User < Ohm::Model
7
+ class User < Sohm::Model
8
+ include Sohm::AutoId
9
+ include Sohm::IndexAll
10
+
7
11
  attribute :name
8
12
 
9
13
  index :name
data/test/sohm.rb ADDED
@@ -0,0 +1,44 @@
1
+ # coding: utf-8
2
+ require_relative "helper"
3
+
4
+ class Model < Sohm::Model
5
+ attribute :name
6
+ serial_attribute :score
7
+
8
+ index :name
9
+ end
10
+
11
+ # Sohm-specific tests
12
+ test "ID is required" do
13
+ assert_raise Sohm::MissingID do
14
+ Model.create
15
+ end
16
+ end
17
+
18
+ test "filtering#sample" do
19
+ Model.create(name: "a", id: 1)
20
+ Model.create(name: "b", id: 2)
21
+ Model.create(name: "b", id: 3)
22
+
23
+ assert_equal "1", Model.find(name: "a").sample.id
24
+
25
+ assert ["2", "3"].include?(Model.find(name: "b").sample.id)
26
+ end
27
+
28
+ test "serial attributes require cas token to be set" do
29
+ model = Model.new(name: "a", score: 5, id: 1)
30
+ model2 = Model.new(name: "a", score: 5, id: 1)
31
+
32
+ model2.save
33
+
34
+ assert_raise Sohm::CasViolation do
35
+ model.save
36
+ end
37
+
38
+ model3 = Model[1]
39
+ model3.update(score: 6)
40
+
41
+ assert_raise Sohm::CasViolation do
42
+ model2.update(score: 7)
43
+ end
44
+ end
data/test/to_hash.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require_relative 'helper'
2
2
 
3
- class User < Ohm::Model
3
+ class User < Sohm::Model
4
+ include Sohm::AutoId
4
5
  end
5
6
 
6
7
  test "returns an empty hash if model doesn't have set attributes" do
@@ -13,7 +14,9 @@ test "returns a hash with its id if model is persisted" do
13
14
  assert_equal Hash[id: user.id], user.to_hash
14
15
  end
15
16
 
16
- class Person < Ohm::Model
17
+ class Person < Sohm::Model
18
+ include Sohm::AutoId
19
+
17
20
  attribute :name
18
21
 
19
22
  def to_hash
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sohm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Xuejie Xiao
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-09 00:00:00.000000000 Z
11
+ date: 2015-04-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redic
@@ -76,6 +76,8 @@ extra_rdoc_files: []
76
76
  files:
77
77
  - ".gems"
78
78
  - ".gitignore"
79
+ - ".travis.gemfile"
80
+ - ".travis.yml"
79
81
  - CHANGELOG.md
80
82
  - LICENSE
81
83
  - README.md
@@ -90,11 +92,11 @@ files:
90
92
  - examples/redis-logging.txt
91
93
  - examples/slug.rb
92
94
  - examples/tagging.rb
93
- - lib/sample.rb
94
95
  - lib/sohm.rb
96
+ - lib/sohm/auto_id.rb
95
97
  - lib/sohm/command.rb
98
+ - lib/sohm/index_all.rb
96
99
  - lib/sohm/json.rb
97
- - lib/sohm/lua/delete.lua
98
100
  - lib/sohm/lua/save.lua
99
101
  - makefile
100
102
  - sohm.gemspec
@@ -112,9 +114,8 @@ files:
112
114
  - test/list.rb
113
115
  - test/model.rb
114
116
  - test/set.rb
115
- - test/thread_safety.rb
117
+ - test/sohm.rb
116
118
  - test/to_hash.rb
117
- - test/uniques.rb
118
119
  homepage: https://github.com/xxuejie/sohm
119
120
  licenses:
120
121
  - MIT
data/lib/sample.rb DELETED
@@ -1,14 +0,0 @@
1
- $:.unshift(File.dirname(__FILE__))
2
- require 'sohm'
3
-
4
- class User < Sohm::Model
5
- attribute :age
6
- attribute :name
7
-
8
- serial_attribute :desc
9
- serial_attribute :list
10
-
11
- index :age
12
- index :desc
13
- index :list
14
- end