contentstack 0.0.2

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.
@@ -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