dbldots_oedipus 0.0.16

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.
Files changed (54) hide show
  1. data/.gitignore +10 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE +20 -0
  5. data/README.md +435 -0
  6. data/Rakefile +26 -0
  7. data/ext/oedipus/extconf.rb +72 -0
  8. data/ext/oedipus/lexing.c +96 -0
  9. data/ext/oedipus/lexing.h +20 -0
  10. data/ext/oedipus/oedipus.c +339 -0
  11. data/ext/oedipus/oedipus.h +58 -0
  12. data/lib/oedipus.rb +40 -0
  13. data/lib/oedipus/comparison.rb +88 -0
  14. data/lib/oedipus/comparison/between.rb +21 -0
  15. data/lib/oedipus/comparison/equal.rb +21 -0
  16. data/lib/oedipus/comparison/gt.rb +21 -0
  17. data/lib/oedipus/comparison/gte.rb +21 -0
  18. data/lib/oedipus/comparison/in.rb +21 -0
  19. data/lib/oedipus/comparison/lt.rb +21 -0
  20. data/lib/oedipus/comparison/lte.rb +21 -0
  21. data/lib/oedipus/comparison/not.rb +25 -0
  22. data/lib/oedipus/comparison/not_equal.rb +21 -0
  23. data/lib/oedipus/comparison/not_in.rb +21 -0
  24. data/lib/oedipus/comparison/outside.rb +21 -0
  25. data/lib/oedipus/comparison/shortcuts.rb +144 -0
  26. data/lib/oedipus/connection.rb +124 -0
  27. data/lib/oedipus/connection/pool.rb +133 -0
  28. data/lib/oedipus/connection/registry.rb +56 -0
  29. data/lib/oedipus/connection_error.rb +14 -0
  30. data/lib/oedipus/index.rb +320 -0
  31. data/lib/oedipus/query_builder.rb +185 -0
  32. data/lib/oedipus/rspec/test_rig.rb +132 -0
  33. data/lib/oedipus/version.rb +12 -0
  34. data/oedipus.gemspec +42 -0
  35. data/spec/data/.gitkeep +0 -0
  36. data/spec/integration/connection/registry_spec.rb +50 -0
  37. data/spec/integration/connection_spec.rb +156 -0
  38. data/spec/integration/index_spec.rb +442 -0
  39. data/spec/spec_helper.rb +16 -0
  40. data/spec/unit/comparison/between_spec.rb +36 -0
  41. data/spec/unit/comparison/equal_spec.rb +22 -0
  42. data/spec/unit/comparison/gt_spec.rb +22 -0
  43. data/spec/unit/comparison/gte_spec.rb +22 -0
  44. data/spec/unit/comparison/in_spec.rb +22 -0
  45. data/spec/unit/comparison/lt_spec.rb +22 -0
  46. data/spec/unit/comparison/lte_spec.rb +22 -0
  47. data/spec/unit/comparison/not_equal_spec.rb +22 -0
  48. data/spec/unit/comparison/not_in_spec.rb +22 -0
  49. data/spec/unit/comparison/not_spec.rb +37 -0
  50. data/spec/unit/comparison/outside_spec.rb +36 -0
  51. data/spec/unit/comparison/shortcuts_spec.rb +125 -0
  52. data/spec/unit/comparison_spec.rb +109 -0
  53. data/spec/unit/query_builder_spec.rb +205 -0
  54. metadata +164 -0
@@ -0,0 +1,58 @@
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
+ // Macros for lazy fingers
14
+ #define ODP_TO_S(v) rb_funcall(v, rb_intern("to_s"), 0)
15
+ #define ODP_TO_F(n) rb_funcall(n, rb_intern("to_f"), 0)
16
+ #define ODP_KIND_OF_P(v, type) (rb_funcall(v, rb_intern("kind_of?"), 1, type) == Qtrue)
17
+
18
+ /*! Internal struct used to reference a mysql connection */
19
+ typedef struct {
20
+ /*! Boolean representing the connected state */
21
+ int connected;
22
+ /*! The actual pointer allocated by mysql_init() */
23
+ MYSQL * ptr;
24
+ } OdpMysql;
25
+
26
+ /* -- Public methods -- */
27
+
28
+ /*! Allocate and initialize a new mysql client */
29
+ static VALUE odp_new(VALUE klass, VALUE host, VALUE port);
30
+
31
+ /*! Initialize a new mysql client */
32
+ static VALUE odp_initialize(VALUE self, VALUE host, VALUE port);
33
+
34
+ /*! Connect, or reconnect to mysql */
35
+ static VALUE odp_open(VALUE self);
36
+
37
+ /*! Disconnect from mysql */
38
+ static VALUE odp_close(VALUE self);
39
+
40
+ /*! Execute an SQL non-read query and return the number of rows affected */
41
+ static VALUE odp_execute(int argc, VALUE * args, VALUE self);
42
+
43
+ /*! Execute several SQL read queries and return the result sets */
44
+ static VALUE odp_query(int argc, VALUE * args, VALUE self);
45
+
46
+ /* -- Internal methods -- */
47
+
48
+ /*! Generic method to raise a connection error */
49
+ static void odp_raise(VALUE self, const char *msg);
50
+
51
+ /*! Free memory allocated to mysql */
52
+ static void odp_free(OdpMysql * conn);
53
+
54
+ /*! Substitute all ? markers with the values in bind_values */
55
+ static VALUE odp_replace_bind_values(OdpMysql * conn, VALUE sql, VALUE * bind_values, int num_values);
56
+
57
+ /*! Cast the given field to a ruby data type */
58
+ static VALUE odp_cast_value(MYSQL_FIELD f, char * v, unsigned long len);
@@ -0,0 +1,40 @@
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
+ require "oedipus/version"
11
+
12
+ require "oedipus/oedipus"
13
+
14
+ require "oedipus/comparison"
15
+ require "oedipus/comparison/equal"
16
+ require "oedipus/comparison/not_equal"
17
+ require "oedipus/comparison/between"
18
+ require "oedipus/comparison/outside"
19
+ require "oedipus/comparison/in"
20
+ require "oedipus/comparison/not_in"
21
+ require "oedipus/comparison/gte"
22
+ require "oedipus/comparison/gt"
23
+ require "oedipus/comparison/lte"
24
+ require "oedipus/comparison/lt"
25
+ require "oedipus/comparison/not"
26
+ require "oedipus/comparison/shortcuts"
27
+
28
+ require "oedipus/query_builder"
29
+
30
+ require "oedipus/connection_error"
31
+ require "oedipus/connection"
32
+ require "oedipus/connection/pool"
33
+ require "oedipus/connection/registry"
34
+
35
+ require "oedipus/index"
36
+
37
+ module Oedipus
38
+ extend Comparison::Shortcuts
39
+ extend Connection::Registry
40
+ 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 SQL arguments.
81
+ #
82
+ # @return [Array]
83
+ # an SQL expression to compare a LHS against v
84
+ def to_sql
85
+ raise NotImplementedError, "Comparison#to_sql must be defined by subclasses"
86
+ end
87
+ end
88
+ 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
+ # Between comparison of range.
12
+ class Comparison::Between < Comparison
13
+ def to_sql
14
+ ["BETWEEN ? AND ?", v.first, v.exclude_end? ? v.end - 1 : v.end]
15
+ end
16
+
17
+ def inverse
18
+ Comparison::Outside.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
+ # Equality comparison of value.
12
+ class Comparison::Equal < Comparison
13
+ def to_sql
14
+ ["= ?", 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_sql
14
+ ["> ?", 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_sql
14
+ [">= ?", 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_sql
14
+ ["IN (#{v.map{'?'}.join(', ')})", *v]
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_sql
14
+ ["< ?", 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_sql
14
+ ["<= ?", 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_sql
18
+ v.inverse.to_sql
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_sql
14
+ ["!= ?", 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_sql
14
+ ["NOT IN (#{v.map{'?'}.join(', ')})", *v]
15
+ end
16
+
17
+ def inverse
18
+ Comparison::In.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
+ # Outside comparison of range.
12
+ class Comparison::Outside < Comparison
13
+ def to_sql
14
+ ["NOT BETWEEN ? AND ?", v.first, v.exclude_end? ? v.end - 1 : v.end]
15
+ end
16
+
17
+ def inverse
18
+ Comparison::Between.new(v)
19
+ end
20
+ end
21
+ 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