lux-fw 0.1.17
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.version +1 -0
- data/bin/cli/am +250 -0
- data/bin/cli/assets +37 -0
- data/bin/cli/console +50 -0
- data/bin/cli/dev +1 -0
- data/bin/cli/eval +15 -0
- data/bin/cli/exceptions +62 -0
- data/bin/cli/generate +82 -0
- data/bin/cli/get +5 -0
- data/bin/cli/nginx +28 -0
- data/bin/cli/production +1 -0
- data/bin/cli/routes +12 -0
- data/bin/cli/server +1 -0
- data/bin/cli/stat +1 -0
- data/bin/forever +65 -0
- data/bin/job_que +39 -0
- data/bin/lux +87 -0
- data/bin/txt/nginx.conf +29 -0
- data/bin/txt/siege-and-puma.txt +3 -0
- data/lib/common/base32.rb +47 -0
- data/lib/common/before_and_after.rb +71 -0
- data/lib/common/class_attributes.rb +66 -0
- data/lib/common/class_method_params.rb +94 -0
- data/lib/common/crypt.rb +66 -0
- data/lib/common/folder_model.rb +50 -0
- data/lib/common/generic_model.rb +62 -0
- data/lib/common/policy.rb +54 -0
- data/lib/common/string_base.rb +49 -0
- data/lib/common/url.rb +171 -0
- data/lib/lux/api/api.rb +150 -0
- data/lib/lux/api/lib/application_api.rb +19 -0
- data/lib/lux/api/lib/doc_builder.rb +18 -0
- data/lib/lux/api/lib/dsl.rb +73 -0
- data/lib/lux/api/lib/model_api.rb +145 -0
- data/lib/lux/api/lib/rescue.rb +18 -0
- data/lib/lux/cache/cache.rb +71 -0
- data/lib/lux/cache/lib/memcached.rb +3 -0
- data/lib/lux/cache/lib/null.rb +23 -0
- data/lib/lux/cache/lib/ram.rb +38 -0
- data/lib/lux/cell/cell.rb +260 -0
- data/lib/lux/config/config.rb +88 -0
- data/lib/lux/controller/controller.rb +185 -0
- data/lib/lux/controller/lib/nav.rb +77 -0
- data/lib/lux/controller/lib/plugs.rb +10 -0
- data/lib/lux/delayed_job/delayed_job.rb +44 -0
- data/lib/lux/delayed_job/lib/memory.rb +14 -0
- data/lib/lux/delayed_job/lib/nsq.rb +3 -0
- data/lib/lux/delayed_job/lib/postgre.rb +6 -0
- data/lib/lux/delayed_job/lib/redis.rb +19 -0
- data/lib/lux/error/error.rb +75 -0
- data/lib/lux/helper/helper.rb +109 -0
- data/lib/lux/html/html.rb +3 -0
- data/lib/lux/html/lib/form.rb +81 -0
- data/lib/lux/html/lib/input.rb +71 -0
- data/lib/lux/html/lib/input_types.rb +277 -0
- data/lib/lux/lux.rb +164 -0
- data/lib/lux/mailer/mailer.rb +73 -0
- data/lib/lux/page/lib/encrypt_params.rb +44 -0
- data/lib/lux/page/lib/flash.rb +49 -0
- data/lib/lux/page/lib/static_file.rb +97 -0
- data/lib/lux/page/page.rb +271 -0
- data/lib/lux/rescue_from/rescue_from.rb +61 -0
- data/lib/lux/template/template.rb +95 -0
- data/lib/lux-fw.rb +48 -0
- data/lib/overload/array.rb +52 -0
- data/lib/overload/blank.rb +62 -0
- data/lib/overload/date.rb +58 -0
- data/lib/overload/file.rb +14 -0
- data/lib/overload/hash.rb +86 -0
- data/lib/overload/hash_wia.rb +282 -0
- data/lib/overload/inflections.rb +199 -0
- data/lib/overload/integer.rb +19 -0
- data/lib/overload/module.rb +10 -0
- data/lib/overload/nil.rb +8 -0
- data/lib/overload/object.rb +77 -0
- data/lib/overload/string.rb +89 -0
- data/lib/overload/string_inflections.rb +7 -0
- data/lib/overload/struct.rb +5 -0
- data/lib/plugins/assets/assets_plug.rb +26 -0
- data/lib/plugins/assets/helper_module_adapter.rb +49 -0
- data/lib/plugins/assets/init.rb +4 -0
- data/lib/plugins/db_helpers/array_and_hstore.rb +64 -0
- data/lib/plugins/db_helpers/arrays_and_tags.rb +23 -0
- data/lib/plugins/db_helpers/before_save.rb +44 -0
- data/lib/plugins/db_helpers/cached_find_by.rb +45 -0
- data/lib/plugins/db_helpers/class_and_instance.rb +120 -0
- data/lib/plugins/db_helpers/dataset_plugin.rb +101 -0
- data/lib/plugins/db_helpers/filter_wrappers.rb +21 -0
- data/lib/plugins/db_helpers/link_plugin.rb +95 -0
- data/lib/plugins/db_helpers/localize_plugin.rb +57 -0
- data/lib/plugins/db_helpers/primary_keys.rb +36 -0
- data/lib/plugins/db_helpers/typero_attributes.rb +69 -0
- data/lib/plugins/db_logger/init.rb +18 -0
- data/lib/plugins/db_logger/lux_response_adapter.rb +9 -0
- data/lib/plugins/paginate/helper.rb +32 -0
- data/lib/plugins/paginate/sequel_adapter.rb +18 -0
- data/lib/vendor/mini_assets/mini_asset/base.rb +167 -0
- data/lib/vendor/mini_assets/mini_asset/css.rb +38 -0
- data/lib/vendor/mini_assets/mini_asset/js.rb +38 -0
- data/lib/vendor/mini_assets/mini_asset.rb +31 -0
- data/lib/vendor/oauth/lib/facebook.rb +35 -0
- data/lib/vendor/oauth/lib/github.rb +37 -0
- data/lib/vendor/oauth/lib/google.rb +41 -0
- data/lib/vendor/oauth/lib/linkedin.rb +41 -0
- data/lib/vendor/oauth/lib/stackexchange.rb +37 -0
- data/lib/vendor/oauth/lib/twitter.rb +41 -0
- data/lib/vendor/oauth/oauth.rb +46 -0
- metadata +334 -0
@@ -0,0 +1,26 @@
|
|
1
|
+
# plug :local_assets
|
2
|
+
# /compiled_asset/www/js/pjax.coffee
|
3
|
+
# /raw_asset/www/js/pjax.coffee
|
4
|
+
class Lux::Controller
|
5
|
+
def lux_assets_plug
|
6
|
+
|
7
|
+
# only allow clear in dev
|
8
|
+
if Lux.page.no_cache?
|
9
|
+
puts '* Clearing assets from ./tmp/assets'
|
10
|
+
`rm -rf ./tmp/assets`
|
11
|
+
end
|
12
|
+
|
13
|
+
path = nav.path.join('/')
|
14
|
+
|
15
|
+
if nav.root == 'compiled_asset'
|
16
|
+
asset = MiniAsset.create(path)
|
17
|
+
page.content_type asset.content_type
|
18
|
+
page.body asset.compiled_data
|
19
|
+
elsif nav.root == 'raw_asset'
|
20
|
+
Lux.error "You can watch raw files only in development" unless Lux.dev?
|
21
|
+
|
22
|
+
file = Lux.root.join('app/assets/%s' % path)
|
23
|
+
body file.exist? ? file.read : "error: File not found"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# export to all templates
|
2
|
+
# = asset 'www/index.scss'
|
3
|
+
# = asset 'www/index.coffee'
|
4
|
+
module DefaultHelper
|
5
|
+
def asset_include path
|
6
|
+
raise ArgumentError.new("Path can't be empty") if path.empty?
|
7
|
+
|
8
|
+
url = if path.starts_with?('/') || path.include?('//')
|
9
|
+
path
|
10
|
+
else
|
11
|
+
'/compiled_asset/%s' % path
|
12
|
+
end
|
13
|
+
|
14
|
+
ext = url.split('?').first.split('.').last
|
15
|
+
|
16
|
+
if ['coffee', 'js'].include?(ext)
|
17
|
+
%[<script src="#{url}"></script>]
|
18
|
+
else
|
19
|
+
%[<link rel="stylesheet" href="#{url}" />]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# builds full asset path based on resource extension
|
24
|
+
# asset('main/index.coffee')
|
25
|
+
# will render 'app/assets/main/index.coffee' as http://aset.path/assets/main-index-md5hash.js
|
26
|
+
def asset file, dev_file=nil
|
27
|
+
# return second link if it is defined and we are in dev mode
|
28
|
+
return asset_include dev_file if dev_file && Lux.dev?
|
29
|
+
|
30
|
+
# return internet links
|
31
|
+
return asset_include file if file.starts_with?('/') || file.starts_with?('http')
|
32
|
+
|
33
|
+
# return asset link in production or faile unless able
|
34
|
+
unless Lux.config(:compile_assets)
|
35
|
+
mfile = MiniAsset.manifest['files'][file]
|
36
|
+
raise 'Compiled asset link for "%s" not found in manifest.json' % file if mfile.empty?
|
37
|
+
return asset_include Lux.config.assets_root.to_s + mfile
|
38
|
+
end
|
39
|
+
|
40
|
+
# try to create list of incuded files and show every one of them
|
41
|
+
data = []
|
42
|
+
asset = MiniAsset.create file
|
43
|
+
for file in asset.files
|
44
|
+
data.push asset_include file
|
45
|
+
end
|
46
|
+
|
47
|
+
data.join($/)
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# inits and saves postgre
|
2
|
+
# string and integer arrays
|
3
|
+
# hstore as hash with indifferent access to keys
|
4
|
+
|
5
|
+
module Sequel::Plugins::LuxArrayAndHstore
|
6
|
+
module ClassMethods
|
7
|
+
end
|
8
|
+
|
9
|
+
module DatasetMethods
|
10
|
+
end
|
11
|
+
|
12
|
+
module InstanceMethods
|
13
|
+
# set right values on
|
14
|
+
def after_initialize
|
15
|
+
db_schema.each do |field, schema|
|
16
|
+
type = schema[:db_type]
|
17
|
+
if type.include?('[]') && !self[field].is_a?(Array)
|
18
|
+
self[field] = self[field].to_s.gsub(/^\{|\}$/, '').split(',')
|
19
|
+
self[field] = self[field].map(&:to_i) if schema[:type] == :integer
|
20
|
+
elsif type == 'jsonb'
|
21
|
+
self[field] ||= {}
|
22
|
+
self[field] = HashWithIndifferentAccess.new(JSON.load(self[field]) || {})
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def before_save
|
28
|
+
@_array_hash_cache_fields = {}
|
29
|
+
|
30
|
+
db_schema.each do |field, schema|
|
31
|
+
if schema[:db_type].include?('[]')
|
32
|
+
@_array_hash_cache_fields[field] = self[field].dup
|
33
|
+
|
34
|
+
data = self[field].to_a
|
35
|
+
data = data.map(&:to_i) if schema[:type] == :integer
|
36
|
+
|
37
|
+
db_data = data.to_json
|
38
|
+
db_data[0,1] = '{'
|
39
|
+
db_data[-1,1] = '}'
|
40
|
+
self[field] = db_data
|
41
|
+
elsif ['json', 'jsonb'].index(schema[:db_type])
|
42
|
+
@_array_hash_cache_fields[field] = self[field].dup
|
43
|
+
|
44
|
+
# we use this to convert symbols in keys to strings
|
45
|
+
self[field] = JSON.load(self[field].to_json).to_json
|
46
|
+
elsif schema[:db_type] == 'boolean'
|
47
|
+
self[field] = false if self[field] == 0
|
48
|
+
self[field] = true if self[field] == 1
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
super
|
53
|
+
end
|
54
|
+
|
55
|
+
def after_save
|
56
|
+
@_array_hash_cache_fields.each { |k, v| self[k] = v }
|
57
|
+
|
58
|
+
super
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
Sequel::Model.plugin :lux_array_and_hstore
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Sequel::Plugins::LuxArrays
|
2
|
+
module ClassMethods
|
3
|
+
end
|
4
|
+
|
5
|
+
module DatasetMethods
|
6
|
+
# def tagged_with(tag=nil, field=:tags)
|
7
|
+
# return self unless tag
|
8
|
+
# where("? = any (#{field})", tag)
|
9
|
+
# end
|
10
|
+
|
11
|
+
# only postgree
|
12
|
+
# Bucket.can.all_tags -> can_tags mora biti zadnji
|
13
|
+
def all_tags(field=:tags, *args)
|
14
|
+
sqlq = sql.split(' FROM ')[1]
|
15
|
+
sqlq = "select lower(unnest(#{field})) as tag FROM " + sqlq
|
16
|
+
sqlq = "select tag as name, count(tag) as cnt from (#{sqlq}) as tags group by tag order by cnt desc"
|
17
|
+
DB.fetch(sqlq).map(&:h).or([])
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
Sequel::Model.plugin :lux_arrays
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Sequel::Plugins::LuxBeforeSave
|
2
|
+
module InstanceMethods
|
3
|
+
def validate
|
4
|
+
for field in columns
|
5
|
+
schema = db_schema[field]
|
6
|
+
|
7
|
+
# alert, no trim on to big field length
|
8
|
+
if schema[:max_length] && self[field] && self[field].length > schema[:max_length]
|
9
|
+
msg = 'Field "%s" max length is %s, got %d' % [field, schema[:max_length], self[field].length]
|
10
|
+
errors.add(field, msg)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
super
|
14
|
+
end
|
15
|
+
|
16
|
+
def before_save
|
17
|
+
# basic security
|
18
|
+
self[:created_at] = Time.now.utc if ! self[:id] && respond_to?(:created_at)
|
19
|
+
self[:updated_at] = Time.now.utc if respond_to?(:updated_at)
|
20
|
+
|
21
|
+
if respond_to?(:created_by) || respond_to?(:updated_by)
|
22
|
+
errors.add(:base, 'You have to be registered to save data') unless User.current
|
23
|
+
end
|
24
|
+
|
25
|
+
for f in [:created_by, :updated_by]
|
26
|
+
if respond_to?(f) && !self[:id] && !self[f]
|
27
|
+
raise UnauthorizedError, "Current user not defined, can't set :#{f} on #{self.class}" unless User.current
|
28
|
+
self[f] = User.current.id
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
Lux.cache.delete(cache_key)
|
33
|
+
super
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
def before_destroy
|
38
|
+
Lux.cache.delete(cache_key)
|
39
|
+
super
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
Sequel::Model.plugin :lux_before_save
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# module Sequel::Plugins::LuxCachedFindBy
|
2
|
+
|
3
|
+
# module ClassMethods
|
4
|
+
|
5
|
+
# @@cached_find_by ||= {}
|
6
|
+
# @@cache_all_for ||= {}
|
7
|
+
|
8
|
+
# def find id
|
9
|
+
# return nil if id.blank?
|
10
|
+
# key = "#{self}/#{id}"
|
11
|
+
# Lux.cache.thread(key) { where(id:id).first }
|
12
|
+
# end
|
13
|
+
|
14
|
+
# def find_by what
|
15
|
+
# where(what).first
|
16
|
+
# end
|
17
|
+
|
18
|
+
# ###
|
19
|
+
|
20
|
+
# # in top of the class, defines cache to be run in memory
|
21
|
+
# # cache_all_for 10.minutes
|
22
|
+
# def cache_all_for duration
|
23
|
+
# @@cache_all_for[self.to_s] = duration
|
24
|
+
# end
|
25
|
+
|
26
|
+
# # City.cached_find_by(120, code: nav.root)
|
27
|
+
# def cached_find_by duration, opts
|
28
|
+
# key = opts.keys.first
|
29
|
+
# value = opts.values.first
|
30
|
+
# time = Time.now.to_i
|
31
|
+
|
32
|
+
# @@cached_find_by[self.to_s] = nil if @@cached_find_by[self.to_s] && (@@cached_find_by[self.to_s][0] + duration) < time
|
33
|
+
# @@cached_find_by[self.to_s] ||= [time, all]
|
34
|
+
|
35
|
+
# for el in @@cached_find_by[self.to_s][1]
|
36
|
+
# return el.dup if el[key] == value
|
37
|
+
# end
|
38
|
+
|
39
|
+
# nil
|
40
|
+
# end
|
41
|
+
|
42
|
+
# end
|
43
|
+
# end
|
44
|
+
|
45
|
+
# Sequel::Model.plugin :lux_cached_find_by
|
@@ -0,0 +1,120 @@
|
|
1
|
+
# http://ricostacruz.com/cheatsheets/sequel.html
|
2
|
+
# http://sequel.jeremyevans.net/rdoc/files/doc/model_plugins_rdoc.html
|
3
|
+
|
4
|
+
module Sequel::Plugins::LuxClassAndInstance
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
[:desc, :asc, :pluck, :ids].each do |m|
|
8
|
+
Sequel::Plugins.def_dataset_methods self, m
|
9
|
+
end
|
10
|
+
|
11
|
+
def find id
|
12
|
+
return nil if id.blank?
|
13
|
+
key = "#{self}/#{id}"
|
14
|
+
Lux.cache.thread(key) { where(id:id).first }
|
15
|
+
end
|
16
|
+
|
17
|
+
def find_by what
|
18
|
+
where(what).first
|
19
|
+
end
|
20
|
+
|
21
|
+
# active record like define scope
|
22
|
+
# http://sequel.jeremyevans.net/rdoc/classes/Sequel/Model/ClassMethods.html
|
23
|
+
def scope name, body=nil, &block
|
24
|
+
block ||= body
|
25
|
+
dataset_module{define_method(name, &block)}
|
26
|
+
end
|
27
|
+
|
28
|
+
# instance scope, same as scope but runs on instance
|
29
|
+
# iscope(:notes) { Note.where(created_by:id) }
|
30
|
+
def iscope name, body=nil, &block
|
31
|
+
block ||= body
|
32
|
+
define_method(name, &block)
|
33
|
+
end
|
34
|
+
|
35
|
+
def where_or_new filter
|
36
|
+
where(filter).first || new(filter)
|
37
|
+
end
|
38
|
+
|
39
|
+
def where_or_create filter
|
40
|
+
where(filter).first || create(filter)
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
module InstanceMethods
|
46
|
+
def cache_key
|
47
|
+
"#{self.class}/#{id}"
|
48
|
+
end
|
49
|
+
|
50
|
+
def attributes
|
51
|
+
ret = {}
|
52
|
+
for el in columns
|
53
|
+
ret[el.to_s] = send(el.to_s) rescue '-'
|
54
|
+
end
|
55
|
+
ret
|
56
|
+
end
|
57
|
+
|
58
|
+
def touch
|
59
|
+
save
|
60
|
+
end
|
61
|
+
|
62
|
+
def to_h
|
63
|
+
ret = {}
|
64
|
+
for el in self.keys
|
65
|
+
ret[el] = send el
|
66
|
+
end
|
67
|
+
ret
|
68
|
+
end
|
69
|
+
|
70
|
+
def creator
|
71
|
+
self[:created_by] ? User.find(self[:created_by]) : nil
|
72
|
+
end
|
73
|
+
|
74
|
+
def parent_model
|
75
|
+
model_type.constantize.find(model_id)
|
76
|
+
end
|
77
|
+
|
78
|
+
# has?(:name, "Name is not defined") -> errors.add("Name is not defined")
|
79
|
+
# has?(:name) -> false
|
80
|
+
def has?(*args)
|
81
|
+
if args[1] && args[1].kind_of?(String)
|
82
|
+
unless self[args[0]].present?
|
83
|
+
errors.add(args[0], args[1])
|
84
|
+
return false
|
85
|
+
end
|
86
|
+
return true
|
87
|
+
end
|
88
|
+
args.each { |el| return false unless self[el].present? }
|
89
|
+
true
|
90
|
+
end
|
91
|
+
|
92
|
+
def unique?(field)
|
93
|
+
select(field).xwhere('id<>?', id).count == 0
|
94
|
+
end
|
95
|
+
|
96
|
+
def save!
|
97
|
+
save
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
module DatasetMethods
|
102
|
+
def desc
|
103
|
+
reverse :id
|
104
|
+
end
|
105
|
+
|
106
|
+
def asc
|
107
|
+
order :id
|
108
|
+
end
|
109
|
+
|
110
|
+
def pluck field
|
111
|
+
select_map field
|
112
|
+
end
|
113
|
+
|
114
|
+
def ids
|
115
|
+
select(:id).map(&:id)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
Sequel::Model.plugin :lux_class_and_instance
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Sequel::Model
|
4
|
+
|
5
|
+
module ClassMethods
|
6
|
+
[:xselect, :xorder, :xfrom, :xwhere, :xlike, :last_updated, :qs_search, :for].each do |m|
|
7
|
+
Sequel::Plugins.def_dataset_methods self, m
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
module DatasetMethods
|
12
|
+
def xselect text
|
13
|
+
select Sequel.lit text
|
14
|
+
end
|
15
|
+
|
16
|
+
def xorder text
|
17
|
+
order Sequel.lit text
|
18
|
+
end
|
19
|
+
|
20
|
+
def xfrom text
|
21
|
+
from Sequel.lit text
|
22
|
+
end
|
23
|
+
|
24
|
+
def xwhere hash_or_string, *args
|
25
|
+
return where(Sequel.lit("coalesce(%s,'')!=''" % hash_or_string)) if hash_or_string.is_a?(Symbol)
|
26
|
+
return where(Sequel.lit(hash_or_string, *args)) if hash_or_string.is_a?(String)
|
27
|
+
|
28
|
+
q = hash_or_string.select{ |k,v| v.present? && v != 0 }
|
29
|
+
q.keys.blank? ? self : where(q)
|
30
|
+
end
|
31
|
+
|
32
|
+
def xlike search, *args
|
33
|
+
unless search.blank?
|
34
|
+
search = search.gsub(/'/,"''").downcase
|
35
|
+
where_str = []
|
36
|
+
|
37
|
+
for str in search.split(/\s+/).select(&:present?)
|
38
|
+
and_str = []
|
39
|
+
str = "%#{str}%"
|
40
|
+
|
41
|
+
for el in args
|
42
|
+
if model.db_schema[el][:db_type] == 'jsonb'
|
43
|
+
like_sql = "CAST(#{el} -> '#{Locale.current}' as text) ilike '#{str}'"
|
44
|
+
if Locale::DEFAULT != Locale.current
|
45
|
+
and_str << "(#{like_sql}) or (CAST(#{el} -> '#{Locale::DEFAULT}' as text) ilike '#{str}')"
|
46
|
+
else
|
47
|
+
and_str << like_sql
|
48
|
+
end
|
49
|
+
else
|
50
|
+
and_str << "#{el}::text ilike '#{str}'"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
where_str.push '('+and_str.join(' or ')+')'
|
55
|
+
end
|
56
|
+
|
57
|
+
return where(Sequel.lit(where_str.join(' and ')))
|
58
|
+
end
|
59
|
+
self
|
60
|
+
end
|
61
|
+
|
62
|
+
def last_updated
|
63
|
+
field = model.db_schema[:updated_at] ? :updated_at : :id
|
64
|
+
order(Sequel.desc(field)).first
|
65
|
+
end
|
66
|
+
|
67
|
+
# search in array of qs arguments
|
68
|
+
def qs_search *args
|
69
|
+
for el in args
|
70
|
+
dataset = where("#{el}=?", Lux.page.params[el]) if !Lux.page.params[el].blank? && model.db_schema[el]
|
71
|
+
end
|
72
|
+
dataset || self
|
73
|
+
end
|
74
|
+
|
75
|
+
def for obj
|
76
|
+
# column_names
|
77
|
+
field_name = "#{obj.class.name.underscore}_id".to_sym
|
78
|
+
n1 = model.to_s.underscore
|
79
|
+
n2 = obj.class.to_s.underscore
|
80
|
+
|
81
|
+
cname = n1[0] < n2[0] ? n1+'_'+n2.pluralize : n2+'_'+n1.pluralize
|
82
|
+
|
83
|
+
if (cname.classify.constantize rescue false)
|
84
|
+
where Sequel.lit 'id in (select %s_id from %s where %s_id=%i)' % [n1, cname, n2, obj.id]
|
85
|
+
elsif model.db_schema["#{n2}_ids".to_sym]
|
86
|
+
return where Sequel.lit '%i=any(%s_ids)' % [obj.id, n2]
|
87
|
+
elsif model.db_schema[field_name]
|
88
|
+
return where Sequel.lit '%s=%i' % [field_name, obj.id]
|
89
|
+
elsif model.db_schema[:model_type]
|
90
|
+
return where(:model_type=>obj.class.to_s, :model_id=>obj.id)
|
91
|
+
elsif obj.class.to_s == 'User'
|
92
|
+
if obj.respond_to?(field_name)
|
93
|
+
return where Sequel.lit '%s=?' % [field_name, obj.id]
|
94
|
+
end
|
95
|
+
return where Sequel.lit 'created_by=%i' % obj.id
|
96
|
+
else
|
97
|
+
r "Unknown link for #{obj.class} (probably missing db field)"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Sequel::Plugins::FilterWrappers
|
2
|
+
module ClassMethods
|
3
|
+
|
4
|
+
def validate &block
|
5
|
+
define_method :validate do
|
6
|
+
block.call
|
7
|
+
super
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def before_save &block
|
12
|
+
define_method :before_save do
|
13
|
+
block.call
|
14
|
+
super
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
Sequel::Model.plugin :filter_wrappers
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# @notes.preload(:bucket)
|
2
|
+
|
3
|
+
# class Array
|
4
|
+
# def preload(name)
|
5
|
+
# field = "#{name.to_s.singularize}_id".to_sym
|
6
|
+
# ids = self.map{ |o| o[field] }.uniq
|
7
|
+
# buckets = name.to_s.classify.constantize.where(id:ids).to_a
|
8
|
+
|
9
|
+
# for o in self
|
10
|
+
# o.send "#{name}=", buckets.select{ |el| o.id==el.id }[0]
|
11
|
+
# end
|
12
|
+
# end
|
13
|
+
# end
|
14
|
+
|
15
|
+
module Sequel::Plugins::LuxLink
|
16
|
+
module ClassMethods
|
17
|
+
|
18
|
+
# link :genders, default:1, collection:[ [1, 'male'], [2, 'Female'] ]
|
19
|
+
# link :genders, collection: { 1=>'male', 2=>'Female' }
|
20
|
+
# Object.genders
|
21
|
+
# @object.gender
|
22
|
+
def link(name, opts={})
|
23
|
+
name_s = name.to_s.singularize
|
24
|
+
name_p = name.to_s.pluralize
|
25
|
+
|
26
|
+
if opts[:collection]
|
27
|
+
field = opts[:field] || "#{name_s}_id"
|
28
|
+
|
29
|
+
class_eval %[
|
30
|
+
def #{to_s}.#{name_p}
|
31
|
+
#{opts[:collection].to_json}
|
32
|
+
end
|
33
|
+
|
34
|
+
def #{name_s}
|
35
|
+
val = self[:#{field}] || #{opts[:default] || 'nil'}
|
36
|
+
return unless val
|
37
|
+
for k, v in #{to_s}.#{name_p}
|
38
|
+
return v if k == val
|
39
|
+
end
|
40
|
+
nil
|
41
|
+
end
|
42
|
+
]
|
43
|
+
return
|
44
|
+
end
|
45
|
+
|
46
|
+
klass = opts[:class] ? opts[:class].to_s : name.to_s.singularize.classify
|
47
|
+
|
48
|
+
# link :country, class:Country -> many_to_one :country
|
49
|
+
if name.to_s == name_s
|
50
|
+
class_eval %[
|
51
|
+
def #{name_s}
|
52
|
+
@#{name_s}_cached ||= #{klass}.find(#{name_s}_id)
|
53
|
+
end
|
54
|
+
def #{name_s}=(object)
|
55
|
+
@#{name_s}_cached = object
|
56
|
+
end
|
57
|
+
]
|
58
|
+
|
59
|
+
# link :cities
|
60
|
+
# postgre integer array, has to be in form #{name.singularize}_ids
|
61
|
+
# city_ids = [1,2,4]
|
62
|
+
# cities -> [<City:1>, <City:2>, <City:4>]
|
63
|
+
elsif new.respond_to?("#{name_s}_ids")
|
64
|
+
# puts "* #{to_s}.link :#{name} -> inline #{name_s}_ids".yellow
|
65
|
+
class_eval %[
|
66
|
+
def #{name_p}
|
67
|
+
return [] if #{name_s}_ids.blank?
|
68
|
+
ids = #{name_s}_ids.join(',')
|
69
|
+
#{klass}.where(Sequel.lit('id in ('+ids+')'))
|
70
|
+
end
|
71
|
+
]
|
72
|
+
|
73
|
+
# link :countries -> one_to_many :countries
|
74
|
+
else
|
75
|
+
# one_to_many name, opts
|
76
|
+
field = "#{to_s.tableize.singularize}_id"
|
77
|
+
if klass.constantize.db_schema[field.to_sym]
|
78
|
+
comm = "#{klass}.where(#{field}:id).default"
|
79
|
+
else
|
80
|
+
# we have a link table
|
81
|
+
cname = klass[0,1] > to_s[0,1] ? "#{to_s}#{klass}" : "#{klass}#{to_s}"
|
82
|
+
comm = "#{klass}.xwhere('id in (select #{klass.tableize.singularize}_id from #{cname.tableize} where #{to_s.tableize.singularize}_id=?)', id)"
|
83
|
+
puts "* #{to_s}.link :#{name} -> #{comm}"
|
84
|
+
end
|
85
|
+
class_eval %[
|
86
|
+
def #{name_p}
|
87
|
+
#{comm}
|
88
|
+
end
|
89
|
+
]
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
Sequel::Model.plugin :lux_link
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Sequel::Plugins::LuxLocalize
|
2
|
+
module ClassMethods
|
3
|
+
# in any modal
|
4
|
+
# localize :name
|
5
|
+
# to make :name multilang
|
6
|
+
# and to create :name_en, :name_de, ...
|
7
|
+
def localize(name)
|
8
|
+
unless db_schema[name]
|
9
|
+
puts "Field [:#{name}] does not exist in #{self.to_s}".red
|
10
|
+
end
|
11
|
+
|
12
|
+
unless (db_schema[name][:db_type] rescue nil) == 'jsonb'
|
13
|
+
puts "Field [:#{name}] in #{self.to_s} is not of type [jsonb]".red
|
14
|
+
end
|
15
|
+
|
16
|
+
class_eval %[
|
17
|
+
def #{name}(locale=nil)
|
18
|
+
field = self[:#{name}]
|
19
|
+
field ||= {}
|
20
|
+
locale ||= Locale.current
|
21
|
+
return field[locale] if field[locale] && !field[locale].start_with?('?')
|
22
|
+
val = field[Locale::DEFAULT].to_s
|
23
|
+
Lux.dev? ? '?'+val : val
|
24
|
+
end
|
25
|
+
|
26
|
+
def #{name}=(value)
|
27
|
+
self[:#{name}] ||= {} # if self[:#{name}].class.to_s != 'Hash'
|
28
|
+
self[:#{name}][Locale.current] = value
|
29
|
+
end
|
30
|
+
]
|
31
|
+
|
32
|
+
for lang in Locale.all
|
33
|
+
class_eval %[
|
34
|
+
def #{name}_#{lang}
|
35
|
+
#{name}('#{lang}')
|
36
|
+
end
|
37
|
+
|
38
|
+
def #{name}_#{lang}=(value)
|
39
|
+
value = nil if value.start_with?('?')
|
40
|
+
self[:#{name}] ||= {}
|
41
|
+
self[:#{name}]['#{lang}'] = value
|
42
|
+
end
|
43
|
+
]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
module InstanceMethods
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
def DatasetMethods
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
Sequel::Model.plugin :lux_localize
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# define composite key and check before save
|
2
|
+
# class OrgUser < ApplicationModel
|
3
|
+
# primary_keys :org_id, :user_id
|
4
|
+
# end
|
5
|
+
|
6
|
+
module Sequel::Plugins::PrimaryKeys
|
7
|
+
module ClassMethods
|
8
|
+
def primary_keys(*args)
|
9
|
+
unless args[0]
|
10
|
+
return respond_to?(:_primary_keys) ? _primary_keys : [:id]
|
11
|
+
end
|
12
|
+
|
13
|
+
define_singleton_method(:_primary_keys) { args }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
module InstanceMethods
|
18
|
+
def before_save
|
19
|
+
klass = self.class
|
20
|
+
|
21
|
+
if klass.respond_to?(:_primary_keys)
|
22
|
+
check = klass._primary_keys.inject(klass.dataset) do |record, field|
|
23
|
+
record = record.where("#{field}=?", send(field))
|
24
|
+
end
|
25
|
+
|
26
|
+
check = check.xwhere('id<>?', id) if self[:id]
|
27
|
+
|
28
|
+
raise StandardError, 'Record allredy exists (primary_keys check)' if check.first
|
29
|
+
end
|
30
|
+
|
31
|
+
super
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
Sequel::Model.plugin :primary_keys
|