jsonapi-resources 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,585 @@
1
+ require 'active_record'
2
+ require 'jsonapi/resource_controller'
3
+ require 'jsonapi/resource'
4
+ require 'jsonapi/exceptions'
5
+ require 'rails'
6
+ require 'rails/all'
7
+
8
+ ### DATABASE
9
+ ActiveRecord::Schema.define do
10
+ create_table :people, force: true do |t|
11
+ t.string :name
12
+ t.string :email
13
+ t.datetime :date_joined
14
+ t.timestamps
15
+ end
16
+
17
+ create_table :posts, force: true do |t|
18
+ t.string :title
19
+ t.text :body
20
+ t.integer :author_id
21
+ t.belongs_to :section, index: true
22
+ t.timestamps
23
+ end
24
+
25
+ create_table :comments, force: true do |t|
26
+ t.text :body
27
+ t.belongs_to :post, index: true
28
+ t.integer :author_id
29
+ t.timestamps
30
+ end
31
+
32
+ create_table :tags, force: true do |t|
33
+ t.string :name
34
+ end
35
+
36
+ create_table :sections, force: true do |t|
37
+ t.string :name
38
+ end
39
+
40
+ create_table :posts_tags, force: true do |t|
41
+ t.references :post, :tag, index: true
42
+ end
43
+
44
+ create_table :comments_tags, force: true do |t|
45
+ t.references :comment, :tag, index: true
46
+ end
47
+
48
+ create_table :currencies, id: false, force: true do |t|
49
+ t.string :code, limit: 3, null: false
50
+ t.string :name
51
+ t.timestamps
52
+ end
53
+ add_index :currencies, :code, unique: true
54
+
55
+ create_table :expense_entries, force: true do |t|
56
+ t.string :currency_code, limit: 3, null: false
57
+ t.integer :employee_id, null: false
58
+ t.decimal :cost, precision: 12, scale: 4, null: false
59
+ t.date :transaction_date
60
+ end
61
+
62
+ create_table :planets, force: true do |t|
63
+ t.string :name
64
+ t.string :description
65
+ t.integer :planet_type_id
66
+ end
67
+
68
+ create_table :planet_types, force: true do |t|
69
+ t.string :name
70
+ end
71
+
72
+ create_table :moons, force: true do |t|
73
+ t.string :name
74
+ t.string :description
75
+ t.integer :planet_id
76
+ end
77
+
78
+ create_table :preferences, force: true do |t|
79
+ t.integer :person_id
80
+ t.boolean :advanced_mode, default: false
81
+ end
82
+ end
83
+
84
+ ### MODELS
85
+ class Person < ActiveRecord::Base
86
+ has_many :posts, foreign_key: 'author_id'
87
+ has_many :comments, foreign_key: 'author_id'
88
+ has_many :expense_entries, foreign_key: 'employee_id', dependent: :restrict_with_exception
89
+
90
+ ### Validations
91
+ validates :name, presence: true
92
+ validates :date_joined, presence: true
93
+ end
94
+
95
+ class Post < ActiveRecord::Base
96
+ belongs_to :author, class_name: 'Person', foreign_key: 'author_id'
97
+ has_many :comments
98
+ has_and_belongs_to_many :tags, join_table: :posts_tags
99
+ belongs_to :section
100
+
101
+ validates :author, presence: true
102
+ end
103
+
104
+ class Comment < ActiveRecord::Base
105
+ belongs_to :author, class_name: 'Person', foreign_key: 'author_id'
106
+ belongs_to :post
107
+ has_and_belongs_to_many :tags, join_table: :comments_tags
108
+ end
109
+
110
+ class Tag < ActiveRecord::Base
111
+ has_and_belongs_to_many :posts, join_table: :posts_tags
112
+ end
113
+
114
+ class Section < ActiveRecord::Base
115
+ end
116
+
117
+ class Currency < ActiveRecord::Base
118
+ self.primary_key = :code
119
+ has_many :expense_entries, foreign_key: 'currency_code'
120
+ end
121
+
122
+ class ExpenseEntry < ActiveRecord::Base
123
+ belongs_to :employee, class_name: 'Person', foreign_key: 'employee_id'
124
+ belongs_to :currency, class_name: 'Currency', foreign_key: 'currency_code'
125
+ end
126
+
127
+ class Planet < ActiveRecord::Base
128
+ has_many :moons
129
+ has_one :planet_type
130
+ end
131
+
132
+ class PlanetType < ActiveRecord::Base
133
+ has_many :planets
134
+ end
135
+
136
+ class Moon < ActiveRecord::Base
137
+ belongs_to :planet
138
+ end
139
+
140
+ class Breed
141
+
142
+ def initialize(id = nil, name = nil)
143
+ if id.nil?
144
+ @id = $breed_data.new_id
145
+ $breed_data.add(self)
146
+ else
147
+ @id = id
148
+ end
149
+ @name = name
150
+ end
151
+
152
+ attr_accessor :id, :name
153
+
154
+ def destroy
155
+ $breed_data.remove(@id)
156
+ end
157
+
158
+ def save!
159
+ end
160
+ end
161
+
162
+ class BreedData
163
+ def initialize
164
+ @breeds = {}
165
+ end
166
+
167
+ def breeds
168
+ @breeds
169
+ end
170
+
171
+ def new_id
172
+ @breeds.keys.max + 1
173
+ end
174
+
175
+ def add(breed)
176
+ @breeds[breed.id] = breed
177
+ end
178
+
179
+ def remove(id)
180
+ @breeds.delete(id)
181
+ end
182
+
183
+ end
184
+
185
+ ### PORO Data - don't do this in a production app
186
+ $breed_data = BreedData.new
187
+ $breed_data.add(Breed.new(0, 'persian'))
188
+ $breed_data.add(Breed.new(1, 'siamese'))
189
+ $breed_data.add(Breed.new(2, 'sphinx'))
190
+ $breed_data.add(Breed.new(3, 'to_delete'))
191
+
192
+ ### CONTROLLERS
193
+ class AuthorsController < JSONAPI::ResourceController
194
+
195
+ end
196
+
197
+ class PeopleController < JSONAPI::ResourceController
198
+
199
+ end
200
+
201
+ class PostsController < JSONAPI::ResourceController
202
+ end
203
+
204
+ class TagsController < JSONAPI::ResourceController
205
+ end
206
+
207
+ class CurrenciesController < JSONAPI::ResourceController
208
+ end
209
+
210
+ class ExpenseEntriesController < JSONAPI::ResourceController
211
+ end
212
+
213
+ class BreedsController < JSONAPI::ResourceController
214
+ end
215
+
216
+ ### CONTROLLERS
217
+ module Api
218
+ module V1
219
+ class AuthorsController < JSONAPI::ResourceController
220
+ end
221
+
222
+ class PeopleController < JSONAPI::ResourceController
223
+ end
224
+
225
+ class PostsController < JSONAPI::ResourceController
226
+ end
227
+
228
+ class TagsController < JSONAPI::ResourceController
229
+ end
230
+
231
+ class CurrenciesController < JSONAPI::ResourceController
232
+ end
233
+
234
+ class ExpenseEntriesController < JSONAPI::ResourceController
235
+ end
236
+
237
+ class BreedsController < JSONAPI::ResourceController
238
+ end
239
+ end
240
+
241
+ module V2
242
+ class AuthorsController < JSONAPI::ResourceController
243
+ end
244
+
245
+ class PeopleController < JSONAPI::ResourceController
246
+ end
247
+
248
+ class PostsController < JSONAPI::ResourceController
249
+ end
250
+
251
+ class PreferencesController < JSONAPI::ResourceController
252
+ end
253
+ end
254
+
255
+ module V3
256
+ class PostsController < JSONAPI::ResourceController
257
+ end
258
+ end
259
+ end
260
+
261
+ ### RESOURCES
262
+ class PersonResource < JSONAPI::Resource
263
+ attributes :id, :name, :email, :date_joined
264
+ has_many :comments
265
+ has_many :posts
266
+
267
+ filter :name
268
+
269
+ def self.verify_custom_filter(filter, values, context = nil)
270
+ case filter
271
+ when :name
272
+ values.each do |value|
273
+ if value.length < 3
274
+ raise JSONAPI::Exceptions::InvalidFilterValue.new(filter, value)
275
+ end
276
+ end
277
+ end
278
+ return filter, values
279
+ end
280
+ end
281
+
282
+ class AuthorResource < JSONAPI::Resource
283
+ attributes :id, :name, :email
284
+ model_name 'Person'
285
+ has_many :posts
286
+
287
+ filter :name
288
+
289
+ def self.find(filters, context = nil)
290
+ resources = []
291
+
292
+ filters.each do |attr, filter|
293
+ _model_class.where("\"#{attr}\" LIKE \"%#{filter[0]}%\"").each do |object|
294
+ resources.push self.new(object)
295
+ end
296
+ end
297
+ return resources
298
+ end
299
+
300
+ def fetchable(keys, context = nil)
301
+ if (@object.id % 2) == 1
302
+ super(keys - [:email])
303
+ else
304
+ super(keys)
305
+ end
306
+ end
307
+ end
308
+
309
+ class CommentResource < JSONAPI::Resource
310
+ attributes :id, :body
311
+ has_one :post
312
+ has_one :author, class_name: 'Person'
313
+ has_many :tags
314
+ end
315
+
316
+ class TagResource < JSONAPI::Resource
317
+ attributes :id, :name
318
+
319
+ has_many :posts
320
+ end
321
+
322
+ class SectionResource < JSONAPI::Resource
323
+ attributes 'name'
324
+ end
325
+
326
+ class PostResource < JSONAPI::Resource
327
+ attribute :id
328
+ attribute :title
329
+ attribute :body
330
+ attribute :subject
331
+
332
+ has_one :author, class_name: 'Person'
333
+ has_one :section
334
+ has_many :tags, treat_as_set: true
335
+ has_many :comments, treat_as_set: false
336
+ def subject
337
+ @object.title
338
+ end
339
+
340
+ filters :title, :author, :tags, :comments
341
+ filter :id
342
+
343
+ def self.updateable(keys, context = nil)
344
+ super(keys - [:author, :subject])
345
+ end
346
+
347
+ def self.createable(keys, context = nil)
348
+ super(keys - [:subject])
349
+ end
350
+
351
+ def self.verify_custom_filter(filter, values, context = nil)
352
+ case filter
353
+ when :id
354
+ values.each do |key|
355
+ verify_key(key, context)
356
+ end
357
+ end
358
+ return filter, values
359
+ end
360
+
361
+ def self.is_num?(str)
362
+ begin
363
+ !!Integer(str)
364
+ rescue ArgumentError, TypeError
365
+ false
366
+ end
367
+ end
368
+
369
+ def self.verify_key(key, context = nil)
370
+ raise JSONAPI::Exceptions::InvalidFieldValue.new(:id, key) unless is_num?(key)
371
+ raise JSONAPI::Exceptions::RecordNotFound.new(key) unless find_by_key(key)
372
+ return key
373
+ end
374
+ end
375
+
376
+ class CurrencyResource < JSONAPI::Resource
377
+ key :code
378
+ attributes :code, :name
379
+
380
+ routing_options :param => :code
381
+
382
+ has_many :expense_entries
383
+ end
384
+
385
+ class ExpenseEntryResource < JSONAPI::Resource
386
+ attributes :id, :cost, :transaction_date
387
+
388
+ has_one :currency, class_name: 'Currency', key: 'currency_code'
389
+ has_one :employee
390
+ end
391
+
392
+ class BreedResource < JSONAPI::Resource
393
+ attributes :id, :name
394
+
395
+ def self.find(attrs, context = nil)
396
+ breeds = []
397
+ $breed_data.breeds.values.each do |breed|
398
+ breeds.push(BreedResource.new(breed))
399
+ end
400
+ breeds
401
+ end
402
+
403
+ def self.find_by_key(id, context = nil)
404
+ BreedResource.new($breed_data.breeds[id.to_i])
405
+ end
406
+ end
407
+
408
+ class PlanetResource < JSONAPI::Resource
409
+ attribute :id
410
+ attribute :name
411
+ attribute :description
412
+
413
+ has_many :moons
414
+ has_one :planet_type
415
+ end
416
+
417
+ class PlanetTypeResource < JSONAPI::Resource
418
+ attribute :name
419
+ has_many :planets
420
+ end
421
+
422
+ class MoonResource < JSONAPI::Resource
423
+ attribute :id
424
+ attribute :name
425
+ attribute :description
426
+
427
+ has_one :planet
428
+ end
429
+
430
+ class PreferencesResource < JSONAPI::Resource
431
+ attribute :id
432
+ attribute :advanced_mode
433
+
434
+ has_one :author, class_name: 'Person'
435
+ has_many :friends, class_name: 'Person'
436
+ end
437
+
438
+ ### DATA
439
+ javascript = Section.create(name: 'javascript')
440
+ ruby = Section.create(name: 'ruby')
441
+
442
+ a = Person.create(name: 'Joe Author',
443
+ email: 'joe@xyz.fake',
444
+ date_joined: DateTime.parse('2013-08-07 20:25:00 UTC +00:00'))
445
+
446
+ b = Person.create(name: 'Fred Reader',
447
+ email: 'fred@xyz.fake',
448
+ date_joined: DateTime.parse('2013-10-31 20:25:00 UTC +00:00'))
449
+
450
+ c = Person.create(name: 'Lazy Author',
451
+ email: 'lazy@xyz.fake',
452
+ date_joined: DateTime.parse('2013-10-31 21:25:00 UTC +00:00'))
453
+
454
+ d = Person.create(name: 'Tag Crazy Author',
455
+ email: 'taggy@xyz.fake',
456
+ date_joined: DateTime.parse('2013-11-30 4:20:00 UTC +00:00'))
457
+
458
+ short_tag = Tag.create(name: 'short')
459
+ whiny_tag = Tag.create(name: 'whiny')
460
+ grumpy_tag = Tag.create(name: 'grumpy')
461
+ happy_tag = Tag.create(name: 'happy')
462
+ jr_tag = Tag.create(name: 'JR')
463
+
464
+ silly_tag = Tag.create(name: 'silly')
465
+ sleepy_tag = Tag.create(name: 'sleepy')
466
+ goofy_tag = Tag.create(name: 'goofy')
467
+ wacky_tag = Tag.create(name: 'wacky')
468
+
469
+ # id:1
470
+ Post.create(title: 'New post',
471
+ body: 'A body!!!',
472
+ author_id: a.id).tap do |post|
473
+
474
+ post.tags.concat short_tag, whiny_tag, grumpy_tag
475
+
476
+ post.comments.create(body: 'what a dumb post', author_id: a.id, post_id: post.id).tap do |comment|
477
+ comment.tags.concat whiny_tag, short_tag
478
+ end
479
+
480
+ post.comments.create(body: 'i liked it', author_id: b.id, post_id: post.id).tap do |comment|
481
+ comment.tags.concat happy_tag, short_tag
482
+ end
483
+ end
484
+
485
+ # id:2
486
+ Post.create(title: 'JR Solves your serialization woes!',
487
+ body: 'Use JR',
488
+ author_id: a.id,
489
+ section: Section.create(name: 'ruby')).tap do |post|
490
+
491
+ post.tags.concat jr_tag
492
+
493
+ post.comments.create(body: 'Thanks man. Great post. But what is JR?', author_id: b.id, post_id: post.id).tap do |comment|
494
+ comment.tags.concat jr_tag
495
+ end
496
+ end
497
+
498
+ # id:3
499
+ Post.create(title: 'Update This Later',
500
+ body: 'AAAA',
501
+ author_id: c.id)
502
+
503
+ # id:4
504
+ Post.create(title: 'Delete This Later - Single',
505
+ body: 'AAAA',
506
+ author_id: c.id)
507
+
508
+ # id:5
509
+ Post.create(title: 'Delete This Later - Multiple1',
510
+ body: 'AAAA',
511
+ author_id: c.id)
512
+
513
+ # id:6
514
+ Post.create(title: 'Delete This Later - Multiple2',
515
+ body: 'AAAA',
516
+ author_id: c.id)
517
+
518
+ # id:7
519
+ Post.create(title: 'Delete This Later - Single2',
520
+ body: 'AAAA',
521
+ author_id: c.id)
522
+
523
+ # id:8
524
+ Post.create(title: 'Delete This Later - Multiple2-1',
525
+ body: 'AAAA',
526
+ author_id: c.id)
527
+
528
+ # id:9
529
+ Post.create(title: 'Delete This Later - Multiple2-2',
530
+ body: 'AAAA',
531
+ author_id: c.id)
532
+
533
+ # id:9
534
+ Post.create(title: 'Update This Later - Multiple',
535
+ body: 'AAAA',
536
+ author_id: c.id)
537
+
538
+ # id:10
539
+ Post.create(title: 'JR How To',
540
+ body: 'Use JR to write API apps',
541
+ author_id: a.id).tap do |post|
542
+ post.tags.concat jr_tag
543
+ end
544
+
545
+ Currency.create(code: 'USD', name: 'United States Dollar')
546
+ Currency.create(code: 'EUR', name: 'Euro Member Countries')
547
+
548
+ ExpenseEntry.create(currency_code: 'USD',
549
+ employee_id: c.id,
550
+ cost: '12.05',
551
+ transaction_date: DateTime.parse('2014-04-15 12:13:14 UTC +00:00'))
552
+
553
+ ExpenseEntry.create(currency_code: 'USD',
554
+ employee_id: c.id,
555
+ cost: '12.06',
556
+ transaction_date: DateTime.parse('2014-04-15 12:13:15 UTC +00:00'))
557
+
558
+ Post.create(title: 'Tagged up post 1',
559
+ body: 'AAAA',
560
+ author_id: d.id,
561
+ tag_ids: [6,7,8,9]
562
+ )
563
+
564
+ Post.create(title: 'Tagged up post 2',
565
+ body: 'BBBB',
566
+ author_id: d.id,
567
+ tag_ids: [6,7,8,9]
568
+ )
569
+
570
+ gas_giant = PlanetType.create(name: 'Gas Giant')
571
+ planetoid = PlanetType.create(name: 'Planetoid')
572
+ terrestrial = PlanetType.create(name: 'Terrestrial')
573
+ sulfuric = PlanetType.create(name: 'Sulfuric')
574
+ unknown = PlanetType.create(name: 'unknown')
575
+
576
+ saturn = Planet.create(name: 'Satern',
577
+ description: 'Saturn is the sixth planet from the Sun and the second largest planet in the Solar System, after Jupiter.',
578
+ planet_type_id: planetoid.id)
579
+ titan = Moon.create(name:'Titan', description: 'Best known of the Saturn moons.', planet_id: saturn.id)
580
+ pluto = Planet.create(name: 'Pluto', description: 'Pluto is the smallest planet.', planet_type_id: planetoid.id)
581
+ uranus = Planet.create(name: 'Uranus', description: 'Insert adolescent jokes here.', planet_type_id: gas_giant.id)
582
+ jupiter = Planet.create(name: 'Jupiter', description: 'A gas giant.', planet_type_id: gas_giant.id)
583
+ betax = Planet.create(name: 'Beta X', description: 'Newly discovered Planet X', planet_type_id: unknown.id)
584
+ betay = Planet.create(name: 'Beta X', description: 'Newly discovered Planet Y', planet_type_id: unknown.id)
585
+ betaz = Planet.create(name: 'Beta X', description: 'Newly discovered Planet Z', planet_type_id: unknown.id)