oedipus 0.0.1.pre1 → 0.0.1.pre2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +2 -0
- data/README.md +235 -44
- data/Rakefile +25 -0
- data/ext/oedipus/extconf.rb +72 -0
- data/ext/oedipus/oedipus.c +239 -0
- data/ext/oedipus/oedipus.h +50 -0
- data/lib/oedipus/comparison/between.rb +26 -0
- data/lib/oedipus/comparison/equal.rb +21 -0
- data/lib/oedipus/comparison/gt.rb +21 -0
- data/lib/oedipus/comparison/gte.rb +21 -0
- data/lib/oedipus/comparison/in.rb +21 -0
- data/lib/oedipus/comparison/lt.rb +21 -0
- data/lib/oedipus/comparison/lte.rb +21 -0
- data/lib/oedipus/comparison/not.rb +25 -0
- data/lib/oedipus/comparison/not_equal.rb +21 -0
- data/lib/oedipus/comparison/not_in.rb +21 -0
- data/lib/oedipus/comparison/outside.rb +26 -0
- data/lib/oedipus/comparison/shortcuts.rb +144 -0
- data/lib/oedipus/comparison.rb +88 -0
- data/lib/oedipus/connection.rb +91 -13
- data/lib/oedipus/connection_error.rb +14 -0
- data/lib/oedipus/index.rb +189 -46
- data/lib/oedipus/query_builder.rb +97 -4
- data/lib/oedipus/version.rb +1 -1
- data/lib/oedipus.rb +24 -7
- data/oedipus.gemspec +4 -5
- data/spec/integration/connection_spec.rb +58 -0
- data/spec/integration/index_spec.rb +353 -0
- data/spec/spec_helper.rb +2 -23
- data/spec/support/test_harness.rb +30 -9
- data/spec/unit/comparison/between_spec.rb +36 -0
- data/spec/unit/comparison/equal_spec.rb +22 -0
- data/spec/unit/comparison/gt_spec.rb +22 -0
- data/spec/unit/comparison/gte_spec.rb +22 -0
- data/spec/unit/comparison/in_spec.rb +22 -0
- data/spec/unit/comparison/lt_spec.rb +22 -0
- data/spec/unit/comparison/lte_spec.rb +22 -0
- data/spec/unit/comparison/not_equal_spec.rb +22 -0
- data/spec/unit/comparison/not_in_spec.rb +22 -0
- data/spec/unit/comparison/not_spec.rb +37 -0
- data/spec/unit/comparison/outside_spec.rb +36 -0
- data/spec/unit/comparison/shortcuts_spec.rb +125 -0
- data/spec/unit/comparison_spec.rb +109 -0
- data/spec/unit/query_builder_spec.rb +150 -0
- metadata +68 -19
- data/lib/oedipus/mysql/client.rb +0 -136
- data/spec/unit/connection_spec.rb +0 -36
- data/spec/unit/index_spec.rb +0 -85
@@ -0,0 +1,50 @@
|
|
1
|
+
/*-- encoding: utf-8 --*/
|
2
|
+
|
3
|
+
/*
|
4
|
+
* Oedipus Sphinx 2 Search.
|
5
|
+
* Copyright © 2012 Chris Corbyn.
|
6
|
+
*
|
7
|
+
* See LICENSE file for details.
|
8
|
+
*/
|
9
|
+
|
10
|
+
#include <ruby.h>
|
11
|
+
#include <mysql.h>
|
12
|
+
|
13
|
+
/*! Internal struct used to reference a mysql connection */
|
14
|
+
typedef struct {
|
15
|
+
/*! Boolean representing the connected state */
|
16
|
+
int connected;
|
17
|
+
/*! The actual pointer allocated by mysql_init() */
|
18
|
+
MYSQL * ptr;
|
19
|
+
} OdpMysql;
|
20
|
+
|
21
|
+
/* -- Public methods -- */
|
22
|
+
|
23
|
+
/*! Allocate and initialize a new mysql client */
|
24
|
+
static VALUE odp_new(VALUE klass, VALUE host, VALUE port);
|
25
|
+
|
26
|
+
/*! Initialize a new mysql client */
|
27
|
+
static VALUE odp_initialize(VALUE self, VALUE host, VALUE port);
|
28
|
+
|
29
|
+
/*! Connect, or reconnect to mysql */
|
30
|
+
static VALUE odp_open(VALUE self);
|
31
|
+
|
32
|
+
/*! Disconnect from mysql */
|
33
|
+
static VALUE odp_close(VALUE self);
|
34
|
+
|
35
|
+
/*! Execute an SQL non-read query and return the number of rows affected */
|
36
|
+
static VALUE odp_execute(VALUE self, VALUE sql);
|
37
|
+
|
38
|
+
/*! Execute several SQL read queries and return the result sets */
|
39
|
+
static VALUE odp_query(VALUE self, VALUE sql);
|
40
|
+
|
41
|
+
/*! Cast the given field to a ruby data type */
|
42
|
+
static VALUE odp_cast_value(MYSQL_FIELD f, char * v, unsigned long len);
|
43
|
+
|
44
|
+
/* -- Internal methods -- */
|
45
|
+
|
46
|
+
/*! Generic method to raise a connection error */
|
47
|
+
static void odp_raise(VALUE self, const char *msg);
|
48
|
+
|
49
|
+
/*! Free memory allocated to mysql */
|
50
|
+
static void odp_free(OdpMysql *conn);
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
##
|
4
|
+
# Oedipus Sphinx 2 Search.
|
5
|
+
# Copyright © 2012 Chris Corbyn.
|
6
|
+
#
|
7
|
+
# See LICENSE file for details.
|
8
|
+
##
|
9
|
+
|
10
|
+
module Oedipus
|
11
|
+
# Between comparison of range.
|
12
|
+
class Comparison::Between < Comparison
|
13
|
+
def to_s
|
14
|
+
[
|
15
|
+
"BETWEEN",
|
16
|
+
Connection.quote(v.first),
|
17
|
+
"AND",
|
18
|
+
Connection.quote(v.exclude_end? ? v.end - 1 : v.end)
|
19
|
+
].join(" ")
|
20
|
+
end
|
21
|
+
|
22
|
+
def inverse
|
23
|
+
Comparison::Outside.new(v)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
##
|
4
|
+
# Oedipus Sphinx 2 Search.
|
5
|
+
# Copyright © 2012 Chris Corbyn.
|
6
|
+
#
|
7
|
+
# See LICENSE file for details.
|
8
|
+
##
|
9
|
+
|
10
|
+
module Oedipus
|
11
|
+
# Equality comparison of value.
|
12
|
+
class Comparison::Equal < Comparison
|
13
|
+
def to_s
|
14
|
+
"= #{Connection.quote(v)}"
|
15
|
+
end
|
16
|
+
|
17
|
+
def inverse
|
18
|
+
Comparison::NotEqual.new(v)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
##
|
4
|
+
# Oedipus Sphinx 2 Search.
|
5
|
+
# Copyright © 2012 Chris Corbyn.
|
6
|
+
#
|
7
|
+
# See LICENSE file for details.
|
8
|
+
##
|
9
|
+
|
10
|
+
module Oedipus
|
11
|
+
# Greater than comparison of +v+.
|
12
|
+
class Comparison::GT < Comparison
|
13
|
+
def to_s
|
14
|
+
"> #{Connection.quote(v)}"
|
15
|
+
end
|
16
|
+
|
17
|
+
def inverse
|
18
|
+
Comparison::LTE.new(v)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
##
|
4
|
+
# Oedipus Sphinx 2 Search.
|
5
|
+
# Copyright © 2012 Chris Corbyn.
|
6
|
+
#
|
7
|
+
# See LICENSE file for details.
|
8
|
+
##
|
9
|
+
|
10
|
+
module Oedipus
|
11
|
+
# Greater than or equal comparison of +v+.
|
12
|
+
class Comparison::GTE < Comparison
|
13
|
+
def to_s
|
14
|
+
">= #{Connection.quote(v)}"
|
15
|
+
end
|
16
|
+
|
17
|
+
def inverse
|
18
|
+
Comparison::LT.new(v)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
##
|
4
|
+
# Oedipus Sphinx 2 Search.
|
5
|
+
# Copyright © 2012 Chris Corbyn.
|
6
|
+
#
|
7
|
+
# See LICENSE file for details.
|
8
|
+
##
|
9
|
+
|
10
|
+
module Oedipus
|
11
|
+
# IN comparison of +v+.
|
12
|
+
class Comparison::In < Comparison
|
13
|
+
def to_s
|
14
|
+
"IN (#{v.map { |o| Connection.quote(o)}.join(', ')})"
|
15
|
+
end
|
16
|
+
|
17
|
+
def inverse
|
18
|
+
Comparison::NotIn.new(v)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
##
|
4
|
+
# Oedipus Sphinx 2 Search.
|
5
|
+
# Copyright © 2012 Chris Corbyn.
|
6
|
+
#
|
7
|
+
# See LICENSE file for details.
|
8
|
+
##
|
9
|
+
|
10
|
+
module Oedipus
|
11
|
+
# Less than comparison of +v+.
|
12
|
+
class Comparison::LT < Comparison
|
13
|
+
def to_s
|
14
|
+
"< #{Connection.quote(v)}"
|
15
|
+
end
|
16
|
+
|
17
|
+
def inverse
|
18
|
+
Comparison::GTE.new(v)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
##
|
4
|
+
# Oedipus Sphinx 2 Search.
|
5
|
+
# Copyright © 2012 Chris Corbyn.
|
6
|
+
#
|
7
|
+
# See LICENSE file for details.
|
8
|
+
##
|
9
|
+
|
10
|
+
module Oedipus
|
11
|
+
# Less than or equal comparison of +v+.
|
12
|
+
class Comparison::LTE < Comparison
|
13
|
+
def to_s
|
14
|
+
"<= #{Connection.quote(v)}"
|
15
|
+
end
|
16
|
+
|
17
|
+
def inverse
|
18
|
+
Comparison::GT.new(v)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
##
|
4
|
+
# Oedipus Sphinx 2 Search.
|
5
|
+
# Copyright © 2012 Chris Corbyn.
|
6
|
+
#
|
7
|
+
# See LICENSE file for details.
|
8
|
+
##
|
9
|
+
|
10
|
+
module Oedipus
|
11
|
+
# Negation comparison of value.
|
12
|
+
class Comparison::Not < Comparison
|
13
|
+
def initialize(v)
|
14
|
+
super(Comparison.of(v))
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_s
|
18
|
+
v.inverse.to_s
|
19
|
+
end
|
20
|
+
|
21
|
+
def inverse
|
22
|
+
v
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
##
|
4
|
+
# Oedipus Sphinx 2 Search.
|
5
|
+
# Copyright © 2012 Chris Corbyn.
|
6
|
+
#
|
7
|
+
# See LICENSE file for details.
|
8
|
+
##
|
9
|
+
|
10
|
+
module Oedipus
|
11
|
+
# Negation comparison of value.
|
12
|
+
class Comparison::NotEqual < Comparison
|
13
|
+
def to_s
|
14
|
+
"!= #{Connection.quote(v)}"
|
15
|
+
end
|
16
|
+
|
17
|
+
def inverse
|
18
|
+
Comparison::Equal.new(v)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
##
|
4
|
+
# Oedipus Sphinx 2 Search.
|
5
|
+
# Copyright © 2012 Chris Corbyn.
|
6
|
+
#
|
7
|
+
# See LICENSE file for details.
|
8
|
+
##
|
9
|
+
|
10
|
+
module Oedipus
|
11
|
+
# NOT IN comparison of +v+.
|
12
|
+
class Comparison::NotIn < Comparison
|
13
|
+
def to_s
|
14
|
+
"NOT IN (#{v.map { |o| Connection.quote(o)}.join(', ')})"
|
15
|
+
end
|
16
|
+
|
17
|
+
def inverse
|
18
|
+
Comparison::In.new(v)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
##
|
4
|
+
# Oedipus Sphinx 2 Search.
|
5
|
+
# Copyright © 2012 Chris Corbyn.
|
6
|
+
#
|
7
|
+
# See LICENSE file for details.
|
8
|
+
##
|
9
|
+
|
10
|
+
module Oedipus
|
11
|
+
# Outside comparison of range.
|
12
|
+
class Comparison::Outside < Comparison
|
13
|
+
def to_s
|
14
|
+
[
|
15
|
+
"NOT BETWEEN",
|
16
|
+
Connection.quote(v.first),
|
17
|
+
"AND",
|
18
|
+
Connection.quote(v.exclude_end? ? v.end - 1 : v.end)
|
19
|
+
].join(" ")
|
20
|
+
end
|
21
|
+
|
22
|
+
def inverse
|
23
|
+
Comparison::Between.new(v)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
##
|
4
|
+
# Oedipus Sphinx 2 Search.
|
5
|
+
# Copyright © 2012 Chris Corbyn.
|
6
|
+
#
|
7
|
+
# See LICENSE file for details.
|
8
|
+
##
|
9
|
+
|
10
|
+
module Oedipus
|
11
|
+
class Comparison
|
12
|
+
# Provides short methods for casting values to Comparisons.
|
13
|
+
module Shortcuts
|
14
|
+
extend self
|
15
|
+
|
16
|
+
# Return the Comparison for equality of +v+.
|
17
|
+
#
|
18
|
+
# @param [Object] v
|
19
|
+
# any ruby object to compare in a query
|
20
|
+
#
|
21
|
+
# @return [Comparison::Equal]
|
22
|
+
# an equality comparison of v
|
23
|
+
def eq(v)
|
24
|
+
Equal.new(v)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Return the Comparison for inequality of +v+.
|
28
|
+
#
|
29
|
+
# @param [Object] v
|
30
|
+
# any ruby object to compare in a query
|
31
|
+
#
|
32
|
+
# @return [Comparison::Equal]
|
33
|
+
# an inequality comparison of v
|
34
|
+
def neq(v)
|
35
|
+
NotEqual.new(v)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Return the Comparison for negation of +v+.
|
39
|
+
#
|
40
|
+
# @param [Object] v
|
41
|
+
# any ruby object to compare in a query
|
42
|
+
#
|
43
|
+
# @return [Comparison::Not]
|
44
|
+
# an negated comparison of v
|
45
|
+
def not(v)
|
46
|
+
Not.new(v)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Return the Comparison for the range a..b.
|
50
|
+
#
|
51
|
+
# @param [Object] v
|
52
|
+
# either a Range, or a number
|
53
|
+
#
|
54
|
+
# @param [Fixnum] b
|
55
|
+
# if the first argument was a number, the other bound
|
56
|
+
#
|
57
|
+
# @return [Comparison::Between]
|
58
|
+
# an between comparison of a..b
|
59
|
+
def between(a, b = nil)
|
60
|
+
Between.new(a.kind_of?(Range) ? a : a..b)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Return the Comparison to exclude the range a..b.
|
64
|
+
#
|
65
|
+
# @param [Object] v
|
66
|
+
# either a Range, or a number
|
67
|
+
#
|
68
|
+
# @param [Fixnum] b
|
69
|
+
# if the first argument was a number, the other bound
|
70
|
+
#
|
71
|
+
# @return [Comparison::Outside]
|
72
|
+
# an outside comparison of a..b
|
73
|
+
def outside(a, b = nil)
|
74
|
+
Outside.new(a.kind_of?(Range) ? a : a..b)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Return the Comparison for any value in the set +v+.
|
78
|
+
#
|
79
|
+
# @param [Object] v
|
80
|
+
# any ruby object to compare
|
81
|
+
#
|
82
|
+
# @return [Comparison::In]
|
83
|
+
# the IN comparison for the values in v
|
84
|
+
def in(*v)
|
85
|
+
In.new(v.map { |el| el.respond_to?(:to_a) ? el.to_a : el }.flatten)
|
86
|
+
end
|
87
|
+
|
88
|
+
# Return the Comparison for any value NOT in the set +v+.
|
89
|
+
#
|
90
|
+
# @param [Object] v
|
91
|
+
# any ruby object to compare
|
92
|
+
#
|
93
|
+
# @return [Comparison::NotIn]
|
94
|
+
# the NOT IN comparison for the values in v
|
95
|
+
def not_in(*v)
|
96
|
+
NotIn.new(v.map { |el| el.respond_to?(:to_a) ? el.to_a : el }.flatten)
|
97
|
+
end
|
98
|
+
|
99
|
+
# Return the Comparison for >= +v+.
|
100
|
+
#
|
101
|
+
# @param [Object] v
|
102
|
+
# a number to compare
|
103
|
+
#
|
104
|
+
# @return [Comparison::GTE]
|
105
|
+
# a greater than or equal comparison for v
|
106
|
+
def gte(v)
|
107
|
+
GTE.new(v)
|
108
|
+
end
|
109
|
+
|
110
|
+
# Return the Comparison for > +v+.
|
111
|
+
#
|
112
|
+
# @param [Object] v
|
113
|
+
# a number to compare
|
114
|
+
#
|
115
|
+
# @return [Comparison::GT]
|
116
|
+
# a greater than comparison for v
|
117
|
+
def gt(v)
|
118
|
+
GT.new(v)
|
119
|
+
end
|
120
|
+
|
121
|
+
# Return the Comparison for <= +v+.
|
122
|
+
#
|
123
|
+
# @param [Object] v
|
124
|
+
# a number to compare
|
125
|
+
#
|
126
|
+
# @return [Comparison::LTE]
|
127
|
+
# a less than or equal comparison for v
|
128
|
+
def lte(v)
|
129
|
+
LTE.new(v)
|
130
|
+
end
|
131
|
+
|
132
|
+
# Return the Comparison for < +v+.
|
133
|
+
#
|
134
|
+
# @param [Object] v
|
135
|
+
# a number to compare
|
136
|
+
#
|
137
|
+
# @return [Comparison::LT]
|
138
|
+
# a less than comparison for v
|
139
|
+
def lt(v)
|
140
|
+
LT.new(v)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
##
|
4
|
+
# Oedipus Sphinx 2 Search.
|
5
|
+
# Copyright © 2012 Chris Corbyn.
|
6
|
+
#
|
7
|
+
# See LICENSE file for details.
|
8
|
+
##
|
9
|
+
|
10
|
+
module Oedipus
|
11
|
+
# Represents a comparison operator and value.
|
12
|
+
class Comparison
|
13
|
+
class << self
|
14
|
+
# Return a suitable comparison object for +v+.
|
15
|
+
#
|
16
|
+
# The conversions are:
|
17
|
+
#
|
18
|
+
# - leave Comparison objects unchanged
|
19
|
+
# - convert real ranges to Between comparisons
|
20
|
+
# - convert Infinity-bounded exclusive ranges to GT/LT comparisons
|
21
|
+
# - convert Infinity-bounded inclusive ranges to GTE/LTE comparisons.
|
22
|
+
# - convert everything else to an Equal comparison
|
23
|
+
#
|
24
|
+
# @param [Object] v
|
25
|
+
# a ruby object to be compared
|
26
|
+
#
|
27
|
+
# @param [Comparison]
|
28
|
+
# a comparison suitable for comparing the input
|
29
|
+
def of(v)
|
30
|
+
case v
|
31
|
+
when Comparison
|
32
|
+
v
|
33
|
+
when Range
|
34
|
+
if v.end == Float::INFINITY
|
35
|
+
v.exclude_end? ? Shortcuts.gt(v.first) : Shortcuts.gte(v.first)
|
36
|
+
elsif v.first == -Float::INFINITY
|
37
|
+
v.exclude_end? ? Shortcuts.lt(v.end) : Shortcuts.lte(v.end)
|
38
|
+
else
|
39
|
+
Shortcuts.between(v)
|
40
|
+
end
|
41
|
+
when Enumerable
|
42
|
+
Shortcuts.in(v)
|
43
|
+
else
|
44
|
+
Shortcuts.eq(v)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
attr_reader :v
|
50
|
+
|
51
|
+
# Initialize a new Comparison for +v+.
|
52
|
+
#
|
53
|
+
# @param [Object] v
|
54
|
+
# any ruby object to compare
|
55
|
+
def initialize(v)
|
56
|
+
@v = v
|
57
|
+
end
|
58
|
+
|
59
|
+
# Compare two comparisons for equality.
|
60
|
+
#
|
61
|
+
# @param [Comparison] other
|
62
|
+
# another comparison to check
|
63
|
+
#
|
64
|
+
# @return [Boolean]
|
65
|
+
# true if the comparisons are the same
|
66
|
+
def ==(other)
|
67
|
+
other.class == self.class && other.v == v
|
68
|
+
end
|
69
|
+
|
70
|
+
alias_method :eql?, :==
|
71
|
+
|
72
|
+
# Return the exact inverse of this comparison.
|
73
|
+
#
|
74
|
+
# @return [Comparison]
|
75
|
+
# the inverse of the current comparison
|
76
|
+
def inverse
|
77
|
+
raise NotImplementedError, "Comparison#inverse must be defined by subclasses"
|
78
|
+
end
|
79
|
+
|
80
|
+
# Represent the comparison as a string.
|
81
|
+
#
|
82
|
+
# @return [String]
|
83
|
+
# an expression to compare a LHS against v
|
84
|
+
def to_s
|
85
|
+
raise NotImplementedError, "Comparison#to_s must be defined by subclasses"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
data/lib/oedipus/connection.rb
CHANGED
@@ -7,22 +7,69 @@
|
|
7
7
|
# See LICENSE file for details.
|
8
8
|
##
|
9
9
|
|
10
|
-
require "mysql"
|
11
|
-
|
12
|
-
# SphinxQL greets with charset number 0
|
13
|
-
Mysql::Charset::NUMBER_TO_CHARSET[0] = Mysql::Charset::COLLATION_TO_CHARSET["utf8_general_ci"]
|
14
|
-
|
15
10
|
module Oedipus
|
16
11
|
# Provides an interface for talking to SphinxQL.
|
12
|
+
#
|
13
|
+
# Currently this class wraps a native mysql extension.
|
17
14
|
class Connection
|
15
|
+
class << self
|
16
|
+
# Quote a value (of any type) for use in SphinxQL.
|
17
|
+
#
|
18
|
+
# @param [Object] v
|
19
|
+
# the value to quote
|
20
|
+
#
|
21
|
+
# @return [Object]
|
22
|
+
# the safe value
|
23
|
+
#
|
24
|
+
# Note that single quotes are added to strings.
|
25
|
+
def quote(v)
|
26
|
+
require "bigdecimal"
|
27
|
+
case v
|
28
|
+
when BigDecimal, Rational, Complex
|
29
|
+
v.to_f
|
30
|
+
when Numeric
|
31
|
+
v
|
32
|
+
when NilClass
|
33
|
+
"NULL"
|
34
|
+
else
|
35
|
+
"'#{escape_str(v.to_s)}'"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Escape a string, without adding enclosing quotes.
|
40
|
+
#
|
41
|
+
# @param [String] str
|
42
|
+
# the unsafe input string
|
43
|
+
#
|
44
|
+
# @return [String]
|
45
|
+
# a safe string for use in SphinxQL
|
46
|
+
def escape_str(str)
|
47
|
+
str.gsub(/[\0\n\r\\\'\"\x1a]/) do |s|
|
48
|
+
case s
|
49
|
+
when "\0" then "\\0"
|
50
|
+
when "\n" then "\\n"
|
51
|
+
when "\r" then "\\r"
|
52
|
+
when "\x1a" then "\\Z"
|
53
|
+
else "\\#{s}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
18
59
|
# Instantiate a new Connection to a SphinxQL host.
|
19
60
|
#
|
20
|
-
# @param [
|
61
|
+
# @param [String] server
|
62
|
+
# a 'hostname:port' string
|
63
|
+
#
|
64
|
+
# @param [Hash] options
|
21
65
|
# a Hash containing :host and :port
|
22
66
|
#
|
23
67
|
# The connection will be established on initialization.
|
24
68
|
def initialize(options)
|
25
|
-
|
69
|
+
options = options.kind_of?(String) ?
|
70
|
+
Hash[ [:host, :port].zip(options.split(":")) ] :
|
71
|
+
options
|
72
|
+
@conn = Oedipus::Mysql.new(options[:host], options[:port].to_i)
|
26
73
|
end
|
27
74
|
|
28
75
|
# Acess a specific index for querying.
|
@@ -36,15 +83,46 @@ module Oedipus
|
|
36
83
|
Index.new(index_name, self)
|
37
84
|
end
|
38
85
|
|
39
|
-
|
86
|
+
# Execute one or more queries in a batch.
|
87
|
+
#
|
88
|
+
# Queries should be separated by semicolons.
|
89
|
+
# Results are returned in a 2-dimensional array.
|
90
|
+
#
|
91
|
+
# @param [String] sql
|
92
|
+
# one or more SphinxQL statements, separated by semicolons
|
93
|
+
#
|
94
|
+
# @return [Array]
|
95
|
+
# an array of arrays, containing the returned records
|
96
|
+
#
|
97
|
+
# Note that SphinxQL does not support prepared statements.
|
98
|
+
def multi_query(sql)
|
40
99
|
@conn.query(sql)
|
41
100
|
end
|
42
101
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
102
|
+
# Execute a single read query.
|
103
|
+
#
|
104
|
+
# @param [String] sql
|
105
|
+
# a single SphinxQL statement
|
106
|
+
#
|
107
|
+
# @return [Array]
|
108
|
+
# an array of Hashes containing the matched records
|
109
|
+
#
|
110
|
+
# Note that SphinxQL does not support prepared statements.
|
111
|
+
def query(sql)
|
112
|
+
@conn.query(sql).first
|
113
|
+
end
|
114
|
+
|
115
|
+
# Execute a non-read query.
|
116
|
+
#
|
117
|
+
# @param [String] sql
|
118
|
+
# a SphinxQL query, such as INSERT or REPLACE
|
119
|
+
#
|
120
|
+
# @return [Fixnum]
|
121
|
+
# the number of affected rows
|
122
|
+
#
|
123
|
+
# Note that SphinxQL does not support prepared statements.
|
124
|
+
def execute(sql)
|
125
|
+
@conn.execute(sql)
|
48
126
|
end
|
49
127
|
end
|
50
128
|
end
|