smql 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/smql_to_ar.rb ADDED
@@ -0,0 +1,213 @@
1
+ # SmqlToAR - Base library: Converts SMQL to ActiveRecord
2
+ # Copyright (C) 2011 Denis Knauf
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+ class SmqlToAR
18
+ include ActiveSupport::Benchmarkable
19
+ ############################################################################r
20
+ # Exceptions
21
+
22
+ class SMQLError < Exception
23
+ attr_reader :data
24
+ def initialize data
25
+ @data = data
26
+ super data.inspect
27
+ end
28
+ end
29
+
30
+ # Ein Fehler ist in einem Subquery aufgetreten.
31
+ # Die eigentliche Exception wird in @data[:exception] hinterlegt.
32
+ class SubSMQLError < SMQLError
33
+ def initialize query, model, exception
34
+ ex = {:class => exception.class, :message => exception.message}
35
+ ex[:data] = exception.data if exception.respond_to? :data
36
+ super :query => query, :model => model.to_s, :exception => ex
37
+ set_backtrace exception.backtrace
38
+ end
39
+ end
40
+
41
+ class ParseError < SMQLError; end
42
+
43
+ # Malformed ColOp
44
+ class UnexpectedColOpError < ParseError
45
+ def initialize model, colop, val
46
+ super :got => colop, :val => val, :model => model.to_s
47
+ end
48
+ end
49
+
50
+ class UnexpectedError < ParseError
51
+ def initialize model, colop, val
52
+ super :got => {colop => val}, :model => model.to_s
53
+ end
54
+ end
55
+
56
+ class NonExistingSelectableError < SMQLError
57
+ def initialize got
58
+ super :got => got
59
+ end
60
+ end
61
+
62
+ class NonExistingColumnError < SMQLError
63
+ def initialize expected, got
64
+ super :expected => expected, :got => got
65
+ end
66
+ end
67
+
68
+ class NonExistingRelationError < SMQLError
69
+ def initialize expected, got
70
+ super :expected => expected, :got => got
71
+ end
72
+ end
73
+
74
+ class ProtectedColumnError < SMQLError
75
+ def initialize protected_column
76
+ super :protected_column => protected_column
77
+ end
78
+ end
79
+
80
+ class OnlyOrderOnBaseError < SMQLError
81
+ def initialize path
82
+ super :path => path
83
+ end
84
+ end
85
+
86
+ class BuilderError < Exception; end
87
+
88
+ #############################################################################
89
+
90
+ # Model der Relation `rel` von `model`
91
+ def self.model_of model, rel
92
+ model.reflections[ rel.to_sym].andand.klass
93
+ end
94
+
95
+ # Eine Spalte in einer Tabelle, relativ zu `Column#model`.
96
+ # Kann auch einen Pfad `Column#path` haben, wobei `Column#col` dann
97
+ # eine Relation von dem Model der letzten Relation von `Column#path` ist.
98
+ class Column
99
+ include Enumerable
100
+ attr_reader :path, :col
101
+ attr_accessor :model
102
+
103
+ def initialize model, *col
104
+ @model = model
105
+ @last_model = nil
106
+ *@path, @col = Array.wrap( col).collect {|s| s.to_s.split /[.\/]/ }.flatten.collect &:to_sym
107
+ end
108
+
109
+ def last_model
110
+ @last_model ||= each{}
111
+ end
112
+
113
+ def each
114
+ model = @model
115
+ @path.each do |rel|
116
+ model = SmqlToAR.model_of model, rel
117
+ return false unless model
118
+ yield rel, model
119
+ end
120
+ model
121
+ end
122
+
123
+ def exist_in?
124
+ model = last_model
125
+ return false unless model
126
+ model.column_names.include? @col.to_s
127
+ end
128
+
129
+ def protected?
130
+ model = @model
131
+ each do |rel, _model|
132
+ pr = Array.wrap model.respond_to?( :smql_protected) ? model.smql_protected : nil
133
+ pr.include? rel.to_s
134
+ model = _model
135
+ end
136
+ pr = Array.wrap model.respond_to?( :smql_protected) ? model.smql_protected : nil
137
+ pr.include? @col.to_s
138
+ end
139
+
140
+ def joins builder = nil, table = nil, &exe
141
+ pp = []
142
+ table = Array.wrap table
143
+ exe ||= builder ? lambda {|j, m| builder.join table+j, m} : Array.method( :[])
144
+ collect do |rel, model|
145
+ pp.push rel
146
+ exe.call pp, model
147
+ end
148
+ end
149
+ def to_a() @path+[@col] end
150
+ def to_s() to_a.join '.' end
151
+ def to_sym() to_s.to_sym end
152
+ def to_json() to_s end
153
+ def inspect() "#<Column: #{model} #{to_s}>" end
154
+ def relation() SmqlToAR.model_of last_model, @col end
155
+ def allowed?() ! self.protected? end
156
+ end
157
+
158
+ attr_reader :model, :query, :conditions, :builder, :order
159
+ attr_accessor :logger
160
+ @@logger = if Object.const_defined?( :Rails)
161
+ Rails.logger
162
+ else
163
+ require 'logger'
164
+ Logger.new $stdout
165
+ end
166
+
167
+ class <<self
168
+ def logger=(logger) @@logger = logger end
169
+ def logger() @@logger end
170
+ end
171
+
172
+ def initialize model, query, order = nil
173
+ query = JSON.parse query if query.kind_of? String
174
+ @model, @query, @logger, @order = model, query, @@logger, order
175
+ #p model: @model, query: @query
176
+ end
177
+
178
+ def parse
179
+ benchmark 'SMQL parse' do
180
+ @conditions = ConditionTypes.try_parse @model, @query
181
+ end
182
+ #p conditions: @conditions
183
+ self
184
+ end
185
+
186
+ def build
187
+ benchmark 'SMQL build query' do
188
+ @builder = QueryBuilder.new @model
189
+ table = @builder.base_table
190
+ @conditions.each {|condition| condition.build builder, table }
191
+ end
192
+ #p builder: @builder
193
+ self
194
+ end
195
+
196
+ def ar
197
+ @ar ||= benchmark 'SMQL ar' do
198
+ @builder.to_ar
199
+ end
200
+ end
201
+
202
+ def to_ar
203
+ benchmark 'SMQL' do
204
+ parse
205
+ build
206
+ ar.tap {|ar| logger.info ar.to_sql }
207
+ end
208
+ end
209
+
210
+ def self.to_ar *params
211
+ new( *params).to_ar
212
+ end
213
+ end
metadata ADDED
@@ -0,0 +1,113 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: smql
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 0
9
+ version: 0.0.0
10
+ platform: ruby
11
+ authors:
12
+ - Denis Knauf
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-09-08 00:00:00 +02:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: activerecord
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
30
+ version: "0"
31
+ type: :runtime
32
+ version_requirements: *id001
33
+ - !ruby/object:Gem::Dependency
34
+ name: activesupport
35
+ prerelease: false
36
+ requirement: &id002 !ruby/object:Gem::Requirement
37
+ none: false
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 0
43
+ version: "0"
44
+ type: :runtime
45
+ version_requirements: *id002
46
+ - !ruby/object:Gem::Dependency
47
+ name: json
48
+ prerelease: false
49
+ requirement: &id003 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ segments:
55
+ - 0
56
+ version: "0"
57
+ type: :runtime
58
+ version_requirements: *id003
59
+ description: SMQL is a JSON-based query langauage similar to MQL. This gem convertes these querys to ActiveRecord.
60
+ email:
61
+ - Denis.Knauf@gmail.com
62
+ executables: []
63
+
64
+ extensions: []
65
+
66
+ extra_rdoc_files:
67
+ - LICENSE
68
+ - README.md
69
+ - TODO
70
+ files:
71
+ - AUTHORS
72
+ - LICENSE
73
+ - README.md
74
+ - VERSION
75
+ - lib/smql.rb
76
+ - lib/smql_to_ar.rb
77
+ - lib/smql_to_ar/condition_types.rb
78
+ - lib/smql_to_ar/query_builder.rb
79
+ - TODO
80
+ has_rdoc: true
81
+ homepage: http://github.com/DenisKnauf/smql
82
+ licenses: []
83
+
84
+ post_install_message:
85
+ rdoc_options: []
86
+
87
+ require_paths:
88
+ - lib
89
+ required_ruby_version: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ segments:
95
+ - 0
96
+ version: "0"
97
+ required_rubygems_version: !ruby/object:Gem::Requirement
98
+ none: false
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ segments:
103
+ - 0
104
+ version: "0"
105
+ requirements: []
106
+
107
+ rubyforge_project:
108
+ rubygems_version: 1.3.7
109
+ signing_key:
110
+ specification_version: 3
111
+ summary: JSON-based query language "SMQL" to ActiveRecord converter
112
+ test_files: []
113
+