# encoding: UTF-8 # # Copyright (c) 2010-2017 GoodData Corporation. All rights reserved. # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. require_relative '../metadata' require_relative 'metadata' require_relative '../../mixins/is_attribute' module GoodData class Attribute < MdObject include Mixin::IsAttribute ATTRIBUTE_BASE_AGGREGATIONS = [:count] class << self # Method intended to get all objects of that type in a specified project # # @param options [Hash] the options hash # @option options [Boolean] :full if passed true the subclass can decide # to pull in full objects. This is desirable from the usability POV # but unfortunately has negative impact on performance so it is # not the default. # @return [Array | Array] Return the appropriate metadata objects or their representation def all(options = { :client => GoodData.connection, :project => GoodData.project }) query('attribute', Attribute, options) end # Finds the value of an atribute and gives you the textual form for the label that is acquired by calling primary_label method # # @param uri [String] Uri of the element. in the form of /gdc/md/PID/obj/OBJ_ID/elements?id=21 # @return [String] Textual representation of a particular attribute element def find_element_value(stuff, opts = { :project => GoodData.project }) stuff.scan(%r{([^\[\]]*)\/elements\?id=(\d+)}).pmap do |a, id| opts[:project].attributes(a).primary_label.find_element_value(id.to_i) end.first end end def drill_down(attribute) attribute = Attribute[attribute, client: client, project: project] content['drillDownStepAttributeDF'] = attribute.primary_label.meta['uri'] save end # Returns the labels of an attribute # @return [Array] def display_forms content['displayForms'].pmap { |df| project.labels(df['meta']['uri']) } end alias_method :labels, :display_forms def dimension uri = content['dimension'] return nil if uri.nil? GoodData::Dimension[uri, client: client, project: project] end # Tells you if an attribute is a date dimension. This happens by inspecting # an identifier if it conforms to a particular scheme. # # @return [Boolean] Is the attribute a date attribute? def date_attribute? things = [ 'week', 'euweek.in.year', 'day.in.week', 'day.in.month', 'day.in.quarter', 'day.in.euweek', 'date', 'quarter.in.year', 'week.in.year', 'day.in.year', 'month', 'quarter', 'month.in.quarter', 'week.in.quarter', 'year', 'euweek', 'euweek.in.quarter', 'month.in.year' ] potential_id = identifier.split('.')[1..-1].join('.') things.include?(potential_id) ? true : false end # Returns the first display form which is the primary one # @return [GoodData::Label] Primary label def primary_display_form labels.first end alias_method :primary_label, :primary_display_form # Creates the basic count metric with the attribute used. If you need to # compute the attribute on a different dataset you can specify that in # params. The metric created is not saved. # @param [Hash] options the options to pass to the value list # @option options [Symbol] :type type of aggregation function. # @option options [Symbol] :attribute Use this attribute if you need to # express different dataset for performing the computation on. It basically # serves for creating metrics like SELECT COUNT(User, Opportunity). # @return [GoodData::Metric] def create_metric(options = {}) an_attribute = options[:attribute] a_type = options[:type] || :count unless ATTRIBUTE_BASE_AGGREGATIONS.include?(a_type) fail 'Suggested aggreagtion function (#{a_type}) does not exist for ' \ 'base metric created out of attribute. You can use only one of' \ "#{ATTRIBUTE_BASE_AGGREGATIONS.map { |x| ':' + x.to_s }.join(',')}" end a_title = options[:title] || "#{a_type} of #{title}" if an_attribute project.create_metric("SELECT #{a_type.to_s.upcase}([#{uri}], [#{an_attribute.uri}])", title: a_title, extended_notation: false) else project.create_metric("SELECT #{a_type.to_s.upcase}([#{uri}])", title: a_title, extended_notation: false) end end alias_method :create_measure, :create_metric # For an element id find values (titles) for all display forms. Element id can be given as both number id or URI as a string beginning with / # @param [Object] element_id Element identifier either Number or a uri as a String # @return [Array] list of values for certain element. Returned in the same order as is the order of labels def values_for(element_id) # element_id = element_id.is_a?(String) ? element_id.match(/\?id=(\d)/)[1] : element_id labels.pmap do |label| label.find_element_value(element_id) end end # Returns all values for all labels. This is for inspection purposes only since obviously there can be huge number of elements. # @param [Hash] options the options to pass to the value list # @option options [Number] :limit limits the number of values to certain number. Default is 100 # @return [Array] def values results = labels.map(&:values) results.first.zip(*results[1..-1]) end # Allows to search in attribute labels by name. It uses the string as a basis for regexp and tries to match either a title or an identifier. Returns first match. # @param name [String] name used as a basis for regular expression # @return [GoodData::Label] def label_by_name(name) labels.find { |label| label.title =~ /#{name}/ || label.identifier =~ /#{name}/ } end def computed_attribute? content['rel'] && !content['rel'].empty? end end end