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.
Files changed (75) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data/LICENSE +201 -0
  4. data/README.md +879 -0
  5. data/bin/waxx +120 -0
  6. data/lib/waxx/app.rb +173 -0
  7. data/lib/waxx/conf.rb +54 -0
  8. data/lib/waxx/console.rb +204 -0
  9. data/lib/waxx/csrf.rb +14 -0
  10. data/lib/waxx/database.rb +80 -0
  11. data/lib/waxx/encrypt.rb +38 -0
  12. data/lib/waxx/error.rb +60 -0
  13. data/lib/waxx/html.rb +33 -0
  14. data/lib/waxx/http.rb +268 -0
  15. data/lib/waxx/init.rb +273 -0
  16. data/lib/waxx/irb.rb +44 -0
  17. data/lib/waxx/irb_env.rb +18 -0
  18. data/lib/waxx/json.rb +23 -0
  19. data/lib/waxx/mongodb.rb +221 -0
  20. data/lib/waxx/mysql2.rb +234 -0
  21. data/lib/waxx/object.rb +115 -0
  22. data/lib/waxx/patch.rb +138 -0
  23. data/lib/waxx/pdf.rb +69 -0
  24. data/lib/waxx/pg.rb +246 -0
  25. data/lib/waxx/process.rb +270 -0
  26. data/lib/waxx/req.rb +116 -0
  27. data/lib/waxx/res.rb +98 -0
  28. data/lib/waxx/server.rb +304 -0
  29. data/lib/waxx/sqlite3.rb +237 -0
  30. data/lib/waxx/supervisor.rb +47 -0
  31. data/lib/waxx/test.rb +162 -0
  32. data/lib/waxx/util.rb +57 -0
  33. data/lib/waxx/version.rb +3 -0
  34. data/lib/waxx/view.rb +389 -0
  35. data/lib/waxx/waxx.rb +73 -0
  36. data/lib/waxx/x.rb +103 -0
  37. data/lib/waxx.rb +50 -0
  38. data/skel/README.md +11 -0
  39. data/skel/app/app/app.rb +39 -0
  40. data/skel/app/app/error/app_error.rb +16 -0
  41. data/skel/app/app/error/dhtml.rb +9 -0
  42. data/skel/app/app/error/html.rb +8 -0
  43. data/skel/app/app/error/json.rb +8 -0
  44. data/skel/app/app/error/pdf.rb +13 -0
  45. data/skel/app/app/log/app_log.rb +13 -0
  46. data/skel/app/app.rb +20 -0
  47. data/skel/app/home/home.rb +16 -0
  48. data/skel/app/home/html.rb +145 -0
  49. data/skel/app/html.rb +192 -0
  50. data/skel/app/usr/email.rb +66 -0
  51. data/skel/app/usr/html.rb +115 -0
  52. data/skel/app/usr/list.rb +51 -0
  53. data/skel/app/usr/password.rb +54 -0
  54. data/skel/app/usr/record.rb +98 -0
  55. data/skel/app/usr/usr.js +67 -0
  56. data/skel/app/usr/usr.rb +277 -0
  57. data/skel/app/waxx/waxx.rb +109 -0
  58. data/skel/bin/README.md +1 -0
  59. data/skel/db/README.md +11 -0
  60. data/skel/db/app/0-init.sql +88 -0
  61. data/skel/lib/README.md +1 -0
  62. data/skel/log/README.md +1 -0
  63. data/skel/opt/dev/config.yaml +1 -0
  64. data/skel/opt/prod/config.yaml +1 -0
  65. data/skel/opt/stage/config.yaml +1 -0
  66. data/skel/opt/test/config.yaml +1 -0
  67. data/skel/private/README.md +1 -0
  68. data/skel/public/lib/site.css +202 -0
  69. data/skel/public/lib/waxx/w.ico +0 -0
  70. data/skel/public/lib/waxx/w.png +0 -0
  71. data/skel/public/lib/waxx/waxx.js +111 -0
  72. data/skel/tmp/pids/README.md +1 -0
  73. data.tar.gz.sig +0 -0
  74. metadata +140 -0
  75. metadata.gz.sig +3 -0
data/lib/waxx/test.rb ADDED
@@ -0,0 +1,162 @@
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 test framework for waxx
6
+ #
7
+ # ## Usage:
8
+ #
9
+ #
10
+ # ```
11
+ # module Waxx
12
+ # def test_waxx_app
13
+ # # Setup x vars for different situations
14
+ # Waxx::App.init
15
+ # x_guest = Waxx::Test.x_nonuser
16
+ # x_admin = Waxx::Test.x_user
17
+ # x_admin.usr['grp'] = ["admin"]
18
+ # handler = {
19
+ # test: {
20
+ # desc: "A test handler",
21
+ # get: -> (x, n){
22
+ # "get #{n}"
23
+ # }
24
+ # }
25
+ # }
26
+ #
27
+ # Waxx::Test.test(Waxx::App, # Module to test
28
+ #
29
+ # "access?" => { # Method to test.
30
+ # # Each item below is a "test-name": [result value,
31
+ # # expect: extepected-value,
32
+ # # run: Proc to run that returns true on success,
33
+ # # args: args to pass to the module method
34
+ # # ]
35
+ # "nil" => [Waxx::App.access?(x_guest), expect: true],
36
+ # "asterisk" => [Waxx::App.access?(x_guest, acl:"*"), expect: true],
37
+ # "all" => [Waxx::App.access?(x_guest, acl:"all"), expect: true],
38
+ # "any" => [Waxx::App.access?(x_guest, acl:"any"), expect: true],
39
+ # "user" => [Waxx::App.access?(x_guest, acl:"user"), expect: false],
40
+ # "non-user-admin" => [Waxx::App.access?(x_guest, acl:"admin"), expect: false],
41
+ # "non-user-array-of-admin-other" => [Waxx::App.access?(x_guest, acl:%w(admin other)), expect: false],
42
+ # "proc-true" => [Waxx::App.access?(x_guest, acl: ->(x){true}), expect: true],
43
+ # "proc-false" => [Waxx::App.access?(x_guest, acl: ->(x){false}), expect: false],
44
+ # "admin-admin" => [Waxx::App.access?(x_admin, acl:"admin"), expect: true],
45
+ # "admin-array-of-admin-other" => [Waxx::App.access?(x_admin, acl:%w(admin other)), expect: true],
46
+ # },
47
+ #
48
+ # "not_found" => {
49
+ # "message" => [Waxx::App.not_found(x_guest, message:"not found"), run: -> (x) {x.res == "not found"}, args: [x_guest]]
50
+ # },
51
+ #
52
+ # "runs" => {
53
+ # "with-opts" => [(Waxx::App.init; Waxx::App[:test_app_handler] = handler), expect: handler],
54
+ # "with-name" => [Waxx::App[:test_app_handler], expect: handler],
55
+ # "run" => [Waxx::App.run(x_guest, :test_app_handler, :test, :get, [1]), expect: "get 1"],
56
+ # }
57
+ #
58
+ # )
59
+ # end
60
+ # ```
61
+ module Waxx::Test
62
+ extend self
63
+
64
+ ##
65
+ # Setup and process a test on a module method
66
+ def test(module_name, methods={})
67
+ mod = module_name.to_s
68
+ re = {mod => {}}
69
+ methods.each{|meth, tests|
70
+ re[mod][meth] = {}
71
+ passed = 0
72
+ tests.each{|test_name, args|
73
+ begin
74
+ re[mod][meth][test_name] = run_test(*args)
75
+ passed += 1 if re[mod][meth][test_name]['status'] == 'pass'
76
+ rescue => test_error
77
+ re[mod][meth][test_name] = {
78
+ "status" => "fail",
79
+ "error" => {
80
+ "got" => "ERROR",
81
+ "message" => test_error.to_s,
82
+ "backtrace" => test_error.backtrace
83
+ }
84
+ }
85
+ end
86
+ }
87
+ re[mod][meth]['tests'] = tests.size
88
+ re[mod][meth]['tests_passed'] = passed
89
+ re[mod][meth]['test_performance'] = "#{((passed.to_f / tests.size) * 100).to_i}%"
90
+ }
91
+ re
92
+ end
93
+
94
+ ##
95
+ # Run the test
96
+ def run_test(got, expect:nil, run: nil, args:[])
97
+ if run
98
+ expect = true
99
+ got = run.call(*args)
100
+ end
101
+ if got == expect
102
+ {"status" => "pass"}
103
+ else
104
+ {"status" => "fail",
105
+ "error" => {
106
+ "got" => got,
107
+ "expect" => expect
108
+ }
109
+ }
110
+ end
111
+ end
112
+
113
+ # A mock request skeleton. Create and then edit with test-specific attrs
114
+ def mock_req
115
+ Waxx::Req.new(ENV, {}, 'GET', "/test/test/1", {}, {}, {}, Time.new).freeze
116
+ end
117
+
118
+ # A mock request with default values
119
+ def mock_res(req)
120
+ Waxx::Res.new("", 200, Waxx::Server.default_response_headers(req, "txt"), [], [], [])
121
+ end
122
+
123
+ # A logged-in user
124
+ def x_user(req=mock_req, res=nil, db=nil)
125
+ res ||= mock_res(req)
126
+ #x = Waxx::X.new(req, res, usr, ua, db, meth.downcase.to_sym, app, act, oid, args, ext, jobs).freeze
127
+ Waxx::X.new(
128
+ req,
129
+ res,
130
+ {'id' => 1, 'grp'=>['user']},
131
+ {'id' => 1},
132
+ db,
133
+ :get,
134
+ :test,
135
+ :test,
136
+ 1,
137
+ [1],
138
+ "json",
139
+ []
140
+ )
141
+ end
142
+
143
+ # A non-user/public/guest
144
+ def x_nonuser(req=mock_req, res=nil, db=nil)
145
+ res ||= mock_res(req)
146
+ Waxx::X.new(
147
+ req,
148
+ res,
149
+ {'grp'=>[]},
150
+ {},
151
+ db,
152
+ :get,
153
+ :test,
154
+ :test,
155
+ 1,
156
+ [1],
157
+ "json",
158
+ []
159
+ )
160
+ end
161
+ end
162
+
data/lib/waxx/util.rb ADDED
@@ -0,0 +1,57 @@
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::Util
5
+ extend self
6
+
7
+ def camel_case(str)
8
+ title_case(str.to_s.gsub(/[\._-]/,' ')).gsub(' ','')
9
+ end
10
+
11
+ alias camelize camel_case
12
+
13
+ def label(str)
14
+ title_case(humanize(str.to_s))
15
+ end
16
+
17
+ def humanize(str)
18
+ underscore(str.to_s).gsub('_',' ').capitalize
19
+ end
20
+
21
+ def title_case(str)
22
+ str.to_s.split(' ').map{|t| t.capitalize}.join(' ')
23
+ end
24
+
25
+ alias titleize title_case
26
+
27
+ def underscore(str)
28
+ str.to_s.gsub(/::/, '_')
29
+ .gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
30
+ .gsub(/([a-z\d])([A-Z])/,'\1_\2')
31
+ .tr("-", "_").tr(" ","_")
32
+ .downcase
33
+ end
34
+
35
+ def app_from_class(cls)
36
+ cls.to_s.split("::")[1]
37
+ end
38
+
39
+ def table_from_class(cls)
40
+ underscore(app_from_class(cls))
41
+ end
42
+
43
+ def class_from_table(tbl)
44
+ tbl.to_s.split("_").map{|i| i.capitalize}.join
45
+ end
46
+
47
+ def get_const(base_class, *names)
48
+ names.inject(base_class){|c, n|
49
+ c.const_get(n.to_s.split("_").map{|i| i.capitalize}.join)
50
+ }
51
+ end
52
+
53
+ def qs(str)
54
+ Waxx::Http.qs(str)
55
+ end
56
+
57
+ end
@@ -0,0 +1,3 @@
1
+ module Waxx
2
+ Version = '0.1.2'
3
+ end
data/lib/waxx/view.rb ADDED
@@ -0,0 +1,389 @@
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
+ # A Waxx::View is like a database view.
6
+ # You define the primary object and related tables and fields on the view and it handles some routine processes for you.
7
+ # You can also just use it as a container for specialized business logic or complicated queries.
8
+ #
9
+ # Example usage:
10
+ #
11
+ # ```
12
+ # module App::Usr::List
13
+ # extend Waxx::View
14
+ # extend self
15
+ #
16
+ # # Define what layouts to allow
17
+ # as :json
18
+ #
19
+ # # Define what fields are in the view
20
+ # has(
21
+ # # Fields that are in the 'usr' table
22
+ # :id,
23
+ # :usr_name,
24
+ # :last_login_date,
25
+ # :last_login_host,
26
+ # :failed_login_count,
27
+ # # Fields that are in the 'person' table. Relationships are defined in App::Usr.has(...)
28
+ # "person_id: person.id", # This column is accessible as 'person_id' on this view
29
+ # "person.first_name",
30
+ # "person.last_name",
31
+ # )
32
+ # end
33
+ # ```
34
+ #
35
+ # This view definition will provide you with the following functionality:
36
+ #
37
+ # ```
38
+ # App::Usr::List.get(x)
39
+ # # Executes the following SQL:
40
+ # SELECT usr.id, usr.usr_name, usr.last_login_date, usr.last_login_host, usr.failed_login_count,
41
+ # person.id AS person_id, person.first_name, person.last_name
42
+ # FROM usr LEFT JOIN person ON usr.id = person.id
43
+ # # And returns a PG::Result (If you are using the PG database connector)
44
+ # ```
45
+ module Waxx::View
46
+
47
+ # The parent (primary) object. For example in App::Usr::List, App::Usr is the @object
48
+ attr :object
49
+ # The table name of the primary object
50
+ attr :table
51
+ # A hash of columns (See Waxx::Pg.has)
52
+ attr :columns
53
+ # A hash of name: join_sql. Normally set automatically when the columns are parsed.
54
+ attr :joins
55
+ # A hash of related tables. Normally set automatically when the columns are parsed.
56
+ attr :relations
57
+ # How to search the view by specific field
58
+ attr :matches
59
+ # How to search the view by the "q" parameter
60
+ attr :searches
61
+ # The default order of the results
62
+ attr :order_by
63
+ # A hash of how you can sort this view
64
+ attr :orders
65
+
66
+ ##
67
+ # Initialize a view. This is normally done automatically when calling `has`.
68
+ #
69
+ # Call init if the table, object, or layouts are non-standard. You can also set the attrs directly like `@table = 'usr'`
70
+ #
71
+ # ```
72
+ # tbl: The name of the table
73
+ # cols: Same as has
74
+ # layouts: The layouts to auto-generate using waxx defaults: json, csv, tab, etc.
75
+ # ```
76
+ def init(tbl: nil, cols: nil, layouts: nil)
77
+ @table = (tbl || App.table_from_class(name)).to_sym
78
+ @object = App.get_const(App, @table)
79
+ @relations = {}
80
+ @orders = {}
81
+ has(*cols) if cols
82
+ as(layouts) if layouts
83
+ end
84
+
85
+ ##
86
+ # Get a column on the view
87
+ #
88
+ # ```
89
+ # App::Usr::Record[:usr_name] => {:type=>"character", :label=>"User Name", :table=>:usr, :column=>:usr_name, :views=>[App::Usr::Record, App::Usr::List, App::Usr::Signup]}
90
+ # ```
91
+ def [](c)
92
+ @columns[c.to_sym]
93
+ end
94
+
95
+ ##
96
+ # Columnas on a view can be defined in multiple ways:
97
+ #
98
+ # ```
99
+ # has(
100
+ # :id, # A field in the parent object
101
+ # :name, # Another field in the parent object
102
+ # "company_name:company.name", # name:rel_name.col_name "name" is the name of the col in the query, rel_name is the join table as defined in object, col_name is the column in the foreign table
103
+ # [:creator, {table: "person", sql_select: "first_name || ' ' || last_name", label: "Creator"}] # Array: [name, column (Hash)]
104
+ # {modifier: {table: "person", sql_select: "first_name || ' ' || last_name", label: "Creator"}}
105
+ # ```
106
+ #
107
+ def has(*cols)
108
+ return @columns if cols.empty?
109
+ init if @object.nil?
110
+ #@joins = {}
111
+ @columns = {}
112
+ cols.each{|c|
113
+ n = col = nil
114
+ case c
115
+ # Get the col from the object
116
+ when Symbol
117
+ n = c
118
+ col = @object[c]
119
+ # A related col (must be defined in the related object)
120
+ when String
121
+ n, col = string_to_col(c)
122
+ # A custom col [name, col] col is a Hash
123
+ when Array
124
+ n, col = c
125
+ # A custom col {name: col}, col is a Hash
126
+ when Hash
127
+ n, col = c.to_a[0]
128
+ end
129
+ if col.nil?
130
+ Waxx.debug "Column #{c} not defined in #{@object}."
131
+ #raise "Column #{c} not defined in #{@object}."
132
+ end
133
+ #Waxx.debug @relations.inspect
134
+ #TODO: Deal with relations that have different names than the tables
135
+ col[:views] << self rescue col[:views] = [self]
136
+ @columns[n.to_sym] = col
137
+ }
138
+ @joins ||= Hash[@relations.map{|n, r| [n, %(#{r/:join} JOIN #{r/:foreign_table} AS #{n} ON #{r/:table}.#{r/:col} = #{n}.#{r/:foreign_col})] }]
139
+ end
140
+
141
+ ##
142
+ # Column defined as a string in the format: name:foreign_table.foreign_col
143
+ # Converted to SQL: foreign_table.foreign_col AS name
144
+ # Also adds entries in the @relations hash. @relations drive the SQL join statement
145
+ # Joins are defined in the primary object of this view.
146
+ def string_to_col(str)
147
+ n, rel_name, col_name = parse_col(str)
148
+ # Look in the primary and related objects for relations
149
+ j = @object.joins/rel_name || @relations.values.map{|foreign_rel|
150
+ #Waxx.debug "REL: #{foreign_rel}"
151
+ o = App.get_const(App, foreign_rel/:foreign_table)
152
+ #Waxx.debug o
153
+ #Waxx.debug o.joins.inspect
154
+ o.joins/rel_name
155
+ }.compact.first
156
+ #Waxx.debug "j:#{j.inspect}, n: #{n}, rel: #{rel_name}, col: #{col_name}"
157
+ begin
158
+ col = (App.get_const(App, j/:foreign_table)/col_name).dup
159
+ col[:table] = rel_name
160
+ rescue NoMethodError => e
161
+ Waxx.debug "ERROR: NoMethodError: #{rel_name} does not define col: #{col_name}"
162
+ raise e
163
+ rescue NameError, TypeError => e
164
+ Waxx.debug "ERROR: Name or Type Error: #{rel_name} does not define col: #{col_name}"
165
+ raise e
166
+ end
167
+ begin
168
+ @relations[rel_name] ||= j #(App.get_const(App, j/:table)).joins
169
+ @orders[n] = App.get_const(App, j/:foreign_table).orders/n
170
+ @orders["_#{n}"] = App.get_const(App, j/:foreign_table).orders/"_#{n}"
171
+ #col[:table] = rel_name
172
+ rescue NoMethodError => e
173
+ if col.nil?
174
+ Waxx.debug "col is nil"
175
+ else
176
+ Waxx.debug "ERROR: App[#{col[:table]}] has no joins in View.has"
177
+ end
178
+ raise e
179
+ end
180
+ #Waxx.debug n
181
+ #Waxx.debug col
182
+ [n, col]
183
+ end
184
+
185
+ ##
186
+ # Parse a column (internal method used by col)
187
+ def parse_col(str)
188
+ nam = rel = col = nil
189
+ parts = str.split(/[:\.]/)
190
+ case str
191
+ # alias:relationship.column
192
+ when /^\w+:\s*\w+\.\w+$/
193
+ nam, rel, col = str.split(/[:\.]/).map{|part| part.strip}
194
+ # relationship.column
195
+ when /^\w+\.\w+$/
196
+ rel, col = str.split(".")
197
+ # alias:column (from primary object/table)
198
+ when /^\w+:\w+$/
199
+ nam, col = str.split(":")
200
+ # column (from primary object/table)
201
+ when /^\w+$/
202
+ col = str
203
+ else
204
+ raise "Could not parse column definition in Waxx::View.parse_col (#{name}). Unknown match: #{str}."
205
+ end
206
+ nam = col if nam.nil?
207
+ rel = @table if rel.nil?
208
+ [nam, rel, col]
209
+ end
210
+
211
+ ##
212
+ # Turn the @joins attribute into SQL for the JOIN clause
213
+ def joins_to_sql()
214
+ return nil if @joins.nil? or @joins.empty?
215
+ @joins.map{|n,v| v}.join(" ")
216
+ end
217
+
218
+ ##
219
+ # Autogenerate the modules to do standard layouts like Json, Csv, or Tab
220
+ #
221
+ # ```
222
+ # as :json
223
+ # ```
224
+ #
225
+ # This will generate the following code and allow the output of json formatted data for the view
226
+ #
227
+ # ```
228
+ # module App::Usr::List::Json
229
+ # extend Waxx::Json
230
+ # extend self
231
+ # end
232
+ # ```
233
+ def as(*views)
234
+ views.each{|v|
235
+ eval("
236
+ module #{name}::#{v.to_s.capitalize}
237
+ extend Waxx::#{v.to_s.capitalize}
238
+ extend self
239
+ end
240
+ ")
241
+ }
242
+ end
243
+
244
+ ##
245
+ # An array of columns to match in when passed in as params
246
+ def match_in(*cols)
247
+ @matches = cols.flatten
248
+ end
249
+
250
+ ##
251
+ # Any array of columns to automatically search in using the "q" parameter
252
+ def search_in(*cols)
253
+ @searches = cols.flatten
254
+ end
255
+
256
+ ##
257
+ # Set the default order. Order is a key of the field name. Use _name to sort descending.
258
+ def default_order(ord)
259
+ @order_by = ord
260
+ end
261
+
262
+ ##
263
+ # Gets the data for the view and displays it. This is just a shortcut method.
264
+ #
265
+ # This is normally called from the handler method defined in Object
266
+ #
267
+ # ```
268
+ # App::Usr::List.run(x)
269
+ # # Given a get request with the json extention, the above is a shortcut to:
270
+ # data = App::Usr::List.get(x)
271
+ # App::Usr::List::Json.get(x, data)
272
+ # ```
273
+ def run(x, id:nil, data:nil, where:nil, having:nil, order:nil, limit:nil, offset:nil, message:{}, as:x.ext, meth:x.meth, args:{})
274
+ case meth.to_sym
275
+ when :get, :head
276
+ if data.nil? or data.empty?
277
+ if id
278
+ data = get_by_id(x, id)
279
+ else
280
+ data = get(x, where:where, having:having, order:(order||x['order']), limit:(limit||x['limit']), offset:(offset||x['offset']), args:args)
281
+ end
282
+ end
283
+ when :put, :post, :patch
284
+ data = put_post(x, id, data, args:args)
285
+ when :delete
286
+ delete(x, id, args:args)
287
+ else
288
+ raise "Unknown request method in Waxx::View.run(#{name})"
289
+ end
290
+ layout = const_get(as.to_s.capitalize) rescue nil
291
+ return App.not_found(x, message:"No layout defined for #{as}") if not layout
292
+ if layout.respond_to? meth
293
+ render(x, data, message: message, as: as, meth: meth)
294
+ else
295
+ render(x, data, message: message, as: as, meth: "get")
296
+ end
297
+ end
298
+ alias view run
299
+
300
+ ##
301
+ # Automatically build the where clause of SQL based on the parameters passed in and the definition of matches and searches.
302
+ def build_where(x, args: {}, matches: @matches, searches: @searches)
303
+ return nil if args.nil? or args.empty? or (matches.nil? and searches.nil?)
304
+ w_str = ""
305
+ w_args = []
306
+ q = args/:q || x['q']
307
+ if q and searches
308
+ w_str += "("
309
+ searches.each_with_index{|c, i|
310
+ w_str += " OR " if i > 0
311
+ w_str += "LOWER(#{c}) like $1"
312
+ }
313
+ w_args << "%#{q.downcase}%"
314
+ w_str += ")"
315
+ end
316
+ if matches
317
+ matches.each_with_index{|c, i|
318
+ next if (x/c).to_s == "" and (args/c).to_s == ""
319
+ w_str += " AND " if w_str != ""
320
+ col = self[c.to_sym]
321
+ w_str += "#{c} #{col[:match] || "="} $#{w_args.size + 1}"
322
+ w_args << (args/c || x/c)
323
+ }
324
+ end
325
+ [w_str, w_args]
326
+ end
327
+
328
+ ##
329
+ # Override this method in a view to change params
330
+ def get(x, where:nil, having:nil, order:nil, limit:nil, offset:nil, args:{}, &blk)
331
+ where ||= build_where(x, args: args)
332
+ order ||= args/:order || @order_by
333
+ limit ||= args/:limit
334
+ offset ||= args/:offset
335
+ @object.get(x,
336
+ view: self,
337
+ where: where,
338
+ joins: joins_to_sql(),
339
+ having: having,
340
+ order: order,
341
+ limit: limit,
342
+ offset: offset
343
+ )
344
+ end
345
+
346
+ ##
347
+ # Get a single record of the view based on the primary key of the primary object
348
+ def get_by_id(x, id)
349
+ @object.get_by_id(x, id, view: self)
350
+ end
351
+ alias by_id get_by_id
352
+
353
+ ##
354
+ # Save data
355
+ def put_post(x, id, data, args:nil)
356
+ @object.put_post(x, id, data, view: self)
357
+ end
358
+ alias post put_post
359
+ alias put put_post
360
+
361
+ ##
362
+ # Delete a record by ID (primary key of the primary object)
363
+ def delete(x, id)
364
+ @object.delete(x, id)
365
+ end
366
+
367
+ ##
368
+ # Render the view using the layout for meth and as
369
+ #
370
+ # `render(x, data, as: 'json', meth: 'get')`
371
+ #
372
+ # Uses logical defaults based on x.req
373
+ def render(x, data, message: {}, as:x.ext, meth:x.meth)
374
+ return App.not_found(x) unless const_defined?(as.to_s.capitalize)
375
+ const_get(as.to_s.capitalize).send(meth, x, data, message: message)
376
+ end
377
+
378
+ ##
379
+ # Send a not found message back to the client using the appropriate layout (json, csv, etc)
380
+ def not_found(x, data:{}, message: {type: "NotFound", message:"The record you requested was not found."}, as:x.ext)
381
+ self.const_get(as.to_s.capitalize).not_found(x, data:{}, message: message)
382
+ end
383
+
384
+ ##
385
+ # A shorcut to Waxx.debug
386
+ def debug(str, level=3)
387
+ Waxx.debug(str, level)
388
+ end
389
+ end
data/lib/waxx/waxx.rb ADDED
@@ -0,0 +1,73 @@
1
+ # Waxx Copyright (c) 2016-2017 ePark labs Inc. & Daniel J. Fitzpatrick <dan@eparklabs.com>
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ ##
16
+ # Waxx is a high-performance Ruby web application development framework. See https://www.waxx.io/ for more information.
17
+ module Waxx
18
+ extend self
19
+
20
+ # TODO: Figure this out based on the waxx command opts
21
+ Root = Dir.pwd
22
+
23
+ # A few helper functions
24
+
25
+ ##
26
+ # Shortcut to Waxx::Waxx variables
27
+ def [](str)
28
+ Waxx::Conf[str]
29
+ end
30
+
31
+ ##
32
+ # Shortcut to Waxx::Waxx variables
33
+ def /(str)
34
+ Waxx::Conf/str
35
+ end
36
+
37
+ ##
38
+ # Output to the log
39
+ # Waxx.debug(
40
+ # str, # The text to output
41
+ # level # The number 0 (most important) - 9 (least important)
42
+ # )
43
+ # # Set the level in config.yaml (debug.level) of what level or lower to ouutput
44
+ def debug(str, level=3)
45
+ puts str.to_s if level <= Waxx['debug']['level'].to_i
46
+ end
47
+
48
+ ##
49
+ # Get a pseudo-random (non-cryptographically secure) string to use as a temporary password.
50
+ # If you need real random use SecureRandom.random_bytes(size) or SecureRandom.base64(size).
51
+ # 1. size: Length of string
52
+ # 2. type: [
53
+ # any: US keyboard characters
54
+ # an: Alphanumeric (0-9a-zA-Z)
55
+ # anl: Alphanumeric lower: (0-9a-z)
56
+ # chars: Your own character list
57
+ # ]
58
+ # 3. chars: A string of your own characters
59
+ def random_string(size=32, type=:an, chars=nil)
60
+ if not type.to_sym == :chars
61
+ types = {
62
+ any: '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz~!@#$%^&*()_-+={[}]|:;<,>.?/',
63
+ an: '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
64
+ anl: '0123456789abcdefghijklmnopqrstuvwxyz'
65
+ }
66
+ chars = types[type.to_sym].split("")
67
+ end
68
+ opts = chars.size
69
+ 1.upto(size).map{chars[rand(opts)]}.join
70
+ end
71
+
72
+ end
73
+