lib/gcloud/datastore/query.rb in gcloud-0.8.2 vs lib/gcloud/datastore/query.rb in gcloud-0.9.0
- old
+ new
@@ -13,87 +13,152 @@
# limitations under the License.
require "gcloud/datastore/entity"
require "gcloud/datastore/key"
-require "gcloud/datastore/proto"
module Gcloud
module Datastore
##
# # Query
#
# Represents the search criteria against a Datastore.
#
+ # @see https://cloud.google.com/datastore/docs/concepts/queries Datastore
+ # Queries
+ # @see https://cloud.google.com/datastore/docs/concepts/metadataqueries
+ # Datastore Metadata
+ #
# @example
# query = Gcloud::Datastore::Query.new
# query.kind("Task").
- # where("completed", "=", true)
+ # where("done", "=", false).
+ # where("priority", ">=", 4).
+ # order("priority", :desc)
#
- # entities = dataset.run query
+ # tasks = datastore.run query
#
class Query
##
# Returns a new query object.
#
# @example
# query = Gcloud::Datastore::Query.new
#
def initialize
- @_query = Proto::Query.new
+ @grpc = Google::Datastore::V1beta3::Query.new
end
##
# Add the kind of entities to query.
#
+ # Special entity kinds such as `__namespace__`, `__kind__`, and
+ # `__property__` can be used for [metadata
+ # queries](https://cloud.google.com/datastore/docs/concepts/metadataqueries).
+ #
# @example
# query = Gcloud::Datastore::Query.new
# query.kind "Task"
#
- # all_tasks = dataset.run query
+ # tasks = datastore.run query
#
def kind *kinds
- @_query.kind ||= Proto::KindExpression.new
- @_query.kind.name ||= []
- @_query.kind.name |= kinds
+ kinds.each do |kind|
+ grpc_kind = Google::Datastore::V1beta3::KindExpression.new(name: kind)
+ @grpc.kind << grpc_kind
+ end
+
self
end
##
# Add a property filter to the query.
#
# @example
# query = Gcloud::Datastore::Query.new
# query.kind("Task").
- # where("completed", "=", true)
+ # where("done", "=", false)
#
- # completed_tasks = dataset.run query
+ # tasks = datastore.run query
#
+ # @example Add a composite property filter:
+ # query = Gcloud::Datastore::Query.new
+ # query.kind("Task").
+ # where("done", "=", false).
+ # where("priority", ">=", 4)
+ #
+ # tasks = datastore.run query
+ #
+ # @example Add an inequality filter on a **single** property only:
+ # query = Gcloud::Datastore::Query.new
+ # query.kind("Task").
+ # where("created", ">=", Time.utc(1990, 1, 1)).
+ # where("created", "<", Time.utc(2000, 1, 1))
+ #
+ # tasks = datastore.run query
+ #
+ # @example Add a composite filter on an array property:
+ # query = Gcloud::Datastore::Query.new
+ # query.kind("Task").
+ # where("tag", "=", "fun").
+ # where("tag", "=", "programming")
+ #
+ # tasks = datastore.run query
+ #
+ # @example Add an inequality filter on an array property :
+ # query = Gcloud::Datastore::Query.new
+ # query.kind("Task").
+ # where("tag", ">", "learn").
+ # where("tag", "<", "math")
+ #
+ # tasks = datastore.run query
+ #
+ # @example Add a key filter using the special property `__key__`:
+ # query = Gcloud::Datastore::Query.new
+ # query.kind("Task").
+ # where("__key__", ">", datastore.key("Task", "someTask"))
+ #
+ # tasks = datastore.run query
+ #
+ # @example Add a key filter to a *kindless* query:
+ # last_seen_key = datastore.key "Task", "a"
+ # query = Gcloud::Datastore::Query.new
+ # query.where("__key__", ">", last_seen_key)
+ #
+ # tasks = datastore.run query
+ #
def where name, operator, value
- # Initialize filter
- @_query.filter ||= Proto.new_filter.tap do |f|
- f.composite_filter = Proto.new_composite_filter
- end
- # Create new property filter
- filter = Proto.new_filter.tap do |f|
- f.property_filter = Proto.new_property_filter name, operator, value
- end
- # Add new property filter to the list
- @_query.filter.composite_filter.filter << filter
+ @grpc.filter ||= Google::Datastore::V1beta3::Filter.new(
+ composite_filter: Google::Datastore::V1beta3::CompositeFilter.new(
+ op: :AND
+ )
+ )
+ @grpc.filter.composite_filter.filters << \
+ Google::Datastore::V1beta3::Filter.new(
+ property_filter: Google::Datastore::V1beta3::PropertyFilter.new(
+ property: Google::Datastore::V1beta3::PropertyReference.new(
+ name: name),
+ op: GRPCUtils.to_prop_filter_op(operator),
+ value: GRPCUtils.to_value(value)
+ )
+ )
+
self
end
alias_method :filter, :where
##
# Add a filter for entities that inherit from a key.
#
# @example
+ # task_list_key = datastore.key "TaskList", "default"
+ #
# query = Gcloud::Datastore::Query.new
# query.kind("Task").
- # ancestor(parent.key)
+ # ancestor(task_list_key)
#
- # completed_tasks = dataset.run query
+ # tasks = datastore.run query
#
def ancestor parent
# Use key if given an entity
parent = parent.key if parent.respond_to? :key
where "__key__", "~", parent
@@ -103,110 +168,181 @@
# Sort the results by a property name.
# By default, an ascending sort order will be used.
# To sort in descending order, provide a second argument
# of a string or symbol that starts with "d".
#
- # @example
+ # @example With ascending sort order:
# query = Gcloud::Datastore::Query.new
# query.kind("Task").
- # order("due", :desc)
+ # order("created")
#
- # sorted_tasks = dataset.run query
+ # tasks = datastore.run query
#
+ # @example With descending sort order:
+ # query = Gcloud::Datastore::Query.new
+ # query.kind("Task").
+ # order("created", :desc)
+ #
+ # tasks = datastore.run query
+ #
+ # @example With multiple sort orders:
+ # query = Gcloud::Datastore::Query.new
+ # query.kind("Task").
+ # order("priority", :desc).
+ # order("created")
+ #
+ # tasks = datastore.run query
+ #
+ # @example A property used in an inequality filter must be ordered first:
+ # query = Gcloud::Datastore::Query.new
+ # query.kind("Task").
+ # where("priority", ">", 3).
+ # order("priority").
+ # order("created")
+ #
+ # tasks = datastore.run query
+ #
def order name, direction = :asc
- @_query.order ||= []
- po = Proto::PropertyOrder.new
- po.property = Proto::PropertyReference.new
- po.property.name = name
- po.direction = Proto.to_prop_order_direction direction
- @_query.order << po
+ @grpc.order << Google::Datastore::V1beta3::PropertyOrder.new(
+ property: Google::Datastore::V1beta3::PropertyReference.new(
+ name: name),
+ direction: prop_order_direction(direction)
+ )
+
self
end
##
# Set a limit on the number of results to be returned.
#
# @example
# query = Gcloud::Datastore::Query.new
# query.kind("Task").
- # limit(10)
+ # limit(5)
#
- # paginated_tasks = dataset.run query
+ # tasks = datastore.run query
#
def limit num
- @_query.limit = num
+ @grpc.limit = Google::Protobuf::Int32Value.new(value: num)
+
self
end
##
# Set an offset for the results to be returned.
#
# @example
# query = Gcloud::Datastore::Query.new
# query.kind("Task").
- # limit(10).
- # offset(20)
+ # limit(5).
+ # offset(10)
#
- # paginated_tasks = dataset.run query
+ # tasks = datastore.run query
#
def offset num
- @_query.offset = num
+ @grpc.offset = num
+
self
end
##
# Set the cursor to start the results at.
#
# @example
# query = Gcloud::Datastore::Query.new
# query.kind("Task").
- # limit(10).
- # cursor(task_cursor)
+ # limit(page_size).
+ # start(page_cursor)
#
- # paginated_tasks = dataset.run query
+ # tasks = datastore.run query
#
def start cursor
- @_query.start_cursor = Proto.decode_cursor cursor
+ if cursor.is_a? Cursor
+ @grpc.start_cursor = cursor.to_grpc
+ elsif cursor.is_a? String
+ @grpc.start_cursor = GRPCUtils.decode_bytes cursor
+ else
+ fail ArgumentError, "Can't set a cursor using a #{cursor.class}."
+ end
+
self
end
alias_method :cursor, :start
##
# Retrieve only select properties from the matched entities.
#
# @example
# query = Gcloud::Datastore::Query.new
# query.kind("Task").
- # select("completed", "due")
+ # select("priority", "percent_complete")
#
- # partial_tasks = dataset.run query
+ # priorities = []
+ # percent_completes = []
+ # datastore.run(query).each do |task|
+ # priorities << task["priority"]
+ # percent_completes << task["percent_complete"]
+ # end
#
+ # @example A keys-only query using the special property `__key__`:
+ # query = Gcloud::Datastore::Query.new
+ # query.kind("Task").
+ # select("__key__")
+ #
+ # keys = datastore.run(query).map(&:key)
+ #
def select *names
- @_query.projection ||= []
- @_query.projection += Proto.new_property_expressions(*names)
+ names.each do |name|
+ grpc_projection = Google::Datastore::V1beta3::Projection.new(
+ property: Google::Datastore::V1beta3::PropertyReference.new(
+ name: name))
+ @grpc.projection << grpc_projection
+ end
+
self
end
alias_method :projection, :select
##
# Group results by a list of properties.
#
# @example
# query = Gcloud::Datastore::Query.new
# query.kind("Task").
- # group_by("completed")
+ # distinct_on("type", "priority").
+ # order("type").
+ # order("priority")
#
- # grouped_tasks = dataset.run query
+ # tasks = datastore.run query
#
def group_by *names
- @_query.group_by ||= []
- @_query.group_by += Proto.new_property_references(*names)
+ names.each do |name|
+ grpc_property = Google::Datastore::V1beta3::PropertyReference.new(
+ name: name)
+ @grpc.distinct_on << grpc_property
+ end
+
self
end
+ alias_method :distinct_on, :group_by
# @private
- def to_proto
- @_query
+ def to_grpc
+ @grpc
+ end
+
+ protected
+
+ ##
+ # @private Get the property order direction for a string.
+ def prop_order_direction direction
+ if direction.to_s.downcase.start_with? "a"
+ :ASCENDING
+ elsif direction.to_s.downcase.start_with? "d"
+ :DESCENDING
+ else
+ :DIRECTION_UNSPECIFIED
+ end
end
end
end
end