Class: Kasket::QueryParser
- Inherits:
-
Object
- Object
- Kasket::QueryParser
- Defined in:
- lib/kasket/query_parser.rb
Constant Summary collapse
- AND =
Examples: SELECT * FROM ‘users` WHERE (`users`.`id` = 2) SELECT * FROM `users` WHERE (`users`.`id` = 2) LIMIT 1 ’SELECT * FROM 'posts' WHERE ('posts'.'id' = 574019247) ‘
/\s+AND\s+/i.freeze
- VALUE =
Matches: 123, ?, ‘123’, ‘12”3’
/'?(\d+|\?|(?:(?:[^']|''|\\')*))'?/.freeze
Instance Method Summary collapse
-
#initialize(model_class) ⇒ QueryParser
constructor
A new instance of QueryParser.
-
#parse(sql) ⇒ Hash|nil
Parses a SQL query to produce a kasket query.
Constructor Details
#initialize(model_class) ⇒ QueryParser
Returns a new instance of QueryParser.
12 13 14 15 16 17 18 19 20 21 22 |
# File 'lib/kasket/query_parser.rb', line 12 def initialize(model_class) @model_class = model_class @supported_query_pattern = /^select\s+(.+?)\s+from (?:`|")#{@model_class.table_name}(?:`|") where (.*?)(|\s+limit 1)\s*$/i @star_pattern = /^((`|")#{@model_class.table_name}\2\.)?\*$/ # Matches: `users`.id, `users`.`id`, users.id, id @table_and_column_pattern = /(?:(?:`|")?#{@model_class.table_name}(?:`|")?\.)?(?:`|")?([a-zA-Z]\w*)(?:`|")?/ # Matches: KEY = VALUE, (KEY = VALUE), ()(KEY = VALUE)) @key_eq_value_pattern = /^[\(\s]*#{@table_and_column_pattern}\s+(=|IN)\s+#{VALUE}[\)\s]*$/ end |
Instance Method Details
#parse(sql) ⇒ Hash|nil
Parses a SQL query to produce a kasket query
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/kasket/query_parser.rb', line 29 def parse(sql) if match = @supported_query_pattern.match(sql) select = match[1] unless @star_pattern.match? select # If we're not selecting all columns using star, then ensure all columns are selected explicitly select_columns = select.split(/\s*,\s*/).map do |s| break unless column_match = @table_and_column_pattern.match(s) column_match[1] end.uniq columns = @model_class.column_names return unless columns.size == select_columns.size && (columns - select_columns).empty? end where = match[2] limit = match[3] query = {} query[:attributes] = sorted_attribute_value_pairs(where) return if query[:attributes].nil? if query[:attributes].size > 1 && query[:attributes].map(&:last).any?(Array) # this is a query with IN conditions AND other conditions return end query[:index] = query[:attributes].map(&:first) query[:limit] = limit.blank? ? nil : 1 query[:key] = @model_class.kasket_key_for(query[:attributes]) query[:key] << '/first' if query[:limit] == 1 && !query[:index].include?(:id) query end end |