contentstack 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,27 @@
1
+ module Contentstack
2
+ class Entry
3
+ attr_reader :fields, :content_type, :uid, :owner
4
+ def initialize(attrs, content_type_uid=nil)
5
+ setup(attrs, content_type_uid)
6
+ end
7
+
8
+ def fetch
9
+ entry = API.fetch_entry(@content_type, self.fields[:uid])
10
+ setup(entry["entry"])
11
+ self
12
+ end
13
+
14
+ def get(field_uid)
15
+ raise Contentstack::Error("Please send a valid Field UID") if field_uid.class != String
16
+ @fields[field_uid.to_sym]
17
+ end
18
+
19
+ private
20
+ def setup(attrs, content_type_uid=nil)
21
+ @fields = attrs.symbolize_keys
22
+ @content_type = content_type_uid if !content_type_uid.blank?
23
+ @owner = attrs[:_owner] if attrs[:_owner]
24
+ @uid = attrs[:uid]
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,43 @@
1
+ require 'contentstack/entry'
2
+
3
+ module Contentstack
4
+ class EntryCollection
5
+ attr_reader :entries, :count, :content_type, :schema
6
+
7
+ def initialize(json, content_type_uid=nil)
8
+ @count = json["count"] if json["count"]
9
+ @entries = json["entries"].collect{|entry| Entry.new(entry, content_type_uid) }
10
+ @schema = json["schema"].symbolize_keys if json["schema"]
11
+ @content_type = json["content_type"].symbolize_keys if json["content_type"]
12
+ self
13
+ end
14
+
15
+ def each &block
16
+ @entries.map{|e| block.call(e)}
17
+ end
18
+
19
+ def map &block
20
+ self.each(&block)
21
+ end
22
+
23
+ def collect &block
24
+ self.each(&block)
25
+ end
26
+
27
+ def length
28
+ @entries.length
29
+ end
30
+
31
+ def first
32
+ @entries.first
33
+ end
34
+
35
+ def last
36
+ @entries.last
37
+ end
38
+
39
+ def get(index)
40
+ @entries[index]
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,7 @@
1
+ module Contentstack
2
+ class Error < StandardError
3
+ def initialize(msg="Something Went Wrong.")
4
+ super
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,589 @@
1
+ require 'contentstack/entry_collection'
2
+
3
+ module Contentstack
4
+ # A class that defines a query that is used to query for Entry instance.
5
+ class Query
6
+ # @!attribute [r] query
7
+ # Attribute which has all the information about the query which will be executed against Contentstack API
8
+
9
+ # @!attribute [r] content_type
10
+ # Denotes which `content_type` should the query be executed for
11
+
12
+ attr_reader :query, :content_type
13
+
14
+ # Initialize the Query instance
15
+ # @param [String] content_type
16
+ #
17
+ # Example:
18
+ # @query = @stack.content_type('blog').query
19
+ # @entries = @query.where('author', 'John Doe').fetch
20
+ #
21
+ # @return [Contentstack::Query]
22
+ def initialize(content_type)
23
+ @content_type = content_type
24
+ @query = {
25
+ query: "{}",
26
+ include_count: false,
27
+ skip: 0,
28
+ count: 10,
29
+ desc: 'created_at'
30
+ }
31
+ end
32
+
33
+ # Add a custom query against specified key.
34
+ # @param [String] field_uid
35
+ # @param [String/Number/Boolean/Hash] value
36
+ #
37
+ # Example:
38
+ # @query = @stack.content_type('blog').query
39
+ # @query.add_query('author', "Jane Doe")
40
+ #
41
+ # @return [Contentstack::Query]
42
+ def add_query(field_uid, value)
43
+ add_query_hash({:"#{field_uid}" => value})
44
+ end
45
+
46
+ # Remove provided query key from custom query if exist.
47
+ # @param [String] field_uid
48
+ #
49
+ # Example:
50
+ # @query = @stack.content_type('blog').query
51
+ # @query.remove_query('author')
52
+ #
53
+ # @return [Contentstack::Query]
54
+ def remove_query(field_uid)
55
+ q = ActiveSupport::JSON.decode(@query[:query])
56
+ q.delete(field_uid)
57
+ @query[:query] = ActiveSupport::JSON.encode(q)
58
+ self
59
+ end
60
+
61
+ # Add a constraint to fetch all entries that contains given value against specified key.
62
+ # @param [Hash] query_hash
63
+ #
64
+ # Example:
65
+ # @query = @stack.content_type('blog').query
66
+ # @query.where({:author => "Jane Doe"})
67
+ #
68
+ # @return [Contentstack::Query]
69
+ def where(query_hash)
70
+ add_query_hash(query_hash)
71
+ end
72
+
73
+ # Add a regular expression constraint for finding string values that match the provided regular expression. This may be slow for large data sets.
74
+ # @param [String] field_uid The key to be constrained.
75
+ # @param [String] pattern The regular expression pattern to match.
76
+ # @param [String] options Regex options
77
+ #
78
+ # Example:
79
+ # @query = @stack.content_type('product').query
80
+ # @query.regex('title', '.*Mobile.*', 'i') # Search without case sensitivity
81
+ #
82
+ # @return [Contentstack::Query]
83
+ def regex(field_uid, pattern, options="")
84
+ hash = {
85
+ "#{field_uid}" => {
86
+ "$regex": pattern
87
+ }
88
+ }
89
+
90
+ hash["#{field_uid}"]["$options"] = options if !options.empty? || !options.nil?
91
+
92
+ add_query_hash(hash)
93
+ end
94
+
95
+ # Add a constraint that requires, a specified key exists in response.
96
+ # @param [String] field_uid The key to be constrained.
97
+ #
98
+ # Example:
99
+ # @query = @stack.content_type('product').query
100
+ # @query.exists?('product_image') # only fetch products which have a `product_image`
101
+ #
102
+ # @return [Contentstack::Query]
103
+ def exists?(field_uid)
104
+ add_query_hash({:"#{field_uid}" => {"$exists" => true}})
105
+ end
106
+
107
+ # Add a constraint that requires, a specified key does not exists in response.
108
+ # @param [String] field_uid The key to be constrained.
109
+ #
110
+ # Example:
111
+ # @query = @stack.content_type('product').query
112
+ # @query.not_exists?('product_image') # only fetch products which do not have a `product_image`
113
+ #
114
+ # @return [Contentstack::Query]
115
+ def not_exists?(field_uid)
116
+ add_query_hash({:"#{field_uid}" => {"$exists" => false}})
117
+ self
118
+ end
119
+
120
+ # Combines all the queries together using AND operator.
121
+ #
122
+ # @param [Array] queries Array of instances of the Query class
123
+ #
124
+ # Each query should be an instance of the Contentstack::Query class, and belong to the same `content_type`
125
+ # Example:
126
+ # @query1 = @stack.content_type('category').query
127
+ # @query1.where('title', 'Electronics')
128
+ #
129
+ # @query2 = @stack.content_type('category').query
130
+ # @query2.regex('description', '.*Electronics.*')
131
+ #
132
+ # query_array = [@query1, @query2]
133
+ #
134
+ # @query = @stack.content_type('category').query
135
+ # @query.and(query_array)
136
+ #
137
+ # @return [Contentstack::Query]
138
+ def and(queries)
139
+ add_query_hash({"$and" => concat_queries(queries)})
140
+ self
141
+ end
142
+
143
+ # Combines all the queries together using OR operator.
144
+ #
145
+ # @param [Array] queries Array of instances of the Query class
146
+ #
147
+ # Each query should be an instance of the Contentstack::Query class, and belong to the same `content_type`
148
+ # Example:
149
+ # @query1 = @stack.content_type('category').query
150
+ # @query1.where('title', 'Electronics')
151
+ #
152
+ # @query2 = @stack.content_type('category').query
153
+ # @query2.where('title', 'Apparel')
154
+ #
155
+ # query_array = [@query1, @query2]
156
+ #
157
+ # @query = @stack.content_type('category').query
158
+ # @query.or(query_array)
159
+ #
160
+ # @return [Contentstack::Query]
161
+ def or(queries)
162
+ add_query_hash({"$or" => concat_queries(queries)})
163
+ self
164
+ end
165
+
166
+ # Add a constraint to the query that requires a particular key entry to be less than the provided value.
167
+ #
168
+ # @param [String] field_uid UID of the field for which query should be executed
169
+ #
170
+ # @param [String/Number] value Value that provides an upper bound
171
+ #
172
+ # Example
173
+ # @query = @stack.content_type('product').query
174
+ # @query.less_than('price', '100')
175
+ #
176
+ # @return [Contentstack::Query]
177
+ def less_than(field_uid, value)
178
+ add_query_hash({:"#{field_uid}" => {"$lt" => value}})
179
+ self
180
+ end
181
+
182
+ # Add a constraint to the query that requires a particular key entry to be less than or equal to the provided value.
183
+ #
184
+ # @param [String] field_uid UID of the field for which query should be executed
185
+ #
186
+ # @param [String/Number] value Value that provides an upper bound
187
+ #
188
+ # Example
189
+ # @query = @stack.content_type('product').query
190
+ # @query.less_than_or_equal('price', '100')
191
+ #
192
+ # @return [Contentstack::Query]
193
+ def less_than_or_equal(field_uid, value)
194
+ add_query_hash({:"#{field_uid}" => {"$lte" => value}})
195
+ self
196
+ end
197
+
198
+ # Add a constraint to the query that requires a particular key entry to be greater than the provided value.
199
+ #
200
+ # @param [String] field_uid UID of the field for which query should be executed
201
+ #
202
+ # @param [String/Number] value Value that provides a lower bound
203
+ #
204
+ # Example
205
+ # @query = @stack.content_type('product').query
206
+ # @query.greater_than('price', '100')
207
+ #
208
+ # @return [Contentstack::Query]
209
+ def greater_than(field_uid, value)
210
+ add_query_hash({:"#{field_uid}" => {"$gt" => value}})
211
+ self
212
+ end
213
+
214
+ # Add a constraint to the query that requires a particular key entry to be greater than or equal to the provided value.
215
+ #
216
+ # @param [String] field_uid UID of the field for which query should be executed
217
+ #
218
+ # @param [String/Number] value Value that provides a lower bound
219
+ #
220
+ # Example
221
+ # @query = @stack.content_type('product').query
222
+ # @query.greater_than_or_equal('price', '100')
223
+ #
224
+ # @return [Contentstack::Query]
225
+ def greater_than_or_equal(field_uid, value)
226
+ add_query_hash({:"#{field_uid}" => {"$gte" => value}})
227
+ self
228
+ end
229
+
230
+ # Add a constraint to the query that requires a particular key's entry to be not equal to the provided value.
231
+ #
232
+ # @param [String] field_uid UID of the field for which query should be executed
233
+ # @param [String] value The object that must not be equaled.
234
+ #
235
+ # Example
236
+ # @query = @stack.content_type('product').query
237
+ # @query.not_equal_to('price', '100')
238
+ #
239
+ # @return [Contentstack::Query]
240
+ def not_equal_to(field_uid, value)
241
+ add_query_hash({:"#{field_uid}" => {"$ne" => value}})
242
+ self
243
+ end
244
+
245
+ # Add a constraint to the query that requires a particular key's entry to be contained in the provided array.
246
+ #
247
+ # @param [String] field_uid UID of the field for which query should be executed
248
+ # @param [String] values The possible values for the key's object
249
+ #
250
+ # Example
251
+ # @query = @stack.content_type('category').query
252
+ # @query.contained_in("title", ["Electronics", "Apparel"])
253
+ #
254
+ # @return [Contentstack::Query]
255
+ def contained_in(field_uid, values)
256
+ add_query_hash({:"#{field_uid}" => {"$in" => values}})
257
+ self
258
+ end
259
+
260
+ # Add a constraint to the query that requires a particular key entry's value not be contained in the provided array.
261
+ #
262
+ # @param [String] field_uid UID of the field for which query should be executed
263
+ # @param [String] values The possible values for the key's object
264
+ #
265
+ # Example
266
+ # @query = @stack.content_type('category').query
267
+ # @query.not_contained_in("title", ["Electronics", "Apparel"])
268
+ #
269
+ # @return [Contentstack::Query]
270
+ def not_contained_in(field_uid, values)
271
+ add_query_hash({:"#{field_uid}" => {"$nin" => values}})
272
+ self
273
+ end
274
+
275
+ # The number of objects to skip before returning any.
276
+ #
277
+ # @param [Number] count of objects to skip from resulset.
278
+ #
279
+ # Example
280
+ # @query = @stack.content_type('category').query
281
+ # @query.skip(50)
282
+ #
283
+ # @return [Contentstack::Query]
284
+ def skip(count)
285
+ @query[:skip] = count
286
+ self
287
+ end
288
+
289
+ # This method provides only the entries matching the specified value.
290
+ #
291
+ # @param [String] text value used to match or compare
292
+ #
293
+ # Example
294
+ # @query = @stack.content_type('product').query
295
+ # @query.search("This is an awesome product")
296
+ #
297
+ # @return [Contentstack::Query]
298
+ def search(text)
299
+ @query[:typeahead] = text
300
+ self
301
+ end
302
+
303
+ # A limit on the number of objects to return.
304
+ #
305
+ # @param [Number] count of objects to limit in resulset.
306
+ #
307
+ # Example
308
+ # @query = @stack.content_type('category').query
309
+ # @query.limit(50)
310
+ #
311
+ # @return [Contentstack::Query]
312
+ def limit(count=10)
313
+ @query[:limit] = count
314
+ self
315
+ end
316
+
317
+ # Retrieve only count of entries in result.
318
+ #
319
+ # Example
320
+ # @query = @stack.content_type('category').query
321
+ # @query.count
322
+ #
323
+ # @return [Integer]
324
+ def count
325
+ include_count
326
+ fetch.count
327
+ end
328
+
329
+ # Retrieve count and data of objects in result.
330
+ #
331
+ # Example
332
+ # @query = @stack.content_type('category').query
333
+ # @query.include_count
334
+ #
335
+ # @return [Contentstack::Query]
336
+ def include_count(flag=true)
337
+ @query[:include_count] = flag
338
+ self
339
+ end
340
+
341
+ # Sort the results in ascending order with the given key.
342
+ # Sort the returned entries in ascending order of the provided key.
343
+ #
344
+ # @param [String] field_uid The key to order by
345
+ #
346
+ # Example
347
+ # @query = @stack.content_type('category').query
348
+ # @query.ascending
349
+ #
350
+ # @return [Contentstack::Query]
351
+ def ascending(field_uid)
352
+ @query.delete(:desc)
353
+ @query[:asc] = field_uid
354
+ self
355
+ end
356
+
357
+ # Sort the results in descending order with the given key.
358
+ # Sort the returned entries in descending order of the provided key.
359
+ #
360
+ # @param [String] field_uid The key to order by
361
+ #
362
+ # Example
363
+ # @query = @stack.content_type('category').query
364
+ # @query.descending
365
+ #
366
+ # @return [Contentstack::Query]
367
+ def descending(field_uid)
368
+ @query.delete(:asc)
369
+ @query[:desc] = field_uid
370
+ self
371
+ end
372
+
373
+ # Specifies an array of 'only' keys in BASE object that would be 'included' in the response.
374
+ #
375
+ # @param [Array] fields Array of the 'only' reference keys to be included in response.
376
+ # @param [Array] fields_with_base Can be used to denote 'only' fields of the reference class
377
+ #
378
+ # Example
379
+ # # Include only title and description field in response
380
+ # @query = @stack.content_type('category').query
381
+ # @query.only(['title', 'description'])
382
+ #
383
+ # # Query product and include only the title and description from category reference
384
+ # @query = @stack.content_type('product').query
385
+ # @query.include_reference('category')
386
+ # .only('category', ['title', 'description'])
387
+ #
388
+ # @return [Contentstack::Query]
389
+ def only(fields, fields_with_base=nil)
390
+ q = {}
391
+ if [Array, String].include?(fields_with_base.class)
392
+ fields_with_base = [fields_with_base] if fields_with_base.class == String
393
+ q[fields.to_sym] = fields_with_base
394
+ else
395
+ fields = [fields] if fields.class == String
396
+ q = {BASE: fields}
397
+ end
398
+
399
+ @query[:only] = q
400
+ self
401
+ end
402
+
403
+ # Specifies list of field uids that would be 'excluded' from the response.
404
+ #
405
+ # @param [Array] fields Array of field uid which get 'excluded' from the response.
406
+ # @param [Array] fields_with_base Can be used to denote 'except' fields of the reference class
407
+ #
408
+ # Example
409
+ # # Exclude 'description' field in response
410
+ # @query = @stack.content_type('category').query
411
+ # @query.except(['description'])
412
+ #
413
+ # # Query product and exclude the 'description' from category reference
414
+ # @query = @stack.content_type('product').query
415
+ # @query.include_reference('category')
416
+ # .except('category', ['description'])
417
+ #
418
+ # @return [Contentstack::Query]
419
+ def except(fields, fields_with_base=nil)
420
+ q = {}
421
+ if [Array, String].include?(fields_with_base.class)
422
+ fields_with_base = [fields_with_base] if fields_with_base.class == String
423
+ q[fields.to_sym] = fields_with_base
424
+ else
425
+ fields = [fields] if fields.class == String
426
+ q = {BASE: fields}
427
+ end
428
+
429
+ @query[:except] = q
430
+ self
431
+ end
432
+
433
+ # Add a constraint that requires a particular reference key details.
434
+ #
435
+ # @param [String/Array] reference_field_uids Pass string or array of reference fields that must be included in the response
436
+ #
437
+ # Example
438
+ #
439
+ # # Include reference of 'category'
440
+ # @query = @stack.content_type('product').query
441
+ # @query.include_reference('category')
442
+ #
443
+ # # Include reference of 'category' and 'reviews'
444
+ # @query = @stack.content_type('product').query
445
+ # @query.include_reference(['category', 'reviews'])
446
+ #
447
+ # @return [Contentstack::Query]
448
+ def include_reference(reference_field_uids)
449
+ self.include(reference_field_uids)
450
+ end
451
+
452
+ # Include schemas of all returned objects along with objects themselves.
453
+ #
454
+ # Example
455
+ #
456
+ # @query = @stack.content_type('product').query
457
+ # @query.include_schema
458
+ #
459
+ # @return [Contentstack::Query]
460
+ def include_schema(flag=true)
461
+ @query[:include_schema] = flag
462
+ self
463
+ end
464
+
465
+ # Include object owner's profile in the objects data.
466
+ #
467
+ # Example
468
+ #
469
+ # @query = @stack.content_type('product').query
470
+ # @query.include_owner
471
+ #
472
+ # @return [Contentstack::Query]
473
+ def include_owner(flag=true)
474
+ @query[:include_owner] = flag
475
+ self
476
+ end
477
+
478
+ # Include object's content_type in response
479
+ #
480
+ # Example
481
+ #
482
+ # @query = @stack.content_type('product').query
483
+ # @query.include_content_type
484
+ #
485
+ # @return [Contentstack::Query]
486
+ def include_content_type(flag=true)
487
+ @query[:include_content_type] = flag
488
+ self
489
+ end
490
+
491
+ # Include objects in 'Draft' mode in response
492
+ #
493
+ # Example
494
+ #
495
+ # @query = @stack.content_type('product').query
496
+ # @query.include_draft
497
+ #
498
+ # @return [Contentstack::Query]
499
+ def include_draft(flag=true)
500
+ @query[:include_draft] = flag
501
+ self
502
+ end
503
+
504
+
505
+ #
506
+ # @return [Contentstack::Query]
507
+ def include(field_uids)
508
+ field_uids = [field_uids] if field_uids.class == String
509
+ @query[:include] ||= []
510
+ @query[:include] = @query[:include] | field_uids
511
+ self
512
+ end
513
+
514
+ # Include tags with which to search entries.
515
+ #
516
+ # @param [Array] tags_array Array of tags using which search must be performed
517
+ #
518
+ # Example
519
+ #
520
+ # @query = @stack.content_type('product').query
521
+ # @query.tags(["tag1", "tag2"])
522
+ #
523
+ # @return [Contentstack::Query]
524
+ def tags(tags_array)
525
+ @query[:tags] = tags_array
526
+ self
527
+ end
528
+
529
+
530
+ # Execute query
531
+ #
532
+ # Example
533
+ #
534
+ # @query = @stack.content_type('product').query
535
+ # @query.tags(["tag1", "tag2"])
536
+ # .fetch
537
+ #
538
+ # @return [Contentstack::EntryCollection]
539
+ def fetch
540
+ entries = API.fetch_entries(@content_type, @query)
541
+ EntryCollection.new(entries, @content_type)
542
+ end
543
+
544
+ # Execute a Query and get the single matching object
545
+ #
546
+ # Example
547
+ #
548
+ # @query = @stack.content_type('product').query
549
+ # @query.tags(["tag1", "tag2"])
550
+ # .find_one
551
+ #
552
+ # @return [Contentstack::Entry]
553
+ def find_one
554
+ limit 1
555
+ fetch.first
556
+ end
557
+
558
+ alias_method :find, :fetch
559
+ alias_method :in, :contained_in
560
+ alias_method :not_in, :not_contained_in
561
+
562
+ private
563
+ def add_query_hash(query_hash)
564
+ q = ActiveSupport::JSON.decode(@query[:query])
565
+ q.merge!(query_hash)
566
+ @query[:query] = ActiveSupport::JSON.encode(q)
567
+ self
568
+ end
569
+
570
+ def concat_queries(queries)
571
+ this_queries = []
572
+ this_query = ActiveSupport::JSON.decode(@query[:query])
573
+ if this_query.keys.length > 0
574
+ this_queries = [this_query]
575
+ end
576
+
577
+ if queries.class == Array
578
+ queries.map do |query_object|
579
+ if query_object.class == Contentstack::Query && query_object.content_type == @content_type
580
+ q = ActiveSupport::JSON.decode(query_object.query[:query])
581
+ this_queries.push(q.symbolize_keys)
582
+ end
583
+ end
584
+ end
585
+
586
+ this_queries
587
+ end
588
+ end
589
+ end