module Sparkql::ParserCompatibility
Required interface for existing parser implementations
Constants
- FILTER_VALUES
Ordered by precedence.
- MAXIMUM_EXPRESSIONS
- MAXIMUM_FUNCTION_DEPTH
- MAXIMUM_LEVEL_DEPTH
- MAXIMUM_MULTIPLE_VALUES
- OPERATORS_SUPPORTING_MULTIPLES
Public Instance Methods
# File lib/sparkql/parser_compatibility.rb, line 169 def boolean_escape(string) "true" == string end
processes escape characters for a given string. May be overridden by child classes.
# File lib/sparkql/parser_compatibility.rb, line 145 def character_escape( string ) string.gsub(/^\'/,'').gsub(/\'$/,'').gsub(/\\'/, "'") end
To be implemented by child class. Shall return a valid query string for the respective database, or nil if the source could not be processed. It may be possible to return a valid SQL string AND have errors ( as checked by errors? ), but this will be left to the discretion of the child class.
# File lib/sparkql/parser_compatibility.rb, line 63 def compile( source, mapper ) raise NotImplementedError end
# File lib/sparkql/parser_compatibility.rb, line 157 def date_escape(string) Date.parse(string) end
# File lib/sparkql/parser_compatibility.rb, line 161 def datetime_escape(string) DateTime.parse(string) end
# File lib/sparkql/parser_compatibility.rb, line 153 def decimal_escape( string ) string.to_f end
# File lib/sparkql/parser_compatibility.rb, line 99 def dropped_errors? process_errors.dropped_errors? end
Returns an array of errors. This is an array of ParserError
objects
# File lib/sparkql/parser_compatibility.rb, line 81 def errors @errors = [] unless defined?(@errors) @errors end
delegate :errors?, :fatal_errors?, :dropped_errors?, :recovered_errors?, :to => :process_errors Since I don't have rails delegate…
# File lib/sparkql/parser_compatibility.rb, line 93 def errors? process_errors.errors? end
# File lib/sparkql/parser_compatibility.rb, line 118 def escape_value( expression ) if expression[:value].is_a? Array return escape_value_list( expression ) end case expression[:type] when :character return character_escape(expression[:value]) when :integer return integer_escape(expression[:value]) when :decimal return decimal_escape(expression[:value]) when :date return date_escape(expression[:value]) when :datetime return datetime_escape(expression[:value]) when :time return time_escape(expression[:value]) when :boolean return boolean_escape(expression[:value]) when :null return nil end expression[:value] end
# File lib/sparkql/parser_compatibility.rb, line 106 def escape_value_list( expression ) final_list = [] expression[:value].each do | value | new_exp = { :value => value, :type => expression[:type] } final_list << escape_value(new_exp) end expression[:value] = final_list end
# File lib/sparkql/parser_compatibility.rb, line 96 def fatal_errors? process_errors.fatal_errors? end
# File lib/sparkql/parser_compatibility.rb, line 149 def integer_escape( string ) string.to_i end
# File lib/sparkql/parser_compatibility.rb, line 191 def max_expressions MAXIMUM_EXPRESSIONS end
# File lib/sparkql/parser_compatibility.rb, line 199 def max_function_depth MAXIMUM_FUNCTION_DEPTH end
Maximum supported nesting level for the parser filters
# File lib/sparkql/parser_compatibility.rb, line 187 def max_level_depth MAXIMUM_LEVEL_DEPTH end
# File lib/sparkql/parser_compatibility.rb, line 195 def max_values MAXIMUM_MULTIPLE_VALUES end
Delegator for methods to process the error list.
# File lib/sparkql/parser_compatibility.rb, line 87 def process_errors Sparkql::ErrorsProcessor.new(errors) end
# File lib/sparkql/parser_compatibility.rb, line 102 def recovered_errors? process_errors.recovered_errors? end
Returns the rule hash for a given type
# File lib/sparkql/parser_compatibility.rb, line 174 def rules_for_type( type ) FILTER_VALUES.each do |rule| return rule if rule[:type] == type end nil end
true if a given type supports multiple values
# File lib/sparkql/parser_compatibility.rb, line 182 def supports_multiple?( type ) rules_for_type(type).include?( :multiple ) end
# File lib/sparkql/parser_compatibility.rb, line 165 def time_escape(string) DateTime.parse(string) end
Returns a list of expressions tokenized in the following format:
- { :field => IdentifierName, :operator => “Eq”, :value => “'Fargo'”, :type => :character, :conjunction => “And” }
-
This step will set errors if source is not syntactically correct.
# File lib/sparkql/parser_compatibility.rb, line 70 def tokenize( source ) raise ArgumentError, "You must supply a source string to tokenize!" unless source.is_a?(String) # Reset the parser error stack @errors = [] expressions = self.parse(source) expressions end
Private Instance Methods
If a function is being applied to a field, we check that the return type of the function matches what is expected, and that the function supports the field type as the first argument.
# File lib/sparkql/parser_compatibility.rb, line 261 def check_function_type?(expression, expected) validate_manipulation_types(expression[:field_manipulations], expected) end
Checks the type of an expression with what is expected.
# File lib/sparkql/parser_compatibility.rb, line 216 def check_type!(expression, expected, supports_nulls = true) if (expected == expression[:type] && !expression.key?(:field_manipulations)) || (expression.key?(:field_manipulations) && check_function_type?(expression, expected)) || (supports_nulls && expression[:type] == :null) return true # If the field will be passed into a function, # check the type of the return value of the function # and coerce if necessary. elsif expression[:field_manipulations] && expression[:type] == :integer && expression[:field_manipulations][:return_type] == :decimal expression[:type] = :decimal expression[:cast] = :integer return true elsif expected == :datetime && expression[:type] == :date expression[:type] = :datetime expression[:cast] = :date return true elsif expected == :date && expression[:type] == :datetime expression[:type] = :date expression[:cast] = :datetime if multiple_values?(expression[:value]) expression[:value].map!{ |val| coerce_datetime val } else expression[:value] = coerce_datetime expression[:value] end return true elsif expected == :decimal && expression[:type] == :integer expression[:type] = :decimal expression[:cast] = :integer return true end type_error(expression, expected) false end
# File lib/sparkql/parser_compatibility.rb, line 328 def coerce_datetime datetime if datestr = datetime.match(/^(\d{4}-\d{2}-\d{2})/) datestr[0] else datetime end end
Builds the correct operator based on the type and the value. default should be the operator provided in the actual filter string
# File lib/sparkql/parser_compatibility.rb, line 299 def get_operator(expression, default ) f = rules_for_type(expression[:type]) if f[:operators].include?(default) if f[:multiple] && range?(expression[:value]) && default == 'Bt' return "Bt" elsif f[:multiple] && multiple_values?(expression[:value]) return nil unless operator_supports_multiples?(default) return default == "Ne" ? "Not In" : "In" elsif default == "Ne" return "Not Eq" end return default else return nil end end
# File lib/sparkql/parser_compatibility.rb, line 316 def multiple_values?(value) Array(value).size > 1 end
# File lib/sparkql/parser_compatibility.rb, line 324 def operator_supports_multiples?(operator) OPERATORS_SUPPORTING_MULTIPLES.include?(operator) end
# File lib/sparkql/parser_compatibility.rb, line 320 def range?(value) Array(value).size == 2 end
# File lib/sparkql/parser_compatibility.rb, line 205 def tokenizer_error( error_hash ) if @lexer error_hash[:token_index] = @lexer.token_index end self.errors << Sparkql::ParserError.new( error_hash ) end
# File lib/sparkql/parser_compatibility.rb, line 252 def type_error( expression, expected ) compile_error(:token => expression[:field], :expression => expression, :message => "expected #{expected} but found #{expression[:type]}", :status => :fatal ) end
# File lib/sparkql/parser_compatibility.rb, line 265 def validate_manipulation_types(field_manipulations, expected) if field_manipulations[:type] == :function function = Sparkql::FunctionResolver::SUPPORTED_FUNCTIONS[field_manipulations[:function_name].to_sym] return false if function.nil? field_manipulations[:args].each_with_index do |arg, index| if arg[:type] == :field return false unless function[:args][index].include?(:field) end end elsif field_manipulations[:type] == :arithmetic lhs = field_manipulations[:lhs] return false unless validate_side(lhs, expected) rhs = field_manipulations[:rhs] return false unless rhs.nil? || validate_side(rhs, expected) end true end
# File lib/sparkql/parser_compatibility.rb, line 284 def validate_side(side, expected) if side[:type] == :arithmetic return validate_manipulation_types(side, expected) elsif side[:type] == :field return false unless [:decimal, :integer].include?(expected) elsif side[:type] == :function return false unless [:decimal, :integer].include?(side[:return_type]) elsif ![:decimal, :integer].include?(side[:type]) return false end true end