rasti-db 2.1.0 → 2.3.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/lib/rasti/db.rb +11 -1
  3. data/lib/rasti/db/nql/filter_condition_strategies/base.rb +17 -0
  4. data/lib/rasti/db/nql/filter_condition_strategies/postgres.rb +21 -0
  5. data/lib/rasti/db/nql/filter_condition_strategies/sqlite.rb +21 -0
  6. data/lib/rasti/db/nql/filter_condition_strategies/types/generic.rb +49 -0
  7. data/lib/rasti/db/nql/filter_condition_strategies/types/pg_array.rb +32 -0
  8. data/lib/rasti/db/nql/filter_condition_strategies/types/sqlite_array.rb +34 -0
  9. data/lib/rasti/db/nql/filter_condition_strategies/unsupported_type_comparison.rb +22 -0
  10. data/lib/rasti/db/nql/nodes/array_content.rb +21 -0
  11. data/lib/rasti/db/nql/nodes/comparisons/base.rb +10 -0
  12. data/lib/rasti/db/nql/nodes/comparisons/equal.rb +0 -4
  13. data/lib/rasti/db/nql/nodes/comparisons/greater_than.rb +0 -4
  14. data/lib/rasti/db/nql/nodes/comparisons/greater_than_or_equal.rb +0 -4
  15. data/lib/rasti/db/nql/nodes/comparisons/include.rb +0 -4
  16. data/lib/rasti/db/nql/nodes/comparisons/less_than.rb +0 -4
  17. data/lib/rasti/db/nql/nodes/comparisons/less_than_or_equal.rb +0 -4
  18. data/lib/rasti/db/nql/nodes/comparisons/like.rb +0 -4
  19. data/lib/rasti/db/nql/nodes/comparisons/not_equal.rb +0 -4
  20. data/lib/rasti/db/nql/nodes/comparisons/not_include.rb +0 -4
  21. data/lib/rasti/db/nql/nodes/constants/array.rb +17 -0
  22. data/lib/rasti/db/nql/nodes/constants/base.rb +17 -0
  23. data/lib/rasti/db/nql/nodes/constants/false.rb +1 -1
  24. data/lib/rasti/db/nql/nodes/constants/float.rb +1 -1
  25. data/lib/rasti/db/nql/nodes/constants/integer.rb +1 -1
  26. data/lib/rasti/db/nql/nodes/constants/literal_string.rb +1 -1
  27. data/lib/rasti/db/nql/nodes/constants/string.rb +1 -1
  28. data/lib/rasti/db/nql/nodes/constants/time.rb +1 -1
  29. data/lib/rasti/db/nql/nodes/constants/true.rb +1 -1
  30. data/lib/rasti/db/nql/syntax.rb +229 -11
  31. data/lib/rasti/db/nql/syntax.treetop +24 -11
  32. data/lib/rasti/db/query.rb +11 -15
  33. data/lib/rasti/db/type_converters/postgres.rb +32 -36
  34. data/lib/rasti/db/type_converters/postgres_types/array.rb +11 -9
  35. data/lib/rasti/db/type_converters/postgres_types/hstore.rb +10 -9
  36. data/lib/rasti/db/type_converters/postgres_types/json.rb +17 -14
  37. data/lib/rasti/db/type_converters/postgres_types/jsonb.rb +17 -14
  38. data/lib/rasti/db/type_converters/sqlite.rb +62 -0
  39. data/lib/rasti/db/type_converters/sqlite_types/array.rb +34 -0
  40. data/lib/rasti/db/type_converters/time_in_zone.rb +1 -1
  41. data/lib/rasti/db/version.rb +1 -1
  42. data/rasti-db.gemspec +1 -0
  43. data/spec/collection_spec.rb +8 -0
  44. data/spec/minitest_helper.rb +4 -4
  45. data/spec/nql/filter_condition_spec.rb +19 -2
  46. data/spec/nql/filter_condition_strategies_spec.rb +112 -0
  47. data/spec/nql/syntax_parser_spec.rb +24 -0
  48. data/spec/query_spec.rb +95 -6
  49. data/spec/type_converters/sqlite_spec.rb +66 -0
  50. data/spec/type_converters/time_in_zone_spec.rb +1 -1
  51. metadata +32 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3166fff22e51aca6cd07d0994d1bf6170438e0bc9aed41e90370a83920a0d9ff
4
- data.tar.gz: 73e64013ec42740653058f0d9ff6c37ee45de41be0312f2296e4926fb7bff5b4
3
+ metadata.gz: a474b505b3841cc49e0a11a185f6b0fcd7ca9bba8f070d2b8e64c7b34151cd6f
4
+ data.tar.gz: 83f9d514325d34f14f73f594d25e27b3975dd0e84c92737a361973c50416efea
5
5
  SHA512:
6
- metadata.gz: 55c6fc7f5b3ef1d904f252e6d54c595b5d4cb72f1fbdf67f3e577c9cc095bd838f0963f34f611f6b7069971f7ead1d96d7dd20864dbcfea8ed542c5a3008dfdc
7
- data.tar.gz: 3b6c0136ba9823832cf329b3efe78406e69ea92d6d90f89950652628de740ea675a8b7d7152e530838f269b9b32140fa7f80750bcc2b41af70c9efc2b275cd78
6
+ metadata.gz: 6065b85efcdc595cf0d33c3b9054fb7ffdb32caa0ff723b2147a2050f0bd1be65071452850b2b8fbd590e4ad26b83e16b6b145154597d603d4906b3bbdef2305
7
+ data.tar.gz: 7e58767bb989c315223d00a999fdcd9a56f408a2767950534c0c8c886a8b81d134570a1a0990223eaa125097f37d49dcc2389c52bd9b5118fa17c30130736f0d
data/lib/rasti/db.rb CHANGED
@@ -6,20 +6,25 @@ require 'treetop'
6
6
  require 'hierarchical_graph'
7
7
  require 'class_config'
8
8
  require 'hash_ext'
9
+ require 'inflecto'
9
10
  require 'multi_require'
10
11
 
11
12
  module Rasti
12
13
  module DB
13
-
14
+
14
15
  extend MultiRequire
15
16
  extend ClassConfig
16
17
 
17
18
  require_relative 'db/query'
18
19
  require_relative_pattern 'db/relations/*'
19
20
  require_relative_pattern 'db/type_converters/postgres_types/*'
21
+ require_relative_pattern 'db/type_converters/sqlite_types/*'
22
+ require_relative 'db/nql/nodes/constants/base'
23
+ require_relative_pattern 'db/nql/filter_condition_strategies/types/*'
20
24
  require_relative_pattern 'db/**/*'
21
25
 
22
26
  attr_config :type_converters, []
27
+ attr_config :nql_filter_condition_strategy, nil
23
28
 
24
29
  def self.to_db(db, collection_name, attribute_name, value)
25
30
  type_converters.inject(value) do |result, type_converter|
@@ -33,5 +38,10 @@ module Rasti
33
38
  end
34
39
  end
35
40
 
41
+ def self.nql_filter_condition_for(comparison_name, identifier, argument)
42
+ raise 'Undefined Rasti::DB.nql_filter_condition_strategy' unless nql_filter_condition_strategy
43
+ nql_filter_condition_strategy.filter_condition_for comparison_name, identifier, argument
44
+ end
45
+
36
46
  end
37
47
  end
@@ -0,0 +1,17 @@
1
+ module Rasti
2
+ module DB
3
+ module NQL
4
+ module FilterConditionStrategies
5
+ class Base
6
+
7
+ def filter_condition_for(comparison_name, identifier, argument)
8
+ type = type_for argument
9
+ raise UnsupportedTypeComparison.new(type, comparison_name) unless type.respond_to?(comparison_name)
10
+ type.public_send comparison_name, identifier, argument.value
11
+ end
12
+
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,21 @@
1
+ module Rasti
2
+ module DB
3
+ module NQL
4
+ module FilterConditionStrategies
5
+ class Postgres < Base
6
+
7
+ PG_TYPES = {
8
+ array: Types::PGArray
9
+ }
10
+
11
+ private
12
+
13
+ def type_for(argument)
14
+ PG_TYPES.fetch(argument.type, Types::Generic)
15
+ end
16
+
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ module Rasti
2
+ module DB
3
+ module NQL
4
+ module FilterConditionStrategies
5
+ class SQLite < Base
6
+
7
+ SQLITE_TYPES = {
8
+ array: Types::SQLiteArray
9
+ }
10
+
11
+ private
12
+
13
+ def type_for(argument)
14
+ SQLITE_TYPES.fetch(argument.type, Types::Generic)
15
+ end
16
+
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,49 @@
1
+ module Rasti
2
+ module DB
3
+ module NQL
4
+ module FilterConditionStrategies
5
+ module Types
6
+ class Generic
7
+
8
+ def self.equal(identifier, value)
9
+ {identifier => value}
10
+ end
11
+
12
+ def self.not_equal(identifier, value)
13
+ Sequel.negate equal(identifier, value)
14
+ end
15
+
16
+ def self.greater_than(identifier, value)
17
+ identifier > value
18
+ end
19
+
20
+ def self.greater_than_or_equal(identifier, value)
21
+ identifier >= value
22
+ end
23
+
24
+ def self.less_than(identifier, value)
25
+ identifier < value
26
+ end
27
+
28
+ def self.less_than_or_equal(identifier, value)
29
+ identifier <= value
30
+ end
31
+
32
+ def self.like(identifier, value)
33
+ Sequel.ilike identifier, value
34
+ end
35
+
36
+ def self.include(identifier, value)
37
+ Sequel.ilike identifier, "%#{value}%"
38
+ end
39
+
40
+ def self.not_include(identifier, value)
41
+ ~include(identifier, value)
42
+ end
43
+
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,32 @@
1
+ module Rasti
2
+ module DB
3
+ module NQL
4
+ module FilterConditionStrategies
5
+ module Types
6
+ class PGArray
7
+
8
+ def self.equal(identifier, values)
9
+ Sequel.&(
10
+ Sequel.pg_array(identifier).contains(Sequel.pg_array(values)),
11
+ Sequel.pg_array(identifier).contained_by(Sequel.pg_array(values))
12
+ )
13
+ end
14
+
15
+ def self.not_equal(identifier, values)
16
+ ~equal(identifier, values)
17
+ end
18
+
19
+ def self.include(identifier, values)
20
+ Sequel.pg_array(identifier).overlaps Sequel.pg_array(values)
21
+ end
22
+
23
+ def self.not_include(identifier, values)
24
+ ~include(identifier, values)
25
+ end
26
+
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,34 @@
1
+ module Rasti
2
+ module DB
3
+ module NQL
4
+ module FilterConditionStrategies
5
+ module Types
6
+ class SQLiteArray
7
+
8
+ def self.equal(identifier, values)
9
+ array = values.map { |value| "\"#{value}\"" }.join(',')
10
+ {identifier => "[#{array}]"}
11
+ end
12
+
13
+ def self.not_equal(identifier, values)
14
+ Sequel.|(*values.map { |value| ~Sequel.like(identifier, "%\"#{value}\"%") })
15
+ end
16
+
17
+ def self.like(identifier, values)
18
+ Sequel.|(*values.map { |value| Sequel.like(identifier, "%#{value}%") })
19
+ end
20
+
21
+ def self.include(identifier, values)
22
+ Sequel.|(*values.map { |value| Sequel.like(identifier, "%\"#{value}\"%") })
23
+ end
24
+
25
+ def self.not_include(identifier, values)
26
+ Sequel.&(*values.map { |value| ~Sequel.like(identifier, "%\"#{value}\"%") })
27
+ end
28
+
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,22 @@
1
+ module Rasti
2
+ module DB
3
+ module NQL
4
+ module FilterConditionStrategies
5
+ class UnsupportedTypeComparison < StandardError
6
+
7
+ attr_reader :argument_type, :comparison_name
8
+
9
+ def initialize(argument_type, comparison_name)
10
+ @argument_type = argument_type
11
+ @comparison_name = comparison_name
12
+ end
13
+
14
+ def message
15
+ "Unsupported comparison #{comparison_name} for #{argument_type}"
16
+ end
17
+
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,21 @@
1
+ module Rasti
2
+ module DB
3
+ module NQL
4
+ module Nodes
5
+ class ArrayContent < Treetop::Runtime::SyntaxNode
6
+
7
+ def values
8
+ [left.value] + right_value
9
+ end
10
+
11
+ private
12
+
13
+ def right_value
14
+ right.is_a?(self.class) ? right.values : [right.value]
15
+ end
16
+
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -13,6 +13,16 @@ module Rasti
13
13
  attribute.computed_attributes(collection_class)
14
14
  end
15
15
 
16
+ def filter_condition(collection_class)
17
+ DB.nql_filter_condition_for comparison_name, attribute.identifier(collection_class), argument
18
+ end
19
+
20
+ private
21
+
22
+ def comparison_name
23
+ Inflecto.underscore(Inflecto.demodulize(self.class)).to_sym
24
+ end
25
+
16
26
  end
17
27
  end
18
28
  end
@@ -5,10 +5,6 @@ module Rasti
5
5
  module Comparisons
6
6
  class Equal < Base
7
7
 
8
- def filter_condition(collection_class)
9
- { attribute.identifier(collection_class) => argument.value }
10
- end
11
-
12
8
  end
13
9
  end
14
10
  end
@@ -5,10 +5,6 @@ module Rasti
5
5
  module Comparisons
6
6
  class GreaterThan < Base
7
7
 
8
- def filter_condition(collection_class)
9
- attribute.identifier(collection_class) > argument.value
10
- end
11
-
12
8
  end
13
9
  end
14
10
  end
@@ -5,10 +5,6 @@ module Rasti
5
5
  module Comparisons
6
6
  class GreaterThanOrEqual < Base
7
7
 
8
- def filter_condition(collection_class)
9
- attribute.identifier(collection_class) >= argument.value
10
- end
11
-
12
8
  end
13
9
  end
14
10
  end
@@ -5,10 +5,6 @@ module Rasti
5
5
  module Comparisons
6
6
  class Include < Base
7
7
 
8
- def filter_condition(collection_class)
9
- Sequel.ilike(attribute.identifier(collection_class), "%#{argument.value}%")
10
- end
11
-
12
8
  end
13
9
  end
14
10
  end
@@ -5,10 +5,6 @@ module Rasti
5
5
  module Comparisons
6
6
  class LessThan < Base
7
7
 
8
- def filter_condition(collection_class)
9
- attribute.identifier(collection_class) < argument.value
10
- end
11
-
12
8
  end
13
9
  end
14
10
  end
@@ -5,10 +5,6 @@ module Rasti
5
5
  module Comparisons
6
6
  class LessThanOrEqual < Base
7
7
 
8
- def filter_condition(collection_class)
9
- attribute.identifier(collection_class) <= argument.value
10
- end
11
-
12
8
  end
13
9
  end
14
10
  end
@@ -5,10 +5,6 @@ module Rasti
5
5
  module Comparisons
6
6
  class Like < Base
7
7
 
8
- def filter_condition(collection_class)
9
- Sequel.ilike(attribute.identifier(collection_class), argument.value)
10
- end
11
-
12
8
  end
13
9
  end
14
10
  end
@@ -5,10 +5,6 @@ module Rasti
5
5
  module Comparisons
6
6
  class NotEqual < Base
7
7
 
8
- def filter_condition(collection_class)
9
- Sequel.negate(attribute.identifier(collection_class) => argument.value)
10
- end
11
-
12
8
  end
13
9
  end
14
10
  end
@@ -5,10 +5,6 @@ module Rasti
5
5
  module Comparisons
6
6
  class NotInclude < Base
7
7
 
8
- def filter_condition(collection_class)
9
- ~ Sequel.ilike(attribute.identifier(collection_class), "%#{argument.value}%")
10
- end
11
-
12
8
  end
13
9
  end
14
10
  end
@@ -0,0 +1,17 @@
1
+ module Rasti
2
+ module DB
3
+ module NQL
4
+ module Nodes
5
+ module Constants
6
+ class Array < Base
7
+
8
+ def value
9
+ contents.is_a?(ArrayContent) ? contents.values : [contents.value]
10
+ end
11
+
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Rasti
2
+ module DB
3
+ module NQL
4
+ module Nodes
5
+ module Constants
6
+ class Base < Treetop::Runtime::SyntaxNode
7
+
8
+ def type
9
+ Inflecto.underscore(Inflecto.demodulize(self.class)).to_sym
10
+ end
11
+
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end