flounder 0.14.0 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5cc0f113f0d254c49373affa1869e3f8fc03a3fb
4
- data.tar.gz: 8ff7ed39500492b2f965ff7e1d7c1acc2a7f2473
3
+ metadata.gz: 9f4ec6bd3fa4f14eccf7efa8d3aed4e81a3d8e08
4
+ data.tar.gz: cba009f5dc2b519b4636b643b7ac1d02bd9a493c
5
5
  SHA512:
6
- metadata.gz: a0e855f62812d513ae1ca5bfb0d04d0a313c5f9d0f7c42d076de31625a60b344dd32a05e8f9cfb674346e6db7c964ea157c0f2c50f91f5dce333226612191a23
7
- data.tar.gz: bc99c6125d8e890eb89f1db3ab1ad326e50f0a2d13950a4efed4089f4c209773e3d79dc2513862c33a82788d130c9484c60cc7b7a09832efd55a10a91c55b829
6
+ metadata.gz: 81a859be8701dc7aa497f17949ed8bb8db93cb22daaba9c24796d5d225ef4cfd936174f132648bde9755d67b4aa15c92db2c09e404fec28280e4db62d3fa302b
7
+ data.tar.gz: 85f24647fe87ddd7a788df1f0722811fd828d4e0c5c570c6ac295e40d9ef6d4e5fb3ead5526a20bf35566f2132638c7b355ba0e1291697e79c20f8c63a6d9c38
data/HISTORY CHANGED
@@ -1,4 +1,7 @@
1
1
 
2
+ # 0.15
3
+ + Condition piece generator - use this to create OR expressions: Entity#cond
4
+
2
5
  # 0.13
3
6
  + Expression generator (Domain#expr).
4
7
 
data/flounder.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "flounder"
5
- s.version = '0.14.0'
5
+ s.version = '0.15.0'
6
6
  s.summary = "Flounder is a way to write SQL simply in Ruby. It deals with everything BUT object relational mapping. "
7
7
  s.email = "kaspar.schiess@technologyastronauts.ch"
8
8
  s.homepage = "https://bitbucket.org/technologyastronauts/oss_flounder"
@@ -50,9 +50,12 @@ module Flounder
50
50
  end
51
51
 
52
52
  # Builds an SQL expression.
53
+ #
54
+ # domain.expr { concat('1', '2') }
53
55
  #
54
- def expr context=self, &block
55
- Expression::Builder.new(self, context).call(&block)
56
+ def expr &block
57
+ builder = Expression::Builder.new(self)
58
+ builder.call(&block)
56
59
  end
57
60
 
58
61
  # Returns an aggregate of all query wall clock times. Please see
@@ -66,6 +66,15 @@ module Flounder
66
66
  end
67
67
  alias to_s inspect
68
68
 
69
+ # Builds a condition part or a general SQL expression.
70
+ #
71
+ # entity.cond(a: 1)
72
+ #
73
+ def cond *conditions
74
+ builder = Expression::Builder.new(domain)
75
+ builder.interpret_conditions(self, conditions)
76
+ end
77
+
69
78
  # Starts a new select query and yields it to the block. Note that you don't
70
79
  # need to call this method to obtain a select query - any of the methods
71
80
  # on Query::Select should work on the entity and return a new query object.
@@ -11,6 +11,12 @@ module Flounder::Expression
11
11
  def cast type
12
12
  Cast.new(@domain, type, self)
13
13
  end
14
+ def | expr
15
+ BinaryOp.new(@domain, 'OR', self, expr)
16
+ end
17
+ def & expr
18
+ BinaryOp.new(@domain, 'AND', self, expr)
19
+ end
14
20
 
15
21
  def eval argument
16
22
  case argument
@@ -83,18 +89,70 @@ module Flounder::Expression
83
89
  end
84
90
  end
85
91
 
92
+ class ConditionBit < Expr
93
+ def initialize domain, engine, bit
94
+ super(domain)
95
+ @engine = engine
96
+ @bit = bit
97
+ end
98
+
99
+ attr_accessor :bit, :engine
100
+
101
+ def to_sql
102
+ bit.to_sql(engine)
103
+ end
104
+ end
105
+
106
+ class BinaryOp < Expr
107
+ def initialize domain, op_string, *terms
108
+ super(domain)
109
+
110
+ @op_string = op_string
111
+ @terms = terms
112
+ end
113
+
114
+ attr_accessor :op_string
115
+
116
+ def concat term
117
+ @terms << term
118
+ end
119
+
120
+ def to_sql
121
+ "(" +
122
+ @terms.
123
+ map { |t| eval(t) }.
124
+ join(" #{op_string} ") +
125
+ ")"
126
+ end
127
+ end
128
+
86
129
  class Builder
87
- def initialize domain, context
130
+ def initialize domain
88
131
  @domain = domain
89
- @context = context
90
132
  end
91
133
 
92
- attr_accessor :domain, :context
134
+ attr_accessor :domain
93
135
 
94
136
  def call &block
95
137
  instance_eval(&block)
96
138
  end
97
139
 
140
+ # Conditions are interpreted relative to an entity.
141
+ def interpret_conditions entity, conditions
142
+ # The method we need is in there...
143
+ query = Flounder::Query::Select.new(domain, entity)
144
+ engine = Flounder::Engine.new(domain.connection_pool)
145
+
146
+ and_expr = BinaryOp.new(domain, 'AND')
147
+
148
+ # TODO parse_conditions and its call tree is not really something that
149
+ # belongs into the query object - we should create a new abstraction here.
150
+ query.parse_conditions(*conditions) { |bit|
151
+ and_expr.concat(ConditionBit.new(domain, engine, bit)) }
152
+
153
+ and_expr
154
+ end
155
+
98
156
  def respond_to? sym, include_all=false
99
157
  true
100
158
  end
@@ -81,14 +81,6 @@ module Flounder::Query
81
81
  domain.log_bm measure
82
82
  end
83
83
 
84
- private
85
- # Prepares a kick - meaning an execution on the database or a transform
86
- # to an sql string. Ready Set...
87
- #
88
- def prepare_kick
89
- # should be overridden
90
- end
91
-
92
84
  # Parses a conditions array like it is found with #where and #having and
93
85
  # calls the block for each condition bit. Returns self.
94
86
  #
@@ -126,6 +118,14 @@ module Flounder::Query
126
118
  end
127
119
  return self
128
120
  end
121
+
122
+ private
123
+ # Prepares a kick - meaning an execution on the database or a transform
124
+ # to an sql string. Ready Set...
125
+ #
126
+ def prepare_kick
127
+ # should be overridden
128
+ end
129
129
 
130
130
  # Rewrites a statement that contains bind placeholders like '$1' to
131
131
  # contain placeholders starting at offset+1. Also checks that no
data/qed/expressions.md CHANGED
@@ -4,8 +4,14 @@
4
4
  Flounder also helps with the writing of complex SQL expressions.
5
5
 
6
6
  ~~~ruby
7
- users = domain[:users]
8
- domain.expr { a(b(c(1, ' ', users[:id]))) }.cast('int').as(:foo).
9
- assert generates_sql("a(b(c(1, ' ', \"users\".\"id\")))::int AS foo")
7
+ users = domain[:users]
8
+ domain.expr { a(b(c(1, ' ', users[:id]))) }.cast('int').as(:foo).
9
+ assert generates_sql("a(b(c(1, ' ', \"users\".\"id\")))::int AS foo")
10
10
  ~~~
11
11
 
12
+ You can also pass a condition-like hash to expr directly, it will return a Ruby object that allows for chaining.
13
+
14
+ ~~~ruby
15
+ (users.cond(:posts, a: 1) | users.cond(a: 2)).
16
+ assert generates_sql("((\"posts\".\"a\" = 1) OR (\"users\".\"a\" = 2))")
17
+ ~~~
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flounder
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.14.0
4
+ version: 0.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kaspar Schiess
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-10-02 00:00:00.000000000 Z
12
+ date: 2014-10-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: arel