waxx 0.1.2
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.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data/LICENSE +201 -0
- data/README.md +879 -0
- data/bin/waxx +120 -0
- data/lib/waxx/app.rb +173 -0
- data/lib/waxx/conf.rb +54 -0
- data/lib/waxx/console.rb +204 -0
- data/lib/waxx/csrf.rb +14 -0
- data/lib/waxx/database.rb +80 -0
- data/lib/waxx/encrypt.rb +38 -0
- data/lib/waxx/error.rb +60 -0
- data/lib/waxx/html.rb +33 -0
- data/lib/waxx/http.rb +268 -0
- data/lib/waxx/init.rb +273 -0
- data/lib/waxx/irb.rb +44 -0
- data/lib/waxx/irb_env.rb +18 -0
- data/lib/waxx/json.rb +23 -0
- data/lib/waxx/mongodb.rb +221 -0
- data/lib/waxx/mysql2.rb +234 -0
- data/lib/waxx/object.rb +115 -0
- data/lib/waxx/patch.rb +138 -0
- data/lib/waxx/pdf.rb +69 -0
- data/lib/waxx/pg.rb +246 -0
- data/lib/waxx/process.rb +270 -0
- data/lib/waxx/req.rb +116 -0
- data/lib/waxx/res.rb +98 -0
- data/lib/waxx/server.rb +304 -0
- data/lib/waxx/sqlite3.rb +237 -0
- data/lib/waxx/supervisor.rb +47 -0
- data/lib/waxx/test.rb +162 -0
- data/lib/waxx/util.rb +57 -0
- data/lib/waxx/version.rb +3 -0
- data/lib/waxx/view.rb +389 -0
- data/lib/waxx/waxx.rb +73 -0
- data/lib/waxx/x.rb +103 -0
- data/lib/waxx.rb +50 -0
- data/skel/README.md +11 -0
- data/skel/app/app/app.rb +39 -0
- data/skel/app/app/error/app_error.rb +16 -0
- data/skel/app/app/error/dhtml.rb +9 -0
- data/skel/app/app/error/html.rb +8 -0
- data/skel/app/app/error/json.rb +8 -0
- data/skel/app/app/error/pdf.rb +13 -0
- data/skel/app/app/log/app_log.rb +13 -0
- data/skel/app/app.rb +20 -0
- data/skel/app/home/home.rb +16 -0
- data/skel/app/home/html.rb +145 -0
- data/skel/app/html.rb +192 -0
- data/skel/app/usr/email.rb +66 -0
- data/skel/app/usr/html.rb +115 -0
- data/skel/app/usr/list.rb +51 -0
- data/skel/app/usr/password.rb +54 -0
- data/skel/app/usr/record.rb +98 -0
- data/skel/app/usr/usr.js +67 -0
- data/skel/app/usr/usr.rb +277 -0
- data/skel/app/waxx/waxx.rb +109 -0
- data/skel/bin/README.md +1 -0
- data/skel/db/README.md +11 -0
- data/skel/db/app/0-init.sql +88 -0
- data/skel/lib/README.md +1 -0
- data/skel/log/README.md +1 -0
- data/skel/opt/dev/config.yaml +1 -0
- data/skel/opt/prod/config.yaml +1 -0
- data/skel/opt/stage/config.yaml +1 -0
- data/skel/opt/test/config.yaml +1 -0
- data/skel/private/README.md +1 -0
- data/skel/public/lib/site.css +202 -0
- data/skel/public/lib/waxx/w.ico +0 -0
- data/skel/public/lib/waxx/w.png +0 -0
- data/skel/public/lib/waxx/waxx.js +111 -0
- data/skel/tmp/pids/README.md +1 -0
- data.tar.gz.sig +0 -0
- metadata +140 -0
- metadata.gz.sig +3 -0
data/lib/waxx/json.rb
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Waxx Copyright (c) 2016 ePark labs Inc. & Daniel J. Fitzpatrick <dan@eparklabs.com> All rights reserved.
|
|
2
|
+
# Released under the Apache Version 2 License. See LICENSE.txt.
|
|
3
|
+
|
|
4
|
+
module Waxx::Json
|
|
5
|
+
extend self
|
|
6
|
+
def get(x, d, message:{})
|
|
7
|
+
if PG::Result === d
|
|
8
|
+
x << d.map{|r| r}.to_json
|
|
9
|
+
else
|
|
10
|
+
x << d.to_json
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
alias :post :get
|
|
14
|
+
alias :put :get
|
|
15
|
+
alias :patch :get
|
|
16
|
+
def delete(x, message:{})
|
|
17
|
+
x << {ok: true, type: message[:type], message: message[:message]}.to_json
|
|
18
|
+
end
|
|
19
|
+
def not_found(x, data:{}, message:{})
|
|
20
|
+
x.res.status = 404
|
|
21
|
+
x << {ok: false, type: message[:type], message: message[:message]}.to_json
|
|
22
|
+
end
|
|
23
|
+
end
|
data/lib/waxx/mongodb.rb
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
# Waxx Copyright (c) 2016 ePark labs Inc. & Daniel J. Fitzpatrick <dan@eparklabs.com> All rights reserved.
|
|
2
|
+
# Released under the Apache Version 2 License. See LICENSE.txt.
|
|
3
|
+
|
|
4
|
+
module Waxx::Mongodb
|
|
5
|
+
|
|
6
|
+
attr :db
|
|
7
|
+
attr :table
|
|
8
|
+
attr :columns
|
|
9
|
+
attr :pkey
|
|
10
|
+
attr :joins
|
|
11
|
+
attr :orders
|
|
12
|
+
|
|
13
|
+
def init(db:"app", table:nil, pk:"id", cols:nil)
|
|
14
|
+
@db = db.to_sym
|
|
15
|
+
@table = (table || App.table_from_class(name)).to_sym
|
|
16
|
+
@pkey = pk.to_sym
|
|
17
|
+
@columns = {}
|
|
18
|
+
@joins = {}
|
|
19
|
+
@orders = {}
|
|
20
|
+
has(cols) if cols
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def has(opts=nil)
|
|
24
|
+
init if @table.nil?
|
|
25
|
+
return @columns if opts.nil?
|
|
26
|
+
@columns = opts
|
|
27
|
+
@columns.each{|n,v|
|
|
28
|
+
v[:table] = @table
|
|
29
|
+
v[:column] = n
|
|
30
|
+
v[:views] = []
|
|
31
|
+
v[:label] ||= Waxx::Util.label(n)
|
|
32
|
+
@orders[n] = v[:order] || n
|
|
33
|
+
@orders["_#{n}".to_sym] = v[:_order] || "#{n} DESC"
|
|
34
|
+
@pkey = n if v[:pkey]
|
|
35
|
+
if v[:is]
|
|
36
|
+
r, tc = v[:is].split(":")
|
|
37
|
+
t, c = tc.split(".")
|
|
38
|
+
@joins[r] = {join: "INNER", table: t, col: c}
|
|
39
|
+
end
|
|
40
|
+
if v[:has]
|
|
41
|
+
r, tc = v[:has].split(":")
|
|
42
|
+
t, c = tc.split(".")
|
|
43
|
+
@joins[r] = {join: "LEFT", table: t, col: c}
|
|
44
|
+
end
|
|
45
|
+
}
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def [](n)
|
|
49
|
+
@columns[n.to_sym]
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def /(n)
|
|
53
|
+
@columns[n.to_sym]
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def get_cols(*args)
|
|
57
|
+
re = {}
|
|
58
|
+
args.flatten.map{|a| re[a] = @columns[a.to_sym]}
|
|
59
|
+
re
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def runs(opts=nil)
|
|
63
|
+
init if @table.nil?
|
|
64
|
+
return App[@table] if opts.nil?
|
|
65
|
+
App[@table] = opts
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def run(x, act, meth, *args)
|
|
69
|
+
App[@table][act.to_sym][meth.to_sym][x, *args]
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def render(x, meth, *args)
|
|
73
|
+
const_get(x.ext.capitalize).send(meth, x, *args)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def parse_select(select, view)
|
|
77
|
+
raise "Can not define both select and view in Waxx::Object.parse_select (#{name})." if select and view
|
|
78
|
+
return select || "*" if view.nil?
|
|
79
|
+
view.columns.map{|n,c|
|
|
80
|
+
raise "Column #{n} not defined in #{view}" if c.nil?
|
|
81
|
+
if c[:sql_select]
|
|
82
|
+
"#{c[:sql_select]} AS #{n}"
|
|
83
|
+
elsif n != c[:column]
|
|
84
|
+
"#{c[:table]}.#{c[:column]} AS #{n}"
|
|
85
|
+
else
|
|
86
|
+
"#{c[:table]}.#{c[:column]}"
|
|
87
|
+
end
|
|
88
|
+
}.join(", ")
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def get(x, select:nil, id:nil, joins:nil, where:nil, having:nil, order:nil, limit:nil, offset:nil, view:nil, &blk)
|
|
92
|
+
Waxx.debug "object.get"
|
|
93
|
+
select = parse_select(select, view)
|
|
94
|
+
where = ["#{@table}.#{@pkey} = $1",id] if id and where.nil?
|
|
95
|
+
# Block SQL injection in order clause. All order options must be defined in @orders.
|
|
96
|
+
if order
|
|
97
|
+
if not @orders/order
|
|
98
|
+
Waxx.debug("ERROR: Object.get order (#{order}) not found in @orders [#{@orders.keys.join(", ")}]. Sorting by #{@pkey} instead.")
|
|
99
|
+
order = @pkey
|
|
100
|
+
else
|
|
101
|
+
order = @orders/order
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
if joins.nil? and view
|
|
105
|
+
joins = view.joins_to_sql
|
|
106
|
+
end
|
|
107
|
+
q = {select:select, joins:joins, where:where, having:having, order:order, limit:limit, offset:offset}
|
|
108
|
+
yield q if block_given?
|
|
109
|
+
Waxx.debug "object.get.select: #{q[:select]}"
|
|
110
|
+
return [] if q[:select].empty?
|
|
111
|
+
sql = []
|
|
112
|
+
sql << "SELECT #{q[:select] || "*"}"
|
|
113
|
+
sql << "FROM #{@table} #{q[:joins]}"
|
|
114
|
+
sql << "WHERE #{q[:where][0]}" if q[:where]
|
|
115
|
+
sql << "HAVING #{q[:having[0]]}" if q[:having]
|
|
116
|
+
sql << "ORDER BY #{q[:order]}" if q[:order]
|
|
117
|
+
sql << "LIMIT #{q[:limit].to_i}" if q[:limit]
|
|
118
|
+
sql << "OFFSET #{q[:offset].to_i}" if q[:offset]
|
|
119
|
+
vals = []
|
|
120
|
+
vals << q[:where][1] if q[:where] and q[:where][1]
|
|
121
|
+
vals << q[:having][1] if q[:having] and q[:having][1]
|
|
122
|
+
#[sql.join(" "), vals.flatten]
|
|
123
|
+
Waxx.debug sql
|
|
124
|
+
Waxx.debug vals.join(", ")
|
|
125
|
+
x.db[@db].exec(sql.join(" "), vals.flatten)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def get_by_id(x, id, select=nil, view:nil)
|
|
129
|
+
get(x, id: id, select: select, view: view).first
|
|
130
|
+
end
|
|
131
|
+
alias by_id get_by_id
|
|
132
|
+
|
|
133
|
+
def post(x, data, cols:nil, returning:nil, view:nil, &blk)
|
|
134
|
+
if view
|
|
135
|
+
cols = view.columns.select{|n,c| c[:table] == @table}
|
|
136
|
+
else
|
|
137
|
+
cols ||= @columns
|
|
138
|
+
end
|
|
139
|
+
data = blk.call if block_given?
|
|
140
|
+
sql = "INSERT INTO #{@table} ("
|
|
141
|
+
names = []
|
|
142
|
+
vars = []
|
|
143
|
+
vals = []
|
|
144
|
+
ret = []
|
|
145
|
+
i = 1
|
|
146
|
+
cols.each{|n,v|
|
|
147
|
+
if data/n
|
|
148
|
+
names << n.to_s
|
|
149
|
+
vars << "$#{i}"
|
|
150
|
+
vals << cast(v, data/n)
|
|
151
|
+
i += 1
|
|
152
|
+
end
|
|
153
|
+
ret << n.to_s
|
|
154
|
+
}
|
|
155
|
+
sql << names.join(",")
|
|
156
|
+
sql << ") VALUES (#{vars.join(",")})"
|
|
157
|
+
sql << " RETURNING #{returning || ret.join(",")}"
|
|
158
|
+
Waxx.debug(sql)
|
|
159
|
+
Waxx.debug(vals)
|
|
160
|
+
x.db[@db].exec(sql, vals).first
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def put(x, id, data, cols:nil, returning:nil, view:nil, where:nil, &blk)
|
|
164
|
+
if view
|
|
165
|
+
cols = view.columns.select{|n,c| c[:table] == @table}
|
|
166
|
+
else
|
|
167
|
+
cols ||= @columns
|
|
168
|
+
end
|
|
169
|
+
data = blk.call if block_given?
|
|
170
|
+
sql = "UPDATE #{@table} SET "
|
|
171
|
+
set = []
|
|
172
|
+
vals = []
|
|
173
|
+
ret = []
|
|
174
|
+
i = 1
|
|
175
|
+
Waxx.debug "data: #{data}"
|
|
176
|
+
cols.each{|n,v|
|
|
177
|
+
Waxx.debug "col: #{n}: #{v.inspect}"
|
|
178
|
+
if data.has_key? n.to_s or data.has_key? n.to_sym
|
|
179
|
+
set << "#{n} = $#{i}"
|
|
180
|
+
vals << cast(v, data/n)
|
|
181
|
+
ret << n.to_s
|
|
182
|
+
i += 1
|
|
183
|
+
end
|
|
184
|
+
}
|
|
185
|
+
sql << set.join(",")
|
|
186
|
+
sql << " WHERE #{@pkey} = $#{i} #{where} RETURNING #{returning || ret.join(",")}"
|
|
187
|
+
vals << id
|
|
188
|
+
Waxx.debug(sql)
|
|
189
|
+
Waxx.debug(vals)
|
|
190
|
+
x.db[@db].exec(sql, vals).first
|
|
191
|
+
end
|
|
192
|
+
alias patch put
|
|
193
|
+
|
|
194
|
+
def put_post(x, id, data, cols:nil, returning:nil, view: nil)
|
|
195
|
+
q = nil
|
|
196
|
+
q = get_by_id(x, id, @pkey) if id.to_i > 0
|
|
197
|
+
return post(x, data, cols: cols, returning: returning, view: view) if q.nil?
|
|
198
|
+
put(x, id, data, cols: cols, returning: returning, view: view)
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def cast(col, val)
|
|
202
|
+
case col[:type].to_sym
|
|
203
|
+
when :int
|
|
204
|
+
val.to_s.empty? ? nil : val.to_i
|
|
205
|
+
when :float, :numeric
|
|
206
|
+
val.to_s.empty? ? nil : val.to_f
|
|
207
|
+
else
|
|
208
|
+
val
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def delete(x, id)
|
|
213
|
+
x.db[@db].exec("DELETE FROM #{@table} WHERE #{@pkey} = $1", [id])
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def order(req_order, default_order='')
|
|
217
|
+
return default_order if req_order.nil?
|
|
218
|
+
return orders[req_order.to_sym] if orders.has_key? req_order.to_sym
|
|
219
|
+
@pkey
|
|
220
|
+
end
|
|
221
|
+
end
|
data/lib/waxx/mysql2.rb
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# Waxx Copyright (c) 2016 ePark labs Inc. & Daniel J. Fitzpatrick <dan@eparklabs.com> All rights reserved.
|
|
2
|
+
# Released under the Apache Version 2 License. See LICENSE.txt.
|
|
3
|
+
|
|
4
|
+
##
|
|
5
|
+
# The MySQL Object methods
|
|
6
|
+
module Waxx::Mysql2
|
|
7
|
+
extend self
|
|
8
|
+
|
|
9
|
+
attr :app
|
|
10
|
+
attr :db
|
|
11
|
+
attr :table
|
|
12
|
+
attr :columns
|
|
13
|
+
attr :pkey
|
|
14
|
+
attr :joins
|
|
15
|
+
attr :orders
|
|
16
|
+
|
|
17
|
+
##
|
|
18
|
+
# Connect to a MySQL/MariaDB database
|
|
19
|
+
#
|
|
20
|
+
# Set in config.yaml:
|
|
21
|
+
# databases:
|
|
22
|
+
# app: mysql2://user:pass@host:port/database?opt1=val1;opt2=val2
|
|
23
|
+
def connect(conf={})
|
|
24
|
+
Mysql2::Client.new( conf )
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def init(app:nil, db:"app", table:nil, pk:"id", cols:nil)
|
|
28
|
+
@app ||= (app || App.table_from_class(name)).to_sym
|
|
29
|
+
@db ||= db.to_sym
|
|
30
|
+
@table ||= (table || App.table_from_class(name)).to_sym
|
|
31
|
+
@pkey ||= pk.to_sym
|
|
32
|
+
@columns ||= {}
|
|
33
|
+
@joins ||= {}
|
|
34
|
+
@orders ||= {}
|
|
35
|
+
has(cols) if cols
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def has(opts=nil)
|
|
39
|
+
init if @table.nil?
|
|
40
|
+
return @columns if opts.nil?
|
|
41
|
+
@columns = opts
|
|
42
|
+
@columns.each{|n,v|
|
|
43
|
+
v[:table] = @table
|
|
44
|
+
v[:column] = n
|
|
45
|
+
v[:views] = []
|
|
46
|
+
v[:label] ||= Waxx::Util.label(n)
|
|
47
|
+
@orders[n] = v[:order] || n
|
|
48
|
+
@orders["_#{n}".to_sym] = v[:_order] || "#{n} DESC"
|
|
49
|
+
@pkey = n if v[:pkey]
|
|
50
|
+
if v[:is]
|
|
51
|
+
r, tc = v[:is].split(":")
|
|
52
|
+
t, c = tc.split(".")
|
|
53
|
+
@joins[r] = {join: "INNER", table: t, col: c}
|
|
54
|
+
end
|
|
55
|
+
if v[:has]
|
|
56
|
+
r, tc = v[:has].split(":")
|
|
57
|
+
t, c = tc.split(".")
|
|
58
|
+
@joins[r] = {join: "LEFT", table: t, col: c}
|
|
59
|
+
end
|
|
60
|
+
}
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def [](n)
|
|
64
|
+
@columns[n.to_sym]
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def /(n)
|
|
68
|
+
@columns[n.to_sym]
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def get_cols(*args)
|
|
72
|
+
re = {}
|
|
73
|
+
args.flatten.map{|a| re[a] = @columns[a.to_sym]}
|
|
74
|
+
re
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def runs(opts=nil)
|
|
78
|
+
init if @app.nil?
|
|
79
|
+
return App[@app] if opts.nil?
|
|
80
|
+
App[@app] = opts
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def run(x, act, meth, *args)
|
|
84
|
+
App[@app][act.to_sym][meth.to_sym][x, *args]
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def parse_select(select, view)
|
|
88
|
+
raise "Can not define both select and view in Waxx::Object.parse_select (#{name})." if select and view
|
|
89
|
+
return select || "*" if view.nil?
|
|
90
|
+
view.columns.map{|n,c|
|
|
91
|
+
raise "Column #{n} not defined in #{view}" if c.nil?
|
|
92
|
+
if c[:sql_select]
|
|
93
|
+
"#{c[:sql_select]} AS #{n}"
|
|
94
|
+
elsif n != c[:column]
|
|
95
|
+
"#{c[:table]}.#{c[:column]} AS #{n}"
|
|
96
|
+
else
|
|
97
|
+
"#{c[:table]}.#{c[:column]}"
|
|
98
|
+
end
|
|
99
|
+
}.join(", ")
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def get(x, select:nil, id:nil, joins:nil, where:nil, having:nil, order:nil, limit:nil, offset:nil, view:nil, &blk)
|
|
103
|
+
Waxx.debug "object.get"
|
|
104
|
+
select = parse_select(select, view)
|
|
105
|
+
where = ["#{@table}.#{@pkey} = ?",id] if id and where.nil?
|
|
106
|
+
# Block SQL injection in order clause. All order options must be defined in @orders.
|
|
107
|
+
if order
|
|
108
|
+
if not @orders/order
|
|
109
|
+
Waxx.debug("ERROR: Object.get order (#{order}) not found in @orders [#{@orders.keys.join(", ")}]. Sorting by #{@pkey} instead.")
|
|
110
|
+
order = @pkey
|
|
111
|
+
else
|
|
112
|
+
order = @orders/order
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
if joins.nil? and view
|
|
116
|
+
joins = view.joins_to_sql
|
|
117
|
+
end
|
|
118
|
+
q = {select:select, joins:joins, where:where, having:having, order:order, limit:limit, offset:offset}
|
|
119
|
+
yield q if block_given?
|
|
120
|
+
Waxx.debug "object.get.select: #{q[:select]}"
|
|
121
|
+
return [] if q[:select].empty?
|
|
122
|
+
sql = []
|
|
123
|
+
sql << "SELECT #{q[:select] || "*"}"
|
|
124
|
+
sql << "FROM #{@table} #{q[:joins]}"
|
|
125
|
+
sql << "WHERE #{q[:where][0]}" if q[:where]
|
|
126
|
+
sql << "HAVING #{q[:having[0]]}" if q[:having]
|
|
127
|
+
sql << "ORDER BY #{q[:order]}" if q[:order]
|
|
128
|
+
sql << "LIMIT #{q[:limit].to_i}" if q[:limit]
|
|
129
|
+
sql << "OFFSET #{q[:offset].to_i}" if q[:offset]
|
|
130
|
+
vals = []
|
|
131
|
+
vals << q[:where][1] if q[:where] and q[:where][1]
|
|
132
|
+
vals << q[:having][1] if q[:having] and q[:having][1]
|
|
133
|
+
#[sql.join(" "), vals.flatten]
|
|
134
|
+
Waxx.debug sql
|
|
135
|
+
Waxx.debug vals.join(", ")
|
|
136
|
+
x.db[@db].prepare(sql.join(" ")).execute(*(vals.flatten))
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def get_by_id(x, id, select=nil, view:nil)
|
|
140
|
+
get(x, id: id, select: select, view: view).first
|
|
141
|
+
end
|
|
142
|
+
alias by_id get_by_id
|
|
143
|
+
|
|
144
|
+
def post(x, data, cols:nil, returning:nil, view:nil, &blk)
|
|
145
|
+
if view
|
|
146
|
+
cols = view.columns.select{|n,c| c[:table] == @table}
|
|
147
|
+
else
|
|
148
|
+
cols ||= @columns
|
|
149
|
+
end
|
|
150
|
+
data = blk.call if block_given?
|
|
151
|
+
sql = "INSERT INTO #{@table} ("
|
|
152
|
+
names = []
|
|
153
|
+
vars = []
|
|
154
|
+
vals = []
|
|
155
|
+
ret = []
|
|
156
|
+
i = 1
|
|
157
|
+
cols.each{|n,v|
|
|
158
|
+
if data/n
|
|
159
|
+
names << n.to_s
|
|
160
|
+
vars << "?"
|
|
161
|
+
vals << cast(v, data/n)
|
|
162
|
+
i += 1
|
|
163
|
+
end
|
|
164
|
+
ret << n.to_s
|
|
165
|
+
}
|
|
166
|
+
sql << names.join(",")
|
|
167
|
+
sql << ") VALUES (#{vars.join(",")})"
|
|
168
|
+
Waxx.debug(sql)
|
|
169
|
+
Waxx.debug(vals)
|
|
170
|
+
x.db[@db].prepare(sql).execute(*vals)
|
|
171
|
+
id = x.db[@db].last_id
|
|
172
|
+
x.db[@db].prepare("SELECT #{returning || ret.join(",")} FROM #{@table} WHERE #{@pkey} = ?").execute(id).first
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def put(x, id, data, cols:nil, returning:nil, view:nil, where:nil, &blk)
|
|
176
|
+
if view
|
|
177
|
+
cols = view.columns.select{|n,c| c[:table] == @table}
|
|
178
|
+
else
|
|
179
|
+
cols ||= @columns
|
|
180
|
+
end
|
|
181
|
+
data = blk.call if block_given?
|
|
182
|
+
sql = "UPDATE #{@table} SET "
|
|
183
|
+
set = []
|
|
184
|
+
vals = []
|
|
185
|
+
ret = []
|
|
186
|
+
i = 1
|
|
187
|
+
Waxx.debug "data: #{data}"
|
|
188
|
+
cols.each{|n,v|
|
|
189
|
+
Waxx.debug "col: #{n}: #{v.inspect}"
|
|
190
|
+
if data.has_key? n.to_s or data.has_key? n.to_sym
|
|
191
|
+
set << "#{n} = ?"
|
|
192
|
+
vals << cast(v, data/n)
|
|
193
|
+
ret << n.to_s
|
|
194
|
+
i += 1
|
|
195
|
+
end
|
|
196
|
+
}
|
|
197
|
+
sql << set.join(",")
|
|
198
|
+
sql << " WHERE #{@pkey} = ? #{where}"
|
|
199
|
+
vals << id
|
|
200
|
+
Waxx.debug(sql)
|
|
201
|
+
Waxx.debug(vals)
|
|
202
|
+
x.db[@db].prepare(sql).execute(*vals)
|
|
203
|
+
x.db[@db].prepare("SELECT #{returning || ret.join(",")} FROM #{@table} WHERE #{@pkey} = ?").execute(id).first
|
|
204
|
+
end
|
|
205
|
+
alias patch put
|
|
206
|
+
|
|
207
|
+
def put_post(x, id, data, cols:nil, returning:nil, view: nil)
|
|
208
|
+
q = nil
|
|
209
|
+
q = get_by_id(x, id, @pkey) if id.to_i > 0
|
|
210
|
+
return post(x, data, cols: cols, returning: returning, view: view) if q.nil?
|
|
211
|
+
put(x, id, data, cols: cols, returning: returning, view: view)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def cast(col, val)
|
|
215
|
+
case col[:type].to_sym
|
|
216
|
+
when :int
|
|
217
|
+
val.to_s.empty? ? nil : val.to_i
|
|
218
|
+
when :float, :numeric
|
|
219
|
+
val.to_s.empty? ? nil : val.to_f
|
|
220
|
+
else
|
|
221
|
+
val
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def delete(x, id)
|
|
226
|
+
x.db[@db].query("DELETE FROM #{@table} WHERE #{@pkey} = $1", [id])
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
def order(req_order, default_order='')
|
|
230
|
+
return default_order if req_order.nil?
|
|
231
|
+
return orders[req_order.to_sym] if orders.has_key? req_order.to_sym
|
|
232
|
+
@pkey
|
|
233
|
+
end
|
|
234
|
+
end
|
data/lib/waxx/object.rb
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Waxx Copyright (c) 2016 ePark labs Inc. & Daniel J. Fitzpatrick <dan@eparklabs.com> All rights reserved.
|
|
2
|
+
# Released under the Apache Version 2 License. See LICENSE.txt.
|
|
3
|
+
|
|
4
|
+
module Waxx::Object
|
|
5
|
+
|
|
6
|
+
attr :app
|
|
7
|
+
|
|
8
|
+
##
|
|
9
|
+
# Define the app interface (routes), methods to run, and access control
|
|
10
|
+
#
|
|
11
|
+
# ```
|
|
12
|
+
# module App::Person
|
|
13
|
+
# extend Waxx::Object
|
|
14
|
+
#
|
|
15
|
+
# runs(
|
|
16
|
+
# default: 'list',
|
|
17
|
+
# list: {
|
|
18
|
+
# desc: "List people",
|
|
19
|
+
# acl: "user",
|
|
20
|
+
# get: -> (x) {
|
|
21
|
+
# x << x.db.app.exec("SELECT * FROM person ORDER BY last_name, first_name").map{|r| r}.to_json
|
|
22
|
+
# }
|
|
23
|
+
# }
|
|
24
|
+
# )
|
|
25
|
+
# end
|
|
26
|
+
# ```
|
|
27
|
+
#
|
|
28
|
+
# The special "default" key can be used to run a method when the act is not defined. In the example above, a request to `/person` will act like a request to `/person/list`
|
|
29
|
+
#
|
|
30
|
+
# Attributes of each argument to the runs method
|
|
31
|
+
#
|
|
32
|
+
# ```
|
|
33
|
+
# desc: A text description of the act. This is used in the documentation of your app
|
|
34
|
+
# acl: The access control list. See the ACL section below
|
|
35
|
+
# get: Handle GET requests
|
|
36
|
+
# put: Handle PUT requests
|
|
37
|
+
# post: Handle POST requests
|
|
38
|
+
# patch: Handle PATCH requests
|
|
39
|
+
# delete: Handle DELETE requests
|
|
40
|
+
# run: A generic handler for any request method (for example if you want all PUT, POST, PATCH, and DELETE requests to go to the same handler).
|
|
41
|
+
# ```
|
|
42
|
+
#
|
|
43
|
+
# ### ACL - Controlling access to your acts
|
|
44
|
+
#
|
|
45
|
+
# The ACL definition is very flexible. This means there are a lot of options.
|
|
46
|
+
#
|
|
47
|
+
# ```
|
|
48
|
+
# No acl parameter # The method is public
|
|
49
|
+
# acl: nil # The method is public
|
|
50
|
+
# acl: "*", "any", "public" # The method is public
|
|
51
|
+
# acl: "user" # Any logged-in user (anyone who logs in is in the group "user")
|
|
52
|
+
# acl: [:admin, :manager] # Anyone in the "admin" or "manager" group.
|
|
53
|
+
# acl: %w(admin manager) # Anyone in the "admin" or "manager" group.
|
|
54
|
+
# # A hash with request methods as keys. Includes the keys "read" for GET and HEAD and "write" for PUT, POST, PATCH, DELETE.
|
|
55
|
+
# acl: {
|
|
56
|
+
# get: "public", # Anyone can GET.
|
|
57
|
+
# write: "admin" # Only an admin can write
|
|
58
|
+
# }
|
|
59
|
+
# # A proc that return boolean (true = access granted, false = access denied)
|
|
60
|
+
# # The x variable is passed in.
|
|
61
|
+
# acl: -> (x) {
|
|
62
|
+
# x.req.env['X-Key'] == "Secret Key"
|
|
63
|
+
# }
|
|
64
|
+
# # Another example based on the client IP set by the proxy server
|
|
65
|
+
# acl: -> (x) {
|
|
66
|
+
# [x.req.env['X-Forwarded-For']].flatten.first == "10.20.40.80"
|
|
67
|
+
# }
|
|
68
|
+
# # Require a user to be in two groups
|
|
69
|
+
# acl: -> (x) {
|
|
70
|
+
# x.groups? :manager, :finance
|
|
71
|
+
# }
|
|
72
|
+
# ```
|
|
73
|
+
def runs(opts=nil)
|
|
74
|
+
@app ||= App.table_from_class(name).to_sym
|
|
75
|
+
return App[@app] if opts.nil?
|
|
76
|
+
App[@app] = opts
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
##
|
|
80
|
+
# Run a act in the current app.
|
|
81
|
+
#
|
|
82
|
+
# ```
|
|
83
|
+
# module App::Person
|
|
84
|
+
# extend Waxx::Object
|
|
85
|
+
#
|
|
86
|
+
# runs(
|
|
87
|
+
# default: 'list',
|
|
88
|
+
# list: {
|
|
89
|
+
# desc: "List people (/person/list.json)",
|
|
90
|
+
# acl: "user",
|
|
91
|
+
# get: -> (x) {
|
|
92
|
+
# x << x.db.app.exec("SELECT * FROM person ORDER BY last_name, first_name").map{|r| r}.to_json
|
|
93
|
+
# }
|
|
94
|
+
# },
|
|
95
|
+
# everyone: {
|
|
96
|
+
# desc: "List everyone (/person/everyone.json)",
|
|
97
|
+
# acl: "user",
|
|
98
|
+
# get: -> (x) {
|
|
99
|
+
# # Run a different act in the same app
|
|
100
|
+
# run(x, :list, :get)
|
|
101
|
+
# }
|
|
102
|
+
# }
|
|
103
|
+
# )
|
|
104
|
+
# end
|
|
105
|
+
# ```
|
|
106
|
+
def run(x, act, meth, *args)
|
|
107
|
+
App[@app][act.to_sym][meth.to_sym][x, *args]
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Shortcut to Waxx.debug
|
|
111
|
+
def debug(str, level=3)
|
|
112
|
+
Waxx.debug(str, level)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
end
|