smql 0.0.0
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.
- data/AUTHORS +1 -0
- data/LICENSE +674 -0
- data/README.md +27 -0
- data/TODO +1 -0
- data/VERSION +1 -0
- data/lib/smql.rb +7 -0
- data/lib/smql_to_ar/condition_types.rb +327 -0
- data/lib/smql_to_ar/query_builder.rb +160 -0
- data/lib/smql_to_ar.rb +213 -0
- metadata +113 -0
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
|
+
|