File: query.rb

package info (click to toggle)
ruby-riddle 2.3.1-2~deb10u1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 10,752 kB
  • sloc: sql: 25,022; php: 5,992; ruby: 4,757; sh: 59; makefile: 5
file content (126 lines) | stat: -rw-r--r-- 2,682 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# frozen_string_literal: true

module Riddle::Query
  ESCAPE_CHARACTERS = /[\(\)\|\-!@~\/"\/\^\$\\><&=\?]/
  # http://sphinxsearch.com/docs/current/extended-syntax.html
  ESCAPE_WORDS = /\b(?:MAYBE|NEAR|PARAGRAPH|SENTENCE|ZONE|ZONESPAN)\b/
  MYSQL2_ESCAPE = defined?(Mysql2) && defined?(Mysql::Client)

  def self.connection(address = '127.0.0.1', port = 9312)
    require 'mysql2'

    # If you use localhost, MySQL insists on a socket connection, but Sphinx
    # requires a TCP connection. Using 127.0.0.1 fixes that.
    address = '127.0.0.1' if address == 'localhost'

    Mysql2::Client.new(
      :host => address,
      :port => port
    )
  end

  def self.meta
    'SHOW META'
  end

  def self.warnings
    'SHOW WARNINGS'
  end

  def self.status
    'SHOW STATUS'
  end

  def self.tables
    'SHOW TABLES'
  end

  def self.variables
    'SHOW VARIABLES'
  end

  def self.collation
    'SHOW COLLATION'
  end

  def self.describe(index)
    "DESCRIBE #{index}"
  end

  def self.begin
    'BEGIN'
  end

  def self.commit
    'COMMIT'
  end

  def self.rollback
    'ROLLBACK'
  end

  def self.set(variable, values, global = true)
    values = "(#{values.join(', ')})" if values.is_a?(Array)
    "SET#{ ' GLOBAL' if global } #{variable} = #{values}"
  end

  def self.snippets(data, index, query, options = nil)
    data, index, query = quote(data), quote(index), quote(query)

    options = ', ' + options.keys.collect { |key|
      value = translate_value options[key]
      value = quote value if value.is_a?(String)

      "#{value} AS #{key}"
    }.join(', ') unless options.nil?

    "CALL SNIPPETS(#{data}, #{index}, #{query}#{options})"
  end

  def self.create_function(name, type, file)
    type = type.to_s.upcase
    "CREATE FUNCTION #{name} RETURNS #{type} SONAME #{quote file}"
  end

  def self.drop_function(name)
    "DROP FUNCTION #{name}"
  end

  def self.update(index, id, values = {})
    values = values.keys.collect { |key|
      "#{key} = #{translate_value values[key]}"
    }.join(', ')

    "UPDATE #{index} SET #{values} WHERE id = #{id}"
  end

  def self.translate_value(value)
    case value
    when TrueClass
      1
    when FalseClass
      0
    else
      value
    end
  end

  def self.escape(string)
    string.gsub(ESCAPE_CHARACTERS) { |match| "\\#{match}" }
      .gsub(ESCAPE_WORDS) { |word| "\\#{word}" }
  end

  def self.quote(string)
    "'#{sql_escape string}'"
  end

  def self.sql_escape(string)
    return Mysql2::Client.escape(string) if MYSQL2_ESCAPE

    string.gsub(/['"\\]/) { |character| "\\#{character}" }
  end
end

require 'riddle/query/delete'
require 'riddle/query/insert'
require 'riddle/query/select'