linkage 0.0.8 → 0.1.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.yardopts +1 -0
  4. data/Gemfile +1 -19
  5. data/Gemfile-java +3 -0
  6. data/README.markdown +88 -34
  7. data/Rakefile +16 -15
  8. data/TODO +4 -0
  9. data/lib/linkage/comparator.rb +139 -144
  10. data/lib/linkage/comparators/compare.rb +236 -29
  11. data/lib/linkage/comparators/strcompare.rb +85 -0
  12. data/lib/linkage/comparators/within.rb +24 -20
  13. data/lib/linkage/configuration.rb +44 -466
  14. data/lib/linkage/dataset.rb +28 -127
  15. data/lib/linkage/exceptions.rb +5 -0
  16. data/lib/linkage/field.rb +6 -37
  17. data/lib/linkage/field_set.rb +3 -3
  18. data/lib/linkage/match_recorder.rb +22 -0
  19. data/lib/linkage/match_set.rb +34 -0
  20. data/lib/linkage/match_sets/csv.rb +39 -0
  21. data/lib/linkage/match_sets/database.rb +45 -0
  22. data/lib/linkage/matcher.rb +30 -0
  23. data/lib/linkage/result_set.rb +25 -110
  24. data/lib/linkage/result_sets/csv.rb +54 -0
  25. data/lib/linkage/result_sets/database.rb +42 -0
  26. data/lib/linkage/runner.rb +57 -16
  27. data/lib/linkage/score_recorder.rb +30 -0
  28. data/lib/linkage/score_set.rb +49 -0
  29. data/lib/linkage/score_sets/csv.rb +64 -0
  30. data/lib/linkage/score_sets/database.rb +77 -0
  31. data/lib/linkage/version.rb +1 -1
  32. data/lib/linkage.rb +14 -17
  33. data/linkage.gemspec +13 -1
  34. data/linkage.gemspec-java +32 -0
  35. data/test/helper.rb +30 -23
  36. data/test/integration/test_cross_linkage.rb +46 -25
  37. data/test/integration/test_database_result_set.rb +55 -0
  38. data/test/integration/test_dual_linkage.rb +19 -94
  39. data/test/integration/test_self_linkage.rb +100 -203
  40. data/test/integration/test_within_comparator.rb +24 -77
  41. data/test/unit/comparators/test_compare.rb +254 -50
  42. data/test/unit/comparators/test_strcompare.rb +45 -0
  43. data/test/unit/comparators/test_within.rb +14 -26
  44. data/test/unit/match_sets/test_csv.rb +78 -0
  45. data/test/unit/match_sets/test_database.rb +63 -0
  46. data/test/unit/result_sets/test_csv.rb +111 -0
  47. data/test/unit/result_sets/test_database.rb +68 -0
  48. data/test/unit/score_sets/test_csv.rb +151 -0
  49. data/test/unit/score_sets/test_database.rb +149 -0
  50. data/test/unit/test_comparator.rb +46 -83
  51. data/test/unit/test_comparators.rb +4 -0
  52. data/test/unit/test_configuration.rb +99 -145
  53. data/test/unit/test_dataset.rb +52 -73
  54. data/test/unit/test_field.rb +4 -55
  55. data/test/unit/test_field_set.rb +6 -6
  56. data/test/unit/test_match_recorder.rb +23 -0
  57. data/test/unit/test_match_set.rb +23 -0
  58. data/test/unit/test_match_sets.rb +4 -0
  59. data/test/unit/test_matcher.rb +44 -0
  60. data/test/unit/test_result_set.rb +24 -223
  61. data/test/unit/test_result_sets.rb +4 -0
  62. data/test/unit/test_runner.rb +122 -17
  63. data/test/unit/test_runners.rb +4 -0
  64. data/test/unit/test_score_recorder.rb +25 -0
  65. data/test/unit/test_score_set.rb +37 -0
  66. data/test/unit/test_score_sets.rb +4 -0
  67. metadata +183 -90
  68. data/Gemfile.lock +0 -92
  69. data/lib/linkage/comparators/binary.rb +0 -12
  70. data/lib/linkage/data.rb +0 -175
  71. data/lib/linkage/decollation.rb +0 -93
  72. data/lib/linkage/expectation.rb +0 -21
  73. data/lib/linkage/expectations/exhaustive.rb +0 -63
  74. data/lib/linkage/expectations/simple.rb +0 -168
  75. data/lib/linkage/function.rb +0 -148
  76. data/lib/linkage/functions/binary.rb +0 -30
  77. data/lib/linkage/functions/cast.rb +0 -54
  78. data/lib/linkage/functions/length.rb +0 -29
  79. data/lib/linkage/functions/strftime.rb +0 -33
  80. data/lib/linkage/functions/trim.rb +0 -30
  81. data/lib/linkage/group.rb +0 -55
  82. data/lib/linkage/meta_object.rb +0 -139
  83. data/lib/linkage/runner/single_threaded.rb +0 -187
  84. data/lib/linkage/utils.rb +0 -164
  85. data/lib/linkage/warnings.rb +0 -5
  86. data/test/integration/test_collation.rb +0 -45
  87. data/test/integration/test_configuration.rb +0 -268
  88. data/test/integration/test_dataset.rb +0 -116
  89. data/test/integration/test_functions.rb +0 -88
  90. data/test/integration/test_result_set.rb +0 -85
  91. data/test/integration/test_scoring.rb +0 -84
  92. data/test/unit/expectations/test_exhaustive.rb +0 -111
  93. data/test/unit/expectations/test_simple.rb +0 -303
  94. data/test/unit/functions/test_binary.rb +0 -54
  95. data/test/unit/functions/test_cast.rb +0 -98
  96. data/test/unit/functions/test_length.rb +0 -52
  97. data/test/unit/functions/test_strftime.rb +0 -60
  98. data/test/unit/functions/test_trim.rb +0 -43
  99. data/test/unit/runner/test_single_threaded.rb +0 -12
  100. data/test/unit/test_data.rb +0 -445
  101. data/test/unit/test_decollation.rb +0 -201
  102. data/test/unit/test_function.rb +0 -233
  103. data/test/unit/test_group.rb +0 -38
  104. data/test/unit/test_meta_object.rb +0 -208
  105. data/test/unit/test_utils.rb +0 -341
@@ -1,93 +0,0 @@
1
- # encoding: utf-8
2
- module Linkage
3
- module Decollation
4
- def decollate(string, database_type, collation)
5
- case database_type
6
- when :mysql
7
- decollate_mysql(string, collation)
8
- else
9
- string
10
- end
11
- end
12
-
13
- def decollate_mysql(string, collation)
14
- case collation
15
- when "latin1_swedish_ci"
16
- decollate_mysql_latin1_swedish_ci(string)
17
- else
18
- string
19
- end
20
- end
21
-
22
- def decollate_mysql_latin1_swedish_ci(string)
23
- result = string.strip
24
- result.each_char.with_index do |char, i|
25
- case char
26
- when 'A', 'a', 'À', 'Á', 'Â', 'Ã', 'à', 'á', 'â', 'ã'
27
- result[i] = 'A'
28
- when 'B', 'b'
29
- result[i] = 'B'
30
- when 'C', 'c', 'Ç', 'ç'
31
- result[i] = 'C'
32
- when 'D', 'd', 'Ð', 'ð'
33
- result[i] = 'D'
34
- when 'E', 'e', 'È', 'É', 'Ê', 'Ë', 'è', 'é', 'ê', 'ë'
35
- result[i] = 'E'
36
- when 'F', 'f'
37
- result[i] = 'F'
38
- when 'G', 'g'
39
- result[i] = 'G'
40
- when 'H', 'h'
41
- result[i] = 'H'
42
- when 'I', 'i', 'Ì', 'Í', 'Î', 'Ï', 'ì', 'í', 'î', 'ï'
43
- result[i] = 'I'
44
- when 'J', 'j'
45
- result[i] = 'J'
46
- when 'K', 'k'
47
- result[i] = 'K'
48
- when 'L', 'l'
49
- result[i] = 'L'
50
- when 'M', 'm'
51
- result[i] = 'M'
52
- when 'N', 'n', 'Ñ', 'ñ'
53
- result[i] = 'N'
54
- when 'O', 'o', 'Ò', 'Ó', 'Ô', 'Õ', 'ò', 'ó', 'ô', 'õ'
55
- result[i] = 'O'
56
- when 'P', 'p'
57
- result[i] = 'P'
58
- when 'Q', 'q'
59
- result[i] = 'Q'
60
- when 'R', 'r'
61
- result[i] = 'R'
62
- when 'S', 's'
63
- result[i] = 'S'
64
- when 'T', 't'
65
- result[i] = 'T'
66
- when 'U', 'u', 'Ù', 'Ú', 'Û', 'ù', 'ú', 'û'
67
- result[i] = 'U'
68
- when 'V', 'v'
69
- result[i] = 'V'
70
- when 'W', 'w'
71
- result[i] = 'W'
72
- when 'X', 'x'
73
- result[i] = 'X'
74
- when 'Y', 'y', 'Ü', 'Ý', 'ü', 'ý'
75
- result[i] = 'Y'
76
- when 'Z', 'z'
77
- result[i] = 'Z'
78
- when '[', 'Å', 'å'
79
- result[i] = '['
80
- when '\\', 'Ä', 'Æ', 'ä', 'æ'
81
- result[i] = '\\'
82
- when ']', 'Ö', 'ö'
83
- result[i] = ']'
84
- when 'Ø', 'ø'
85
- result[i] = 'Ø'
86
- when 'Þ', 'þ'
87
- result[i] = 'Þ'
88
- end
89
- end
90
- result
91
- end
92
- end
93
- end
@@ -1,21 +0,0 @@
1
- module Linkage
2
- # The Expectation class contains information about how two datasets
3
- # should be linked.
4
- class Expectation
5
- def kind
6
- raise NotImplementedError
7
- end
8
-
9
- def apply_to(*args)
10
- raise NotImplementedError
11
- end
12
-
13
- def decollation_needed?
14
- false
15
- end
16
- end
17
- end
18
-
19
- Dir.glob(File.expand_path(File.join(File.dirname(__FILE__), "expectations", "*.rb"))).each do |filename|
20
- require filename
21
- end
@@ -1,63 +0,0 @@
1
- module Linkage
2
- module Expectations
3
- class Exhaustive < Expectation
4
- attr_reader :comparator, :threshold, :mode
5
-
6
- def initialize(comparator, threshold, mode)
7
- @comparator = comparator
8
- @threshold = threshold
9
- @mode = mode
10
- end
11
-
12
- def kind
13
- if @kind.nil?
14
- if @comparator.lhs_args.length != @comparator.rhs_args.length
15
- @kind = :cross
16
- else
17
- @kind = :self
18
- @comparator.lhs_args.each_with_index do |lhs_arg, index|
19
- rhs_arg = @comparator.rhs_args[index]
20
- if !lhs_arg.objects_equal?(rhs_arg)
21
- @kind = :cross
22
- break
23
- end
24
- end
25
- end
26
-
27
- # Check for dual-linkage.
28
- if @kind == :cross
29
- # Assume that all lhs arguments have the same dataset, as well
30
- # as all the rhs arguments. Only check the first argument of each
31
- # side.
32
- lhs_arg = @comparator.lhs_args[0]
33
- rhs_arg = @comparator.rhs_args[0]
34
- if !lhs_arg.datasets_equal?(rhs_arg)
35
- @kind = :dual
36
- end
37
- end
38
- end
39
- @kind
40
- end
41
-
42
- def apply_to(dataset, side)
43
- exprs =
44
- case side
45
- when :lhs
46
- comparator.lhs_args.collect { |arg| arg.to_expr.as(arg.name) }
47
- when :rhs
48
- comparator.rhs_args.collect { |arg| arg.to_expr.as(arg.name) }
49
- end
50
- dataset.select_more(*exprs)
51
- end
52
-
53
- def satisfied?(score)
54
- case mode
55
- when :equal
56
- score == threshold
57
- when :min
58
- score >= threshold
59
- end
60
- end
61
- end
62
- end
63
- end
@@ -1,168 +0,0 @@
1
- module Linkage
2
- module Expectations
3
- class Simple < Expectation
4
- # The dataset this expectation applies to: `:lhs` or `:rhs`. This
5
- # only applies to filter expectations.
6
- # @return [Symbol]
7
- attr_reader :side
8
-
9
- attr_reader :meta_object_1, :meta_object_2, :operator
10
-
11
- VALID_OPERATORS = [:==, :'!=', :>, :<, :>=, :<=]
12
-
13
- # Automatically create an expectation type depending on the arguments.
14
- #
15
- # @param [Linkage::MetaObject] meta_object_1
16
- # @param [Linkage::MetaObject] meta_object_2
17
- # @param [Symbol] operator Valid operators: `:==`, `:'!='`, `:>`, `:<`, `:>=`, `:<=`
18
- def self.create(meta_object_1, meta_object_2, operator)
19
- klass =
20
- if meta_object_1.static? && meta_object_2.static?
21
- raise ArgumentError, "An expectation with two static objects is invalid"
22
- elsif meta_object_1.static? || meta_object_2.static?
23
- Filter
24
- elsif meta_object_1.side == meta_object_2.side
25
- if !meta_object_1.datasets_equal?(meta_object_2)
26
- raise ArgumentError, "An expectation with two dynamic objects with the same side but different datasets is invalid"
27
- end
28
- Filter
29
- elsif meta_object_1.objects_equal?(meta_object_2)
30
- Self
31
- elsif meta_object_1.datasets_equal?(meta_object_2)
32
- Cross
33
- else
34
- Dual
35
- end
36
-
37
- klass.new(meta_object_1, meta_object_2, operator)
38
- end
39
-
40
- # Creates a new Simple.
41
- #
42
- # @param [Linkage::MetaObject] meta_object_1
43
- # @param [Linkage::MetaObject] meta_object_2
44
- # @param [Symbol] operator Valid operators: `:==`, `:'!='`, `:>`, `:<`, `:>=`, `:<=`
45
- def initialize(meta_object_1, meta_object_2, operator)
46
- @meta_object_1 = meta_object_1
47
- @meta_object_2 = meta_object_2
48
- @operator = operator
49
-
50
- if !VALID_OPERATORS.include?(operator)
51
- raise ArgumentError, "Invalid operator: #{operator.inspect}"
52
- end
53
-
54
- after_initialize
55
- end
56
-
57
- def same_except_side?(other)
58
- other.is_a?(Simple) &&
59
- operator == other.operator &&
60
- meta_object_1.objects_equal?(other.meta_object_1) &&
61
- meta_object_2.objects_equal?(other.meta_object_2)
62
- end
63
-
64
- def exactly!
65
- function_1 = Function['binary'].new(@meta_object_1.object, :dataset => @meta_object_1.dataset)
66
- function_2 = Function['binary'].new(@meta_object_2.object, :dataset => @meta_object_2.dataset)
67
- @meta_object_1 = MetaObject.new(function_1, @meta_object_1.side)
68
- @meta_object_2 = MetaObject.new(function_2, @meta_object_2.side)
69
- end
70
-
71
- # Display any warnings about this expectation.
72
- def display_warnings
73
- end
74
-
75
- def decollation_needed?
76
- merged_field.ruby_type[:type] == String && (
77
- @meta_object_1.collation != @meta_object_2.collation ||
78
- @meta_object_1.database_type != @meta_object_2.database_type
79
- )
80
- end
81
-
82
- protected
83
-
84
- def after_initialize
85
- end
86
- end
87
-
88
- class Filter < Simple
89
- def kind; :filter; end
90
-
91
- def to_expr
92
- case @operator
93
- when :==, :'!='
94
- expr = { @meta_object_1.to_expr => @meta_object_2.to_expr }
95
- @operator == :== ? expr : ~expr
96
- else
97
- Sequel::SQL::BooleanExpression.new(@operator,
98
- @meta_object_1.to_identifier, @meta_object_2.to_identifier)
99
- end
100
- end
101
-
102
- def apply_to(dataset, side)
103
- if side != @side
104
- return dataset
105
- end
106
-
107
- dataset.filter(self.to_expr)
108
- end
109
-
110
- def decollation_needed?
111
- false
112
- end
113
-
114
- private
115
-
116
- def after_initialize
117
- super
118
- @side = @meta_object_1.static? ? @meta_object_2.side : @meta_object_1.side
119
- end
120
- end
121
-
122
- class Match < Simple
123
- def apply_to(dataset, side)
124
- target =
125
- if @meta_object_1.side == side
126
- @meta_object_1
127
- elsif @meta_object_2.side == side
128
- @meta_object_2
129
- else
130
- raise ArgumentError, "Invalid `side` argument: #{side}"
131
- end
132
-
133
- dataset.group_match_more({
134
- :meta_object => target,
135
- :alias => merged_field.name
136
- })
137
- end
138
-
139
- def merged_field
140
- @merged_field ||= @meta_object_1.merge(@meta_object_2)
141
- end
142
-
143
- def display_warnings
144
- object_1 = @meta_object_1.object
145
- object_2 = @meta_object_2.object
146
- if object_1.ruby_type[:type] == String && object_2.ruby_type[:type] == String
147
- if @meta_object_1.dataset.database_type != @meta_object_2.dataset.database_type
148
- warn "NOTE: You are comparing two string fields (#{object_1.name} and #{object_2.name}) from different databases. This may result in unexpected results, as different databases compare strings differently. Consider using the =binary= function."
149
- elsif object_1.respond_to?(:collation) && object_1.respond_to?(:collation) && object_1.collation != object_2.collation
150
- warn "NOTE: The two string fields you are comparing (#{object_1.name} and #{object_2.name}) have different collations (#{ldata.collation} vs. #{rdata.collation}). This may result in unexpected results, as the database may compare them differently. Consider using the =exactly= method."
151
- end
152
- end
153
- end
154
- end
155
-
156
- class Self < Match
157
- def kind; :self; end
158
- end
159
-
160
- class Cross < Match
161
- def kind; :cross; end
162
- end
163
-
164
- class Dual < Match
165
- def kind; :dual; end
166
- end
167
- end
168
- end
@@ -1,148 +0,0 @@
1
- module Linkage
2
- # Abstract class to represent SQL functions. No attempts are made to
3
- # ensure that the function actually exists in the database you're using.
4
- #
5
- # @abstract
6
- class Function < Data
7
- # Register a new function.
8
- #
9
- # @param [Class] klass Function class (probably a subclass of {Function})
10
- def self.register(klass)
11
- if klass.instance_methods(false).any? { |m| m.to_s == "ruby_type" }
12
- @functions ||= {}
13
- @functions[klass.function_name] = klass
14
- else
15
- raise ArgumentError, "ruby_type instance method must be defined"
16
- end
17
- end
18
-
19
- def self.[](name)
20
- @functions ? @functions[name] : nil
21
- end
22
-
23
- # Subclasses must define this.
24
- def self.function_name
25
- raise NotImplementedError
26
- end
27
-
28
- # Subclasses can define this to require a specific number of arguments
29
- # of a certain class. To require two parameters of either String or
30
- # Integer, do something like this:
31
- #
32
- # @@parameters = [[String, Integer], [String, Integer]]
33
- # def self.parameters
34
- # @@parameters
35
- # end
36
- #
37
- def self.parameters
38
- nil
39
- end
40
-
41
- attr_reader :args
42
-
43
- # Creates a new Function object. If the arguments contain only
44
- # static objects, you should specify the dataset that this function
45
- # belongs to as the last argument like so:
46
- #
47
- # Function.new(foo, bar, :dataset => dataset)
48
- #
49
- # Optionally, you can use the `dataset=` setter to do it later. Many
50
- # functions require a dataset to work properly. If you try to use
51
- # such a function without setting a dataset, it will raise a RuntimeError.
52
- #
53
- # @param [Linkage::Data, Object] args Function arguments
54
- def initialize(*args)
55
- @names = [self.class.function_name]
56
- @args = args
57
- @options = args.last.is_a?(Hash) ? args.pop : {}
58
- process_args
59
- end
60
-
61
- def name
62
- @name ||= @names.join("_").to_sym
63
- end
64
-
65
- def dataset
66
- if @dataset.nil?
67
- raise RuntimeError, "You must specify a dataset for static functions"
68
- end
69
- @dataset
70
- end
71
-
72
- def dataset=(dataset)
73
- @dataset = dataset
74
- end
75
-
76
- def static?
77
- @static
78
- end
79
-
80
- def ==(other)
81
- equal?(other) || (other.is_a?(Function) && name == other.name && args == other.args && dataset == other.dataset)
82
- end
83
-
84
- # Subclasses must define this. The return value should be a Hash with
85
- # the following elements:
86
- # :type - column type (Ruby class) of the result
87
- # :opts - Optional hash with additional options (like :size)
88
- def ruby_type
89
- raise NotImplementedError
90
- end
91
-
92
- # Returns `nil` by default. Subclasses should redefine this if
93
- # there is a collation.
94
- def collation
95
- nil
96
- end
97
-
98
- # @return [Sequel::SQL::Function]
99
- def to_expr(options = {})
100
- self.class.function_name.to_sym.sql_function(*@values)
101
- end
102
-
103
- private
104
-
105
- def process_args
106
- parameters = self.class.parameters
107
- if parameters && parameters.length != @args.length
108
- raise ArgumentError, "wrong number of arguments (#{@args.length} for #{parameters.length})"
109
- end
110
-
111
- @static = true
112
- @values = []
113
- @args.each_with_index do |arg, i|
114
- if arg.kind_of?(Data)
115
- @names << arg.name
116
- @static &&= arg.static?
117
-
118
- # possibly set dataset
119
- if @dataset.nil?
120
- @dataset = arg.dataset
121
- elsif @dataset != arg.dataset
122
- raise ArgumentError, "Using dynamic data sources with different datasets is not permitted"
123
- end
124
-
125
- type = arg.ruby_type[:type]
126
- value = arg.to_expr
127
- else
128
- @names << arg.to_s.gsub(/\W/, "")
129
- type = arg.class
130
- value = arg
131
- end
132
- if parameters && parameters[i] != [:any] && !parameters[i].include?(type)
133
- raise TypeError, "expected type #{parameters[i].join(" or ")}, got #{type}"
134
- end
135
- @values << value
136
- end
137
-
138
- if @dataset.nil? && @options[:dataset]
139
- # Set dataset for static functions manually
140
- @dataset = @options[:dataset]
141
- end
142
- end
143
- end
144
- end
145
-
146
- Dir.glob(File.expand_path(File.join(File.dirname(__FILE__), "functions", "*.rb"))).each do |filename|
147
- require filename
148
- end
@@ -1,30 +0,0 @@
1
- module Linkage
2
- module Functions
3
- class Binary < Function
4
- def self.function_name
5
- "binary"
6
- end
7
-
8
- def self.parameters
9
- [[String]]
10
- end
11
-
12
- def ruby_type
13
- {:type => File}
14
- end
15
-
16
- def to_expr(options = {})
17
- expr =
18
- case dataset.database_type
19
- when :sqlite
20
- @values[0].cast(:blob)
21
- when :postgres
22
- @values[0].cast(:bytea)
23
- else
24
- @values[0].cast(:binary)
25
- end
26
- end
27
- end
28
- Function.register(Binary)
29
- end
30
- end
@@ -1,54 +0,0 @@
1
- module Linkage
2
- module Functions
3
- class Cast < Function
4
- def self.function_name
5
- "cast"
6
- end
7
-
8
- def self.parameters
9
- [[:any], [String]]
10
- end
11
-
12
- def ruby_type
13
- type =
14
- case @values[1]
15
- when 'integer'
16
- Fixnum
17
- when 'binary'
18
- File
19
- else
20
- raise "unknown type: #{@values[1]}"
21
- end
22
-
23
- {:type => type}
24
- end
25
-
26
- def to_expr(options = {})
27
- cast =
28
- case @values[1]
29
- when 'integer'
30
- case dataset.database_type
31
- when :sqlite, :postgres, :h2
32
- :integer
33
- when :mysql
34
- :signed
35
- end
36
- when 'binary'
37
- case dataset.database_type
38
- when :sqlite
39
- :blob
40
- when :postgres
41
- :bytea
42
- when :mysql, :h2
43
- :binary
44
- end
45
- end
46
-
47
- if cast
48
- @values[0].cast(cast)
49
- end
50
- end
51
- end
52
- Function.register(Cast)
53
- end
54
- end
@@ -1,29 +0,0 @@
1
- module Linkage
2
- module Functions
3
- # Returns the number of characters in a string.
4
- class Length < Function
5
- def self.function_name
6
- "length"
7
- end
8
-
9
- def self.parameters
10
- [[String]]
11
- end
12
-
13
- def ruby_type
14
- {:type => Fixnum}
15
- end
16
-
17
- def to_expr(options = {})
18
- expr =
19
- case dataset.database_type
20
- when :mysql, :postgres
21
- :char_length.sql_function(@values[0])
22
- else
23
- :length.sql_function(@values[0])
24
- end
25
- end
26
- end
27
- Function.register(Length)
28
- end
29
- end
@@ -1,33 +0,0 @@
1
- module Linkage
2
- module Functions
3
- class Strftime < Function
4
- def self.function_name
5
- "strftime"
6
- end
7
-
8
- def self.parameters
9
- [[Date, Time, DateTime], [String]]
10
- end
11
-
12
- def ruby_type
13
- # TODO: string length needed
14
- {:type => String}
15
- end
16
-
17
- def to_expr(options = {})
18
- expr =
19
- case dataset.database_type
20
- when :mysql
21
- :date_format.sql_function(*@values)
22
- when :sqlite
23
- :strftime.sql_function(@values[1], @values[0])
24
- when :postgres
25
- :to_char.sql_function(*@values)
26
- else
27
- :strftime.sql_function(@values[0], @values[1])
28
- end
29
- end
30
- end
31
- Function.register(Strftime)
32
- end
33
- end
@@ -1,30 +0,0 @@
1
- module Linkage
2
- module Functions
3
- class Trim < Function
4
- def self.function_name
5
- "trim"
6
- end
7
-
8
- def self.parameters
9
- [[String]]
10
- end
11
-
12
- def ruby_type
13
- if @args[0].kind_of?(Data)
14
- @args[0].ruby_type
15
- else
16
- {:type => String}
17
- end
18
- end
19
-
20
- def collation
21
- if @args[0].kind_of?(Data)
22
- @args[0].collation
23
- else
24
- super
25
- end
26
- end
27
- end
28
- Function.register(Trim)
29
- end
30
- end