arql 0.3.29 → 0.3.30

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.
@@ -0,0 +1,216 @@
1
+ * 定义快速按时间查询的便利方法
2
+
3
+ ** 问题
4
+
5
+ 对于按照时间范围查询的需求,一般需要构造一个表示时间范围的 Range 对象,例如:
6
+
7
+ #+BEGIN_SRC ruby
8
+ Student.where(created_at: Time.now.beginning_of_day..Time.now.end_of_day)
9
+ #+END_SRC
10
+
11
+ 或者
12
+
13
+ #+BEGIN_SRC ruby
14
+ Student.where(created_at: Time.new(2016, 1, 1)..Time.new(2016, 12, 31))
15
+ #+END_SRC
16
+
17
+ ** 定义一个便利方法
18
+
19
+ 为了简化构造时间 Range 对象的过程,我们可以定义一个便利方法,例如:
20
+
21
+ 创建一个文件 =~/.arql.d/date_range.rb= ,内容如下:
22
+
23
+ #+BEGIN_SRC ruby
24
+ module Kernel
25
+
26
+ # == Example:
27
+ # Range
28
+ # 1. -3..0
29
+ # 2. '27'..'29'
30
+ # 3. '04-01'..'04-10'
31
+ # 4. '2021-04-01'..'2021-04-10'
32
+ # Array
33
+ # 1. [nil, nil] or [] => 1970-01-01 ~ 1000 days later from now
34
+ # 2. [:yday, :today] or [:yesterday, :today]
35
+ # 3. [-10.months, :today]
36
+ # Others
37
+ # 1. Time.now or Date.today
38
+ # 2. :now or :today
39
+ # 3. :yesterday or :yday
40
+ # 4. -2
41
+ # 5. -2.months
42
+ def dates_range(dates)
43
+ dates = :yesterday if dates == :yday
44
+ if dates.is_a?(Range)
45
+ s = if dates.begin.is_a?(Integer)
46
+ (Time.now+dates.begin.days).beginning_of_day
47
+ elsif dates.begin.is_a?(String) && dates.begin =~ /^\d{4}-\d{2}-\d{2}$/
48
+ Time.parse(dates.begin).beginning_of_day
49
+ elsif dates.begin.is_a?(String) && dates.begin =~ /^\d{2}-\d{2}$/
50
+ Time.strptime(dates.begin, '%m-%d').beginning_of_day
51
+ elsif dates.begin.is_a?(String) && dates.begin =~ /^\d{2}$/
52
+ Time.strptime(dates.begin, '%d').beginning_of_day
53
+ else
54
+ dates.begin
55
+ end
56
+ e = if dates.end.is_a?(Integer)
57
+ (Time.now+dates.end.days).end_of_day
58
+ elsif dates.end.is_a?(String) && dates.end =~ /^\d{4}-\d{2}-\d{2}$/
59
+ Time.parse(dates.end).end_of_day
60
+ elsif dates.end.is_a?(String) && dates.end =~ /^\d{2}-\d{2}$/
61
+ Time.strptime(dates.end, '%m-%d').end_of_day
62
+ elsif dates.end.is_a?(String) && dates.end =~ /^\d{2}$/
63
+ Time.strptime(dates.end, '%d').end_of_day
64
+ else
65
+ dates.end
66
+ end
67
+ s..e
68
+ elsif dates.is_a?(Array)
69
+ if dates.size == 2
70
+ s = dates.first || Date.new(1970, 1, 1)
71
+ s = if s.is_a?(Time) || s.is_a?(Date)
72
+ s.beginning_of_day
73
+ elsif s == :now
74
+ Time.now.beginning_of_day
75
+ elsif s == :today
76
+ Date.today.beginning_of_day
77
+ elsif s == :yesterday || s == :yday
78
+ Date.yesterday.beginning_of_day
79
+ elsif s.in?(Time.instance_methods)
80
+ Time.now.send(s).beginning_of_day
81
+ elsif s.is_a?(ActiveSupport::Duration)
82
+ (Time.now+s).beginning_of_day
83
+ elsif s.is_a?(Integer)
84
+ (Time.now+s.days).beginning_of_day
85
+ else
86
+ raise "Not supported s: #{s}"
87
+ end
88
+ e = dates.last || Date.today + 1000.days
89
+ e = if e.is_a?(Time) || e.is_a?(Date)
90
+ e.end_of_day
91
+ elsif e == :now
92
+ Time.now.end_of_day
93
+ elsif e == :today
94
+ Date.today.end_of_day
95
+ elsif e == :yesterday || e == :yday
96
+ Date.yesterday.end_of_day
97
+ elsif e.in?(Time.instance_methods)
98
+ Time.now.send(e).end_of_day
99
+ elsif e.is_a?(ActiveSupport::Duration)
100
+ (Time.now+e).end_of_day
101
+ elsif e.is_a?(Integer)
102
+ (Time.now+e.days).beginning_of_day
103
+ else
104
+ raise "Not supported e: #{e}"
105
+ end
106
+ return s..e
107
+ else
108
+ times = dates.map do |date|
109
+ if date.nil?
110
+ nil
111
+ elsif date.is_a?(Time)
112
+ date
113
+ elsif date == :now
114
+ Time.now
115
+ elsif date.in?(Time.instance_methods)
116
+ Time.now.send(date)
117
+ elsif date.is_a?(ActiveSupport::Duration)
118
+ Time.now+date
119
+ elsif date.is_a?(Integer)
120
+ (Time.now+date.days).beginning_of_day
121
+ else
122
+ raise "Not supported date: #{date}"
123
+ end
124
+ end
125
+ s = times.first || Time.new(1970, 1, 1, 0, 0, 0)
126
+ e = times.last || Time.now + 1000.days
127
+ return s..e
128
+ end
129
+ else
130
+ if dates.is_a?(Time) or dates.is_a?(Date)
131
+ dates = dates.beginning_of_day..dates.end_of_day
132
+ elsif dates == :now
133
+ dates = Time.now.beginning_of_day..Time.now.end_of_day
134
+ elsif dates == :today
135
+ dates = Date.today.beginning_of_day..Date.today.end_of_day
136
+ elsif dates == :yday || dates == :yesterday
137
+ dates = Date.yesterday.beginning_of_day..Date.yesterday.end_of_day
138
+ elsif dates.in?(Time.instance_methods)
139
+ dates = Time.now.send(dates).beginning_of_day..Time.now.send(dates).end_of_day
140
+ elsif dates.is_a?(ActiveSupport::Duration)
141
+ dates = (Time.now+dates).beginning_of_day..(Time.now+dates).end_of_day
142
+ elsif dates.is_a?(Integer)
143
+ (Time.now+dates.days).beginning_of_day..(Time.now+dates.days).end_of_day
144
+ else
145
+ raise "Not supported dates: #{dates}"
146
+ end
147
+ end
148
+ end
149
+
150
+ alias_method :dates, :dates_range
151
+ end
152
+
153
+ class ::ArqlModel
154
+
155
+ class << self
156
+ def ts_attribute_for_create
157
+ (timestamp_attributes_for_create||[]).find { |e| e.in?(column_names) }
158
+ end
159
+
160
+ def ts_attribute_for_update
161
+ (timestamp_attributes_for_update||[]).find { |e| e.in?(column_names) }
162
+ end
163
+
164
+
165
+ def created_on(dates)
166
+ attr = ts_attribute_for_create
167
+ raise 'No attrtibute for create defined' unless attr
168
+ where(attr => dates_range(dates))
169
+ end
170
+
171
+ alias on created_on
172
+
173
+ def today
174
+ created_on(0)
175
+ end
176
+
177
+ def modified_on(dates)
178
+ attr = ts_attribute_for_update
179
+ raise 'No attrtibute for update defined' unless attr
180
+ where(attr: dates_range(dates))
181
+ end
182
+ end
183
+ end
184
+ #+END_SRC
185
+
186
+ 然后在 =~/.arql.d/init.rb= 中引入这个文件:
187
+
188
+ #+BEGIN_SRC ruby
189
+ load(File.absolute_path(File.dirname(__FILE__) + "/date_range.rb"))
190
+ #+END_SRC
191
+
192
+
193
+ ** 使用方法
194
+
195
+ 然后就可以使用这个方法了:
196
+
197
+ #+BEGIN_SRC ruby
198
+ Student.where(created_at: dates(0)). # 查询今天创建的
199
+ Student.where(created_at: dates(:today)). # 查询今天创建的
200
+ Student.where(created_at: dates('2016-01-01'..'2016-01-31')) # 查询 2016 年 1 月创建的
201
+ Student.where(created_at: dates('01'..'10')) # 查询当月 1-10 号创建的
202
+ Student.where(created_at: dates('03-01'..'04-10')) # 查询当年 3 月 1 日到 4 月 10 日创建的
203
+ Student.where(created_at: dates(-20..-1)) # 查询 20 天前到昨天创建的
204
+ #+END_SRC
205
+
206
+ 如果是对 created_at 字段 (在 =init.yaml= 中通过 =created_at= 配置,默认值是 =created_at=) 进行查询, 可以直接使用:
207
+
208
+ #+BEGIN_SRC ruby
209
+ Student.on(0). # 查询今天创建的
210
+ Student.on(:today). # 查询今天创建的
211
+ Student.on('2016-01-01'..'2016-01-31') # 查询 2016 年 1 月创建的
212
+ Student.on('01'..'10') # 查询当月 1-10 号创建的
213
+ Student.on('03-01'..'04-10') # 查询当年 3 月 1 日到 4 月 10 日创建的
214
+ Student.on(-20..-1) # 查询 20 天前到昨天创建的
215
+ #+END_SRC
216
+
@@ -0,0 +1,218 @@
1
+ * Define helper function to create datetime range objects
2
+
3
+ ** Problem
4
+
5
+ When we need to query records within a time range, we need to construct a Range object representing the time range, for example:
6
+
7
+ #+BEGIN_SRC ruby
8
+ Student.where(created_at: Time.now.beginning_of_day..Time.now.end_of_day)
9
+ #+END_SRC
10
+
11
+ or
12
+
13
+ #+BEGIN_SRC ruby
14
+ Student.where(created_at: Time.new(2016, 1, 1)..Time.new(2016, 12, 31))
15
+ #+END_SRC
16
+
17
+ ** Define a helper function
18
+
19
+ To simplify the process of constructing a time Range object, we can define a helper function, for example:
20
+
21
+ Create a file =~/.arql.d/date_range.rb= with the following content:
22
+
23
+ #+BEGIN_SRC ruby
24
+ module Kernel
25
+
26
+ # == Example:
27
+ # Range
28
+ # 1. -3..0
29
+ # 2. '27'..'29'
30
+ # 3. '04-01'..'04-10'
31
+ # 4. '2021-04-01'..'2021-04-10'
32
+ # Array
33
+ # 1. [nil, nil] or [] => 1970-01-01 ~ 1000 days later from now
34
+ # 2. [:yday, :today] or [:yesterday, :today]
35
+ # 3. [-10.months, :today]
36
+ # Others
37
+ # 1. Time.now or Date.today
38
+ # 2. :now or :today
39
+ # 3. :yesterday or :yday
40
+ # 4. -2
41
+ # 5. -2.months
42
+ def dates_range(dates)
43
+ dates = :yesterday if dates == :yday
44
+ if dates.is_a?(Range)
45
+ s = if dates.begin.is_a?(Integer)
46
+ (Time.now+dates.begin.days).beginning_of_day
47
+ elsif dates.begin.is_a?(String) && dates.begin =~ /^\d{4}-\d{2}-\d{2}$/
48
+ Time.parse(dates.begin).beginning_of_day
49
+ elsif dates.begin.is_a?(String) && dates.begin =~ /^\d{2}-\d{2}$/
50
+ Time.strptime(dates.begin, '%m-%d').beginning_of_day
51
+ elsif dates.begin.is_a?(String) && dates.begin =~ /^\d{2}$/
52
+ Time.strptime(dates.begin, '%d').beginning_of_day
53
+ else
54
+ dates.begin
55
+ end
56
+ e = if dates.end.is_a?(Integer)
57
+ (Time.now+dates.end.days).end_of_day
58
+ elsif dates.end.is_a?(String) && dates.end =~ /^\d{4}-\d{2}-\d{2}$/
59
+ Time.parse(dates.end).end_of_day
60
+ elsif dates.end.is_a?(String) && dates.end =~ /^\d{2}-\d{2}$/
61
+ Time.strptime(dates.end, '%m-%d').end_of_day
62
+ elsif dates.end.is_a?(String) && dates.end =~ /^\d{2}$/
63
+ Time.strptime(dates.end, '%d').end_of_day
64
+ else
65
+ dates.end
66
+ end
67
+ s..e
68
+ elsif dates.is_a?(Array)
69
+ if dates.size == 2
70
+ s = dates.first || Date.new(1970, 1, 1)
71
+ s = if s.is_a?(Time) || s.is_a?(Date)
72
+ s.beginning_of_day
73
+ elsif s == :now
74
+ Time.now.beginning_of_day
75
+ elsif s == :today
76
+ Date.today.beginning_of_day
77
+ elsif s == :yesterday || s == :yday
78
+ Date.yesterday.beginning_of_day
79
+ elsif s.in?(Time.instance_methods)
80
+ Time.now.send(s).beginning_of_day
81
+ elsif s.is_a?(ActiveSupport::Duration)
82
+ (Time.now+s).beginning_of_day
83
+ elsif s.is_a?(Integer)
84
+ (Time.now+s.days).beginning_of_day
85
+ else
86
+ raise "Not supported s: #{s}"
87
+ end
88
+ e = dates.last || Date.today + 1000.days
89
+ e = if e.is_a?(Time) || e.is_a?(Date)
90
+ e.end_of_day
91
+ elsif e == :now
92
+ Time.now.end_of_day
93
+ elsif e == :today
94
+ Date.today.end_of_day
95
+ elsif e == :yesterday || e == :yday
96
+ Date.yesterday.end_of_day
97
+ elsif e.in?(Time.instance_methods)
98
+ Time.now.send(e).end_of_day
99
+ elsif e.is_a?(ActiveSupport::Duration)
100
+ (Time.now+e).end_of_day
101
+ elsif e.is_a?(Integer)
102
+ (Time.now+e.days).beginning_of_day
103
+ else
104
+ raise "Not supported e: #{e}"
105
+ end
106
+ return s..e
107
+ else
108
+ times = dates.map do |date|
109
+ if date.nil?
110
+ nil
111
+ elsif date.is_a?(Time)
112
+ date
113
+ elsif date == :now
114
+ Time.now
115
+ elsif date.in?(Time.instance_methods)
116
+ Time.now.send(date)
117
+ elsif date.is_a?(ActiveSupport::Duration)
118
+ Time.now+date
119
+ elsif date.is_a?(Integer)
120
+ (Time.now+date.days).beginning_of_day
121
+ else
122
+ raise "Not supported date: #{date}"
123
+ end
124
+ end
125
+ s = times.first || Time.new(1970, 1, 1, 0, 0, 0)
126
+ e = times.last || Time.now + 1000.days
127
+ return s..e
128
+ end
129
+ else
130
+ if dates.is_a?(Time) or dates.is_a?(Date)
131
+ dates = dates.beginning_of_day..dates.end_of_day
132
+ elsif dates == :now
133
+ dates = Time.now.beginning_of_day..Time.now.end_of_day
134
+ elsif dates == :today
135
+ dates = Date.today.beginning_of_day..Date.today.end_of_day
136
+ elsif dates == :yday || dates == :yesterday
137
+ dates = Date.yesterday.beginning_of_day..Date.yesterday.end_of_day
138
+ elsif dates.in?(Time.instance_methods)
139
+ dates = Time.now.send(dates).beginning_of_day..Time.now.send(dates).end_of_day
140
+ elsif dates.is_a?(ActiveSupport::Duration)
141
+ dates = (Time.now+dates).beginning_of_day..(Time.now+dates).end_of_day
142
+ elsif dates.is_a?(Integer)
143
+ (Time.now+dates.days).beginning_of_day..(Time.now+dates.days).end_of_day
144
+ else
145
+ raise "Not supported dates: #{dates}"
146
+ end
147
+ end
148
+ end
149
+
150
+ alias_method :dates, :dates_range
151
+ end
152
+
153
+ class ::ArqlModel
154
+
155
+ class << self
156
+ def ts_attribute_for_create
157
+ (timestamp_attributes_for_create||[]).find { |e| e.in?(column_names) }
158
+ end
159
+
160
+ def ts_attribute_for_update
161
+ (timestamp_attributes_for_update||[]).find { |e| e.in?(column_names) }
162
+ end
163
+
164
+
165
+ def created_on(dates)
166
+ attr = ts_attribute_for_create
167
+ raise 'No attrtibute for create defined' unless attr
168
+ where(attr => dates_range(dates))
169
+ end
170
+
171
+ alias on created_on
172
+
173
+ def today
174
+ created_on(0)
175
+ end
176
+
177
+ def modified_on(dates)
178
+ attr = ts_attribute_for_update
179
+ raise 'No attrtibute for update defined' unless attr
180
+ where(attr: dates_range(dates))
181
+ end
182
+ end
183
+ end
184
+ #+END_SRC
185
+
186
+
187
+ Then include this file in =~/.arql.d/init.rb=:
188
+
189
+ #+BEGIN_SRC ruby
190
+ load(File.absolute_path(File.dirname(__FILE__) + "/date_range.rb"))
191
+ #+END_SRC
192
+
193
+
194
+ ** Usage
195
+
196
+ Then you can use this method:
197
+
198
+ #+BEGIN_SRC ruby
199
+ Student.where(created_at: dates(0)). # Query records created today
200
+ Student.where(created_at: dates(:today)). # Query records created today
201
+ Student.where(created_at: dates('2016-01-01'..'2016-01-31')) # Query records created in January 2016
202
+ Student.where(created_at: dates('01'..'10')) # Query records created on the 1st to the 10th of the current month
203
+ Student.where(created_at: dates('03-01'..'04-10')) # Query records created from March 1st to April 10th of the current year
204
+ Student.where(created_at: dates(-20..-1)) # Query records created 20 days ago to yesterday
205
+ #+END_SRC
206
+
207
+ If you are querying the =created_at= field (configured in =init.yaml= with =created_at=, the default value is =created_at=), you can use:
208
+
209
+ #+BEGIN_SRC ruby
210
+ Student.on(0). # Query records created today
211
+ Student.on(:today). # Query records created today
212
+ Student.on('2016-01-01'..'2016-01-31') # Query records created in January 2016
213
+ Student.on('01'..'10') # Query records created on the 1st to the 10th of the current month
214
+ Student.on('03-01'..'04-10') # Query records created from March 1st to April 10th of the current year
215
+ Student.on(-20..-1) # Query records created 20 days ago to yesterday
216
+ #+END_SRC
217
+
218
+
@@ -0,0 +1,33 @@
1
+ * 将不同环境的初始化代码放在不同的文件中
2
+
3
+ 配置文件中往往有多个数据库的多个环境配置,这时候可以使用这里的方法,将不同环境的初始化代码放在不同的文件中来避免冲突。
4
+
5
+ 假设配置文件中配置了 4 个数据库环境:
6
+
7
+ + apollo.dev
8
+ + apollo.prod
9
+ + space.dev
10
+ + space.prod
11
+
12
+ 那么可以在 =~/.arql.d/= 目录下创建以下文件:
13
+
14
+ + apollo.rb
15
+ + space.rb
16
+
17
+ 在 =apollo.rb= 文件中放置 apollo 项目的初始化代码; 在 =space.rb= 文件中放置 space 项目的初始化代码。
18
+
19
+ 然后在 =~/.arql.d/init.eb= 文件中写入以下代码:
20
+
21
+ #+BEGIN_SRC ruby
22
+ ["apollo", "space"].each do |project|
23
+ if Arql::App.env.try { |e| e.include?(project + ".") }
24
+ load(File.absolute_path(File.dirname(__FILE__) + "/#{project}.rb"))
25
+ break
26
+ end
27
+ end
28
+ #+END_SRC
29
+
30
+ 这样,当执行 =arql -e apollo.dev= 或 =arql =e apollo.prod= 时,就会加载 =apollo.rb= 文件中的初始化代码;当执行 =arql
31
+ -e space.dev= 或 =arql -e space.prod= 时,就会加载 =space.rb= 文件中的初始化代码。
32
+
33
+
@@ -0,0 +1,31 @@
1
+ * Place your initialization code in a file named after the environment
2
+
3
+ If you have multiple environments in your configuration file, you can place the initialization code for each environment in a separate file to avoid conflicts.
4
+
5
+ Suppose you have 4 database environments in your configuration file:
6
+
7
+ + apollo.dev
8
+ + apollo.prod
9
+ + space.dev
10
+ + space.prod
11
+
12
+ You can create the following files in the =~/.arql.d/= directory:
13
+
14
+ + apollo.rb
15
+ + space.rb
16
+
17
+ Place the initialization code for the apollo project in the =apollo.rb= file; place the initialization code for the space project in the =space.rb= file.
18
+
19
+ Then write the following code in the =~/.arql.d/init.eb= file:
20
+
21
+ #+BEGIN_SRC ruby
22
+ ["apollo", "space"].each do |project|
23
+ if Arql::App.env.try { |e| e.include?(project + ".") }
24
+ load(File.absolute_path(File.dirname(__FILE__) + "/#{project}.rb"))
25
+ break
26
+ end
27
+ end
28
+ #+END_SRC
29
+
30
+ Now, when you run =arql -e apollo.dev= or =arql =e apollo.prod=, the initialization code in the =apollo.rb= file will be loaded; when you run =arql -e space.dev= or =arql -e space.prod=, the initialization code in the =space.rb= file will be loaded.
31
+
data/lib/arql/cli.rb CHANGED
@@ -36,7 +36,7 @@ module Arql
36
36
  @options.env = env
37
37
  end
38
38
 
39
- opts.on('-aDB_ADAPTER', '--db-adapter=DB_ADAPTER', 'Specify database Adapter, default is mysql2') do |db_adapter|
39
+ opts.on('-aDB_ADAPTER', '--db-adapter=DB_ADAPTER', 'Specify database Adapter, default is sqlite3') do |db_adapter|
40
40
  @options.adapter = db_adapter
41
41
  end
42
42
 
@@ -119,7 +119,11 @@ module Arql
119
119
  tables.each do |table_name|
120
120
  table_comment = comments[table_name]
121
121
  primary_keys[table_name].tap do |pkey|
122
- table_name.send(@@classify_method).tap do |const_name|
122
+ table_name_prefixes = options[:table_name_prefixes] || []
123
+ normalized_table_name = table_name_prefixes.each_with_object(table_name.dup) do |prefix, name|
124
+ name.sub!(/^#{prefix}/, '')
125
+ end
126
+ normalized_table_name.send(@@classify_method).tap do |const_name|
123
127
  const_name = 'Modul' if const_name == 'Module'
124
128
  const_name = 'Clazz' if const_name == 'Class'
125
129
  Class.new(::ArqlModel) do
@@ -213,7 +217,11 @@ module Arql
213
217
  tables.each do |table_name|
214
218
  table_comment = comments[table_name]
215
219
  primary_keys[table_name].tap do |pkey|
216
- table_name.send(@@classify_method).tap do |const_name|
220
+ table_name_prefixes = options[:table_name_prefixes] || []
221
+ normalized_table_name = table_name_prefixes.each_with_object(table_name.dup) do |prefix, name|
222
+ name.sub!(/^#{prefix}/, '')
223
+ end
224
+ normalized_table_name.send(@@classify_method).tap do |const_name|
217
225
  const_name = 'Modul' if const_name == 'Module'
218
226
  const_name = 'Clazz' if const_name == 'Class'
219
227
  if const_name !~ /^[A-Z][A-Za-z0-9_]*$/
@@ -359,4 +367,4 @@ module Arql
359
367
  end
360
368
  end
361
369
  end
362
- end
370
+ end
data/lib/arql/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Arql
2
- VERSION = "0.3.29"
2
+ VERSION = "0.3.30"
3
3
  end