-
1
require 'contentstack/entry_collection'
-
-
1
module Contentstack
-
# A class that defines a query that is used to query for Entry instance.
-
1
class Query
-
# @!attribute [r] query
-
# Attribute which has all the information about the query which will be executed against Contentstack API
-
-
# @!attribute [r] content_type
-
# Denotes which `content_type` should the query be executed for
-
-
1
attr_reader :query, :content_type
-
-
# Initialize the Query instance
-
# @param [String] content_type
-
#
-
# Example:
-
# @query = @stack.content_type('blog').query
-
# @entries = @query.where('author', 'John Doe').fetch
-
#
-
# @return [Contentstack::Query]
-
1
def initialize(content_type)
-
53
@content_type = content_type
-
@query = {
-
53
query: "{}",
-
include_count: false,
-
skip: 0,
-
count: 10,
-
desc: 'created_at'
-
}
-
end
-
-
# Add a custom query against specified key.
-
# @param [String] field_uid
-
# @param [String/Number/Boolean/Hash] value
-
#
-
# Example:
-
# @query = @stack.content_type('blog').query
-
# @query.add_query('author', "Jane Doe")
-
#
-
# @return [Contentstack::Query]
-
1
def add_query(field_uid, value)
-
add_query_hash({:"#{field_uid}" => value})
-
end
-
-
# Remove provided query key from custom query if exist.
-
# @param [String] field_uid
-
#
-
# Example:
-
# @query = @stack.content_type('blog').query
-
# @query.remove_query('author')
-
#
-
# @return [Contentstack::Query]
-
1
def remove_query(field_uid)
-
q = ActiveSupport::JSON.decode(@query[:query])
-
q.delete(field_uid)
-
@query[:query] = ActiveSupport::JSON.encode(q)
-
self
-
end
-
-
# Add a constraint to fetch all entries that contains given value against specified key.
-
# @param [Hash] query_hash
-
#
-
# Example:
-
# @query = @stack.content_type('blog').query
-
# @query.where({:author => "Jane Doe"})
-
#
-
# @return [Contentstack::Query]
-
1
def where(query_hash)
-
2
add_query_hash(query_hash)
-
end
-
-
# Add a regular expression constraint for finding string values that match the provided regular expression. This may be slow for large data sets.
-
# @param [String] field_uid The key to be constrained.
-
# @param [String] pattern The regular expression pattern to match.
-
# @param [String] options Regex options
-
#
-
# Example:
-
# @query = @stack.content_type('product').query
-
# @query.regex('title', '.*Mobile.*', 'i') # Search without case sensitivity
-
#
-
# @return [Contentstack::Query]
-
1
def regex(field_uid, pattern, options="")
-
hash = {
-
4
"#{field_uid}" => {
-
"$regex": pattern
-
}
-
}
-
-
4
hash["#{field_uid}"]["$options"] = options if !options.empty? || !options.nil?
-
-
4
add_query_hash(hash)
-
end
-
-
# Add a constraint that requires, a specified key exists in response.
-
# @param [String] field_uid The key to be constrained.
-
#
-
# Example:
-
# @query = @stack.content_type('product').query
-
# @query.exists?('product_image') # only fetch products which have a `product_image`
-
#
-
# @return [Contentstack::Query]
-
1
def exists?(field_uid)
-
1
add_query_hash({:"#{field_uid}" => {"$exists" => true}})
-
end
-
-
# Add a constraint that requires, a specified key does not exists in response.
-
# @param [String] field_uid The key to be constrained.
-
#
-
# Example:
-
# @query = @stack.content_type('product').query
-
# @query.not_exists?('product_image') # only fetch products which do not have a `product_image`
-
#
-
# @return [Contentstack::Query]
-
1
def not_exists?(field_uid)
-
1
add_query_hash({:"#{field_uid}" => {"$exists" => false}})
-
1
self
-
end
-
-
# Combines all the queries together using AND operator.
-
#
-
# @param [Array] queries Array of instances of the Query class
-
#
-
# Each query should be an instance of the Contentstack::Query class, and belong to the same `content_type`
-
# Example:
-
# @query1 = @stack.content_type('category').query
-
# @query1.where('title', 'Electronics')
-
#
-
# @query2 = @stack.content_type('category').query
-
# @query2.regex('description', '.*Electronics.*')
-
#
-
# query_array = [@query1, @query2]
-
#
-
# @query = @stack.content_type('category').query
-
# @query.and(query_array)
-
#
-
# @return [Contentstack::Query]
-
1
def and(queries)
-
1
add_query_hash({"$and" => concat_queries(queries)})
-
1
self
-
end
-
-
# Combines all the queries together using OR operator.
-
#
-
# @param [Array] queries Array of instances of the Query class
-
#
-
# Each query should be an instance of the Contentstack::Query class, and belong to the same `content_type`
-
# Example:
-
# @query1 = @stack.content_type('category').query
-
# @query1.where('title', 'Electronics')
-
#
-
# @query2 = @stack.content_type('category').query
-
# @query2.where('title', 'Apparel')
-
#
-
# query_array = [@query1, @query2]
-
#
-
# @query = @stack.content_type('category').query
-
# @query.or(query_array)
-
#
-
# @return [Contentstack::Query]
-
1
def or(queries)
-
1
add_query_hash({"$or" => concat_queries(queries)})
-
1
self
-
end
-
-
# Add a constraint to the query that requires a particular key entry to be less than the provided value.
-
#
-
# @param [String] field_uid UID of the field for which query should be executed
-
#
-
# @param [String/Number] value Value that provides an upper bound
-
#
-
# Example
-
# @query = @stack.content_type('product').query
-
# @query.less_than('price', '100')
-
#
-
# @return [Contentstack::Query]
-
1
def less_than(field_uid, value)
-
1
add_query_hash({:"#{field_uid}" => {"$lt" => value}})
-
1
self
-
end
-
-
# Add a constraint to the query that requires a particular key entry to be less than or equal to the provided value.
-
#
-
# @param [String] field_uid UID of the field for which query should be executed
-
#
-
# @param [String/Number] value Value that provides an upper bound
-
#
-
# Example
-
# @query = @stack.content_type('product').query
-
# @query.less_than_or_equal('price', '100')
-
#
-
# @return [Contentstack::Query]
-
1
def less_than_or_equal(field_uid, value)
-
1
add_query_hash({:"#{field_uid}" => {"$lte" => value}})
-
1
self
-
end
-
-
# Add a constraint to the query that requires a particular key entry to be greater than the provided value.
-
#
-
# @param [String] field_uid UID of the field for which query should be executed
-
#
-
# @param [String/Number] value Value that provides a lower bound
-
#
-
# Example
-
# @query = @stack.content_type('product').query
-
# @query.greater_than('price', '100')
-
#
-
# @return [Contentstack::Query]
-
1
def greater_than(field_uid, value)
-
1
add_query_hash({:"#{field_uid}" => {"$gt" => value}})
-
1
self
-
end
-
-
# Add a constraint to the query that requires a particular key entry to be greater than or equal to the provided value.
-
#
-
# @param [String] field_uid UID of the field for which query should be executed
-
#
-
# @param [String/Number] value Value that provides a lower bound
-
#
-
# Example
-
# @query = @stack.content_type('product').query
-
# @query.greater_than_or_equal('price', '100')
-
#
-
# @return [Contentstack::Query]
-
1
def greater_than_or_equal(field_uid, value)
-
1
add_query_hash({:"#{field_uid}" => {"$gte" => value}})
-
1
self
-
end
-
-
# Add a constraint to the query that requires a particular key's entry to be not equal to the provided value.
-
#
-
# @param [String] field_uid UID of the field for which query should be executed
-
# @param [String] value The object that must not be equaled.
-
#
-
# Example
-
# @query = @stack.content_type('product').query
-
# @query.not_equal_to('price', '100')
-
#
-
# @return [Contentstack::Query]
-
1
def not_equal_to(field_uid, value)
-
1
add_query_hash({:"#{field_uid}" => {"$ne" => value}})
-
1
self
-
end
-
-
# Add a constraint to the query that requires a particular key's entry to be contained in the provided array.
-
#
-
# @param [String] field_uid UID of the field for which query should be executed
-
# @param [String] values The possible values for the key's object
-
#
-
# Example
-
# @query = @stack.content_type('category').query
-
# @query.contained_in("title", ["Electronics", "Apparel"])
-
#
-
# @return [Contentstack::Query]
-
1
def contained_in(field_uid, values)
-
2
add_query_hash({:"#{field_uid}" => {"$in" => values}})
-
2
self
-
end
-
-
# Add a constraint to the query that requires a particular key entry's value not be contained in the provided array.
-
#
-
# @param [String] field_uid UID of the field for which query should be executed
-
# @param [String] values The possible values for the key's object
-
#
-
# Example
-
# @query = @stack.content_type('category').query
-
# @query.not_contained_in("title", ["Electronics", "Apparel"])
-
#
-
# @return [Contentstack::Query]
-
1
def not_contained_in(field_uid, values)
-
2
add_query_hash({:"#{field_uid}" => {"$nin" => values}})
-
2
self
-
end
-
-
# The number of objects to skip before returning any.
-
#
-
# @param [Number] count of objects to skip from resulset.
-
#
-
# Example
-
# @query = @stack.content_type('category').query
-
# @query.skip(50)
-
#
-
# @return [Contentstack::Query]
-
1
def skip(count)
-
1
@query[:skip] = count
-
1
self
-
end
-
-
# This method provides only the entries matching the specified value.
-
#
-
# @param [String] text value used to match or compare
-
#
-
# Example
-
# @query = @stack.content_type('product').query
-
# @query.search("This is an awesome product")
-
#
-
# @return [Contentstack::Query]
-
1
def search(text)
-
1
@query[:typeahead] = text
-
1
self
-
end
-
-
# A limit on the number of objects to return.
-
#
-
# @param [Number] count of objects to limit in resulset.
-
#
-
# Example
-
# @query = @stack.content_type('category').query
-
# @query.limit(50)
-
#
-
# @return [Contentstack::Query]
-
1
def limit(count=10)
-
1
@query[:limit] = count
-
1
self
-
end
-
-
# Retrieve only count of entries in result.
-
#
-
# Example
-
# @query = @stack.content_type('category').query
-
# @query.count
-
#
-
# @return [Integer]
-
1
def count
-
1
include_count
-
1
fetch.count
-
end
-
-
# Retrieve count and data of objects in result.
-
#
-
# Example
-
# @query = @stack.content_type('category').query
-
# @query.include_count
-
#
-
# @return [Contentstack::Query]
-
1
def include_count(flag=true)
-
8
@query[:include_count] = flag
-
8
self
-
end
-
-
# Sort the results in ascending order with the given key.
-
# Sort the returned entries in ascending order of the provided key.
-
#
-
# @param [String] field_uid The key to order by
-
#
-
# Example
-
# @query = @stack.content_type('category').query
-
# @query.ascending
-
#
-
# @return [Contentstack::Query]
-
1
def ascending(field_uid)
-
1
@query.delete(:desc)
-
1
@query[:asc] = field_uid
-
1
self
-
end
-
-
# Sort the results in descending order with the given key.
-
# Sort the returned entries in descending order of the provided key.
-
#
-
# @param [String] field_uid The key to order by
-
#
-
# Example
-
# @query = @stack.content_type('category').query
-
# @query.descending
-
#
-
# @return [Contentstack::Query]
-
1
def descending(field_uid)
-
1
@query.delete(:asc)
-
1
@query[:desc] = field_uid
-
1
self
-
end
-
-
# Get entries from the specified locale.
-
#
-
# @param [String] code The locale code of the entry
-
#
-
# Example
-
# @query = @stack.content_type('category').query
-
# @query.locale('en-us')
-
#
-
# @return [Contentstack::Query]
-
1
def locale(code)
-
1
@query[:locale] = code
-
1
self
-
end
-
-
# Specifies an array of 'only' keys in BASE object that would be 'included' in the response.
-
#
-
# @param [Array] fields Array of the 'only' reference keys to be included in response.
-
# @param [Array] fields_with_base Can be used to denote 'only' fields of the reference class
-
#
-
# Example
-
# # Include only title and description field in response
-
# @query = @stack.content_type('category').query
-
# @query.only(['title', 'description'])
-
#
-
# # Query product and include only the title and description from category reference
-
# @query = @stack.content_type('product').query
-
# @query.include_reference('category')
-
# .only('category', ['title', 'description'])
-
#
-
# @return [Contentstack::Query]
-
1
def only(fields, fields_with_base=nil)
-
3
q = {}
-
3
if [Array, String].include?(fields_with_base.class)
-
1
fields_with_base = [fields_with_base] if fields_with_base.class == String
-
1
q[fields.to_sym] = fields_with_base
-
else
-
2
fields = [fields] if fields.class == String
-
2
q = {BASE: fields}
-
end
-
-
3
@query[:only] = q
-
3
self
-
end
-
-
# Specifies list of field uids that would be 'excluded' from the response.
-
#
-
# @param [Array] fields Array of field uid which get 'excluded' from the response.
-
# @param [Array] fields_with_base Can be used to denote 'except' fields of the reference class
-
#
-
# Example
-
# # Exclude 'description' field in response
-
# @query = @stack.content_type('category').query
-
# @query.except(['description'])
-
#
-
# # Query product and exclude the 'description' from category reference
-
# @query = @stack.content_type('product').query
-
# @query.include_reference('category')
-
# .except('category', ['description'])
-
#
-
# @return [Contentstack::Query]
-
1
def except(fields, fields_with_base=nil)
-
3
q = {}
-
3
if [Array, String].include?(fields_with_base.class)
-
1
fields_with_base = [fields_with_base] if fields_with_base.class == String
-
1
q[fields.to_sym] = fields_with_base
-
else
-
2
fields = [fields] if fields.class == String
-
2
q = {BASE: fields}
-
end
-
-
3
@query[:except] = q
-
3
self
-
end
-
-
# Add a constraint that requires a particular reference key details.
-
#
-
# @param [String/Array] reference_field_uids Pass string or array of reference fields that must be included in the response
-
#
-
# Example
-
#
-
# # Include reference of 'category'
-
# @query = @stack.content_type('product').query
-
# @query.include_reference('category')
-
#
-
# # Include reference of 'category' and 'reviews'
-
# @query = @stack.content_type('product').query
-
# @query.include_reference(['category', 'reviews'])
-
#
-
# @return [Contentstack::Query]
-
1
def include_reference(reference_field_uids)
-
3
self.include(reference_field_uids)
-
end
-
-
# Include schemas of all returned objects along with objects themselves.
-
#
-
# Example
-
#
-
# @query = @stack.content_type('product').query
-
# @query.include_schema
-
#
-
# @return [Contentstack::Query]
-
1
def include_schema(flag=true)
-
1
@query[:include_schema] = flag
-
1
self
-
end
-
-
# Include object owner's profile in the objects data.
-
#
-
# Example
-
#
-
# @query = @stack.content_type('product').query
-
# @query.include_owner
-
#
-
# @return [Contentstack::Query]
-
1
def include_owner(flag=true)
-
1
@query[:include_owner] = flag
-
1
self
-
end
-
-
# Include object's content_type in response
-
#
-
# Example
-
#
-
# @query = @stack.content_type('product').query
-
# @query.include_content_type
-
#
-
# @return [Contentstack::Query]
-
1
def include_content_type(flag=true)
-
1
@query[:include_content_type] = flag
-
1
self
-
end
-
-
-
# Include the fallback locale publish content, if specified locale content is not publish.
-
#
-
# Example
-
#
-
# @query = @stack.content_type('product').query
-
# @query.include_fallback
-
#
-
# @return [Contentstack::Query]
-
1
def include_fallback(flag=true)
-
1
@query[:include_fallback] = flag
-
1
self
-
end
-
-
# Include Embedded Objects (Entries and Assets) along with entry/entries details.
-
#
-
# Example
-
#
-
# @query = @stack.content_type('product').query
-
# @query.include_embedded_items
-
#
-
# @return [Contentstack::Query]
-
1
def include_embedded_items()
-
@query[:include_embedded_items] = ['BASE']
-
self
-
end
-
-
# Include objects in 'Draft' mode in response
-
#
-
# Example
-
#
-
# @query = @stack.content_type('product').query
-
# @query.include_draft
-
#
-
# @return [Contentstack::Query]
-
1
def include_draft(flag=true)
-
1
@query[:include_draft] = flag
-
1
self
-
end
-
-
-
#
-
# @return [Contentstack::Query]
-
1
def include(field_uids)
-
3
field_uids = [field_uids] if field_uids.class == String
-
3
@query[:include] ||= []
-
3
@query[:include] = @query[:include] | field_uids
-
3
self
-
end
-
-
# Include tags with which to search entries.
-
#
-
# @param [Array] tags_array Array of tags using which search must be performed
-
#
-
# Example
-
#
-
# @query = @stack.content_type('product').query
-
# @query.tags(["tag1", "tag2"])
-
#
-
# @return [Contentstack::Query]
-
1
def tags(tags_array)
-
1
@query[:tags] = tags_array
-
1
self
-
end
-
-
-
# Execute query
-
#
-
# Example
-
#
-
# @query = @stack.content_type('product').query
-
# @query.tags(["tag1", "tag2"])
-
# .fetch
-
#
-
# @return [Contentstack::EntryCollection]
-
1
def fetch
-
48
entries = API.fetch_entries(@content_type, @query)
-
48
EntryCollection.new(entries, @content_type)
-
end
-
-
# Execute a Query and get the single matching object
-
#
-
# Example
-
#
-
# @query = @stack.content_type('product').query
-
# @query.tags(["tag1", "tag2"])
-
# .find_one
-
#
-
# @return [Contentstack::Entry]
-
1
def find_one
-
limit 1
-
fetch.first
-
end
-
-
1
alias_method :find, :fetch
-
1
alias_method :in, :contained_in
-
1
alias_method :not_in, :not_contained_in
-
-
1
private
-
1
def add_query_hash(query_hash)
-
19
q = ActiveSupport::JSON.decode(@query[:query])
-
19
q.merge!(query_hash)
-
19
@query[:query] = ActiveSupport::JSON.encode(q)
-
19
self
-
end
-
-
1
def concat_queries(queries)
-
2
this_queries = []
-
2
this_query = ActiveSupport::JSON.decode(@query[:query])
-
2
if this_query.keys.length > 0
-
this_queries = [this_query]
-
end
-
-
2
if queries.class == Array
-
2
queries.map do |query_object|
-
4
if query_object.class == Contentstack::Query && query_object.content_type == @content_type
-
4
q = ActiveSupport::JSON.decode(query_object.query[:query])
-
4
this_queries.push(q.symbolize_keys)
-
end
-
end
-
end
-
-
2
this_queries
-
end
-
end
-
end