arql 0.3.29 → 0.3.30
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README-zh_CN.org +1096 -0
- data/README.org +1170 -0
- data/auto-set-id-before-save-zh_CN.org +35 -0
- data/auto-set-id-before-save.org +33 -0
- data/custom-configurations-zh_CN.org +50 -0
- data/custom-configurations.org +54 -0
- data/define-associations-zh_CN.org +38 -0
- data/define-associations.org +37 -0
- data/fuzzy-field-query-zh_CN.org +165 -0
- data/fuzzy-field-query.org +165 -0
- data/helper-for-datetime-range-query-zh_CN.org +216 -0
- data/helper-for-datetime-range-query.org +218 -0
- data/initializer-structure-zh_CN.org +33 -0
- data/initializer-structure.org +31 -0
- data/lib/arql/cli.rb +1 -1
- data/lib/arql/definition.rb +11 -3
- data/lib/arql/version.rb +1 -1
- data/oss-files-zh_CN.org +161 -0
- data/oss-files.org +163 -0
- data/sql-log-zh_CN.org +55 -0
- data/sql-log.org +55 -0
- metadata +20 -3
- data/README.md +0 -456
data/README-zh_CN.org
ADDED
@@ -0,0 +1,1096 @@
|
|
1
|
+
* Arql
|
2
|
+
|
3
|
+
Arql是一个简单的工具性 Gem,它将 Rails ActiveRecord 和 Pry 结合在一起,并添加了有用的 Pry 命令。它可以根据数据库表的信
|
4
|
+
息自动定义模型类。如果你是 Ruby 用户,你可以将这个 Arql 用作你的数据库查询工具。
|
5
|
+
|
6
|
+
** 依赖
|
7
|
+
|
8
|
+
+ Ruby 2.6.0 或更高版本
|
9
|
+
+ 对于不同类型的数据库,需要安装相应的数据库适配器或客户端二进制库:
|
10
|
+
- MySQL: 根据你的操作系统,你可能需要安装: =libmariadb-dev= 、 =libmysqlclient-dev= 、 =mysql-devel=
|
11
|
+
=default-libmysqlclient-dev= ; 请参阅发行版的软件包指南以查找特定的软件包;或者参考 [[https://github.com/brianmario/mysql2][mysql2 的文档]]
|
12
|
+
- SQLite3: 不需要安装任何额外的库
|
13
|
+
- PostgreSQL: ~gem install pg~
|
14
|
+
- Oracle: ~gem install activerecord-oracle_enhanced-adapter~
|
15
|
+
- SQL Server: ~gem install activerecord-sqlserver-adapter~
|
16
|
+
|
17
|
+
** 安装
|
18
|
+
|
19
|
+
执行:
|
20
|
+
|
21
|
+
#+begin_example
|
22
|
+
$ gem install arql
|
23
|
+
#+end_example
|
24
|
+
|
25
|
+
如果遇到系统权限问题,请尝试使用 sudo:
|
26
|
+
|
27
|
+
#+begin_example
|
28
|
+
$ sudo gem install arql
|
29
|
+
#+end_example
|
30
|
+
|
31
|
+
** 使用方法
|
32
|
+
|
33
|
+
*** 命令行选项
|
34
|
+
|
35
|
+
#+begin_example
|
36
|
+
Usage: arql [options] [ruby file]
|
37
|
+
|
38
|
+
如果既没有指定 [ruby file] 也没有指定 -E 选项,并且 STDIN 是一个 tty,将启动 Pry REPL,
|
39
|
+
否则将运行指定的 ruby file 或 -E 选项值或从 STDIN 读取的 ruby 代码,并且不会启动 REPL
|
40
|
+
|
41
|
+
-c, --conf=CONFIG_FILE 指定配置文件,默认为 $HOME/.arql.yml 或 $HOME/.arql.d/init.yml
|
42
|
+
-i, --initializer=INITIALIZER 指定初始化 Ruby 文件,默认为 $HOME/.arql.rb 或 $HOME/.arql.d/init.rb
|
43
|
+
-e, --env=ENVIRON 指定配置环境
|
44
|
+
-a, --db-adapter=DB_ADAPTER 指定数据库适配器,默认为 sqlite3
|
45
|
+
-h, --db-host=DB_HOST 指定数据库主机
|
46
|
+
-p, --db-port=DB_PORT 指定数据库端口
|
47
|
+
-d, --db-name=DB_NAME 指定数据库名称
|
48
|
+
-u, --db-user=DB_USER 指定数据库用户
|
49
|
+
-P, --db-password=DB_PASSWORD 指定数据库密码
|
50
|
+
-n, --db-encoding=DB_ENCODING 指定数据库编码,默认为 utf8
|
51
|
+
-o, --db-pool=DB_POOL 指定数据库连接池大小,默认为 5
|
52
|
+
-H, --ssh-host=SSH_HOST 指定 SSH 主机
|
53
|
+
-O, --ssh-port=SSH_PORT 指定 SSH 端口
|
54
|
+
-U, --ssh-user=SSH_USER 指定 SSH 用户
|
55
|
+
-W, --ssh-password=SSH_PASSWORD 指定 SSH 密码
|
56
|
+
-L, --ssh-local-port=SSH_LOCAL_PORT 指定本地 SSH 代理端口
|
57
|
+
-E, --eval=CODE 执行代码
|
58
|
+
-S, --show-sql 在 STDOUT 上显示 SQL
|
59
|
+
-w, --write-sql=OUTPUT 将 SQL 写入 OUTPUT 文件
|
60
|
+
-A, --append-sql=OUTPUT 将 SQL 追加到 OUTPUT 文件
|
61
|
+
--help 打印帮助信息
|
62
|
+
#+end_example
|
63
|
+
|
64
|
+
**** =-c, --config=CONFIG_FILE=
|
65
|
+
|
66
|
+
指定配置文件位置,默认为 =$HOME/.arql.yml= 或 =$HOME/.arql.d/init.yml= 。 配置文件通常与 Rails数据库配置文件相同,
|
67
|
+
但有一些额外的配置选项,例如 =ssh= 选项等。 参考 =配置文件= 部分。
|
68
|
+
|
69
|
+
**** =-i, --initializer=INITIALIZER=
|
70
|
+
|
71
|
+
指定一个 Ruby 源文件,Arql 定义 ActiveRecord 模型类之后执行此文件的代码,默认为 =$HOME/.arql.rb= 或者
|
72
|
+
=$HOME/.arql.d/init.rb= 。你可以在这个文件中为 ActiveRecord 模型类添加方法和关联关系定义。
|
73
|
+
|
74
|
+
**** =-e, --env=ENVIRON=
|
75
|
+
|
76
|
+
指定一个在配置文件中的环境名称。
|
77
|
+
|
78
|
+
**** =-E, --eval=CODE=
|
79
|
+
|
80
|
+
指定一个 Ruby 代码片段,如果指定了此选项,将不会启动 Pry REPL。
|
81
|
+
|
82
|
+
**** =-S, --show-sql=
|
83
|
+
|
84
|
+
arql 默认不显示 SQL 日志,使用此选项打开。
|
85
|
+
|
86
|
+
**** =-w, --write-sql=OUTPUT=
|
87
|
+
|
88
|
+
你也可以使用此选项让 arql 将 SQL 日志写入文件。
|
89
|
+
|
90
|
+
**** =-A, --append-sql-OUTOUT=
|
91
|
+
|
92
|
+
与 =-w= 类似,但是采用追加写入的方式,不会截断已有文件。
|
93
|
+
|
94
|
+
**** 数据库选项
|
95
|
+
|
96
|
+
本节中描述的选项通常会在配置文件中配置,这些选项只是对应配置文件中的配置项的快捷方式,以便在 CLI 中直接修改某些配置项。
|
97
|
+
|
98
|
+
***** -a, --db-adapter=DB_ADAPTER
|
99
|
+
|
100
|
+
指定数据库适配器,可用值:
|
101
|
+
|
102
|
+
- =mysql2=
|
103
|
+
- =postgresql=
|
104
|
+
- =sqlite3=
|
105
|
+
- =sqlserver=
|
106
|
+
- =oracle_enhanced=
|
107
|
+
|
108
|
+
***** -h, --db-host=DB_HOST
|
109
|
+
|
110
|
+
指定数据库主机
|
111
|
+
|
112
|
+
***** -p, --db-port=DB_PORT
|
113
|
+
|
114
|
+
指定数据库端口
|
115
|
+
|
116
|
+
***** -d, --db-name=DB_NAME
|
117
|
+
|
118
|
+
指定数据库名称
|
119
|
+
|
120
|
+
***** -u, --db-user=DB_USER
|
121
|
+
|
122
|
+
指定数据库用户名
|
123
|
+
|
124
|
+
***** -P, --db-password=DB_PASSWORD
|
125
|
+
|
126
|
+
指定数据库密码
|
127
|
+
|
128
|
+
***** -n, --db-encoding=DB_ENCODING
|
129
|
+
|
130
|
+
指定数据库字符编码,默认为 =utf8=
|
131
|
+
|
132
|
+
***** -o, --db-pool=DB_POOL
|
133
|
+
|
134
|
+
指定数据库连接池大小,默认为 =5=
|
135
|
+
|
136
|
+
***** -H, --ssh-host=SSH_HOST
|
137
|
+
|
138
|
+
指定 SSH 主机, 当指定了 SSH 相关的选项时, arql 会建立 SSH 隧道,使用 SSH 隧道连接数据库。
|
139
|
+
|
140
|
+
***** -O, --ssh-port=SSH_PORT
|
141
|
+
|
142
|
+
指定 SSH 端口
|
143
|
+
|
144
|
+
***** -U, --ssh-user=SSH_USER
|
145
|
+
|
146
|
+
指定 SSH 用户名
|
147
|
+
|
148
|
+
***** -W, --ssh-password=SSH_PASSWORD
|
149
|
+
|
150
|
+
指定 SSH 密码
|
151
|
+
|
152
|
+
***** -L, --ssh-local-port=SSH_LOCAL_PORT
|
153
|
+
|
154
|
+
指定 SSH 本地端口,默认为一个 /随机/ 端口
|
155
|
+
|
156
|
+
*** 配置文件
|
157
|
+
|
158
|
+
配置文件的路径默认为 =$HOME/.arql.yml= 或 =$HOME/.arql.d/init.yml= 。 配置文件通常与 Rails数据库配置文件相同,但有一
|
159
|
+
些额外的配置选项:
|
160
|
+
|
161
|
+
1. =created_at= : 一个包含 ActiveRecord =created_at= 字段的自定义列名的数组,默认值为 =created_at= ,如果指定了此项,创建时将使用当前时间戳填充列的值
|
162
|
+
2. =updated_at= : 一个包含 ActiveRecord =updated_at= 字段的自定义列名的数组,默认值为 =updated_at= ,如果指定了此项,更新时将使用当前时间戳填充列的值
|
163
|
+
3. =ssh.host= : ssh 主机, 可以使用 =ssh_config= 文件中的主机名,也可以是直接的 IP 地址或主机名
|
164
|
+
4. =ssh.port= : ssh 端口,默认值为 =22=
|
165
|
+
5. =ssh.user= : ssh 用户名
|
166
|
+
6. =ssh.password= : ssh 密码
|
167
|
+
7. =ssh.local_port= : ssh 本地端口
|
168
|
+
8. =singularized_table_names=: 是否使用单数表名,默认为 =false=, 如果为 =false=, 则 =students= 表将定义为 =Student= 模型,如果为 =true=, 则 =students= 表将定义为 =Students= 模型
|
169
|
+
|
170
|
+
**** 配置文件示例
|
171
|
+
|
172
|
+
#+begin_example
|
173
|
+
default: &default
|
174
|
+
adapter: mysql2
|
175
|
+
encoding: utf8
|
176
|
+
created_at: ["gmt_created"]
|
177
|
+
updated_at: ["gmt_modified"]
|
178
|
+
singularized_table_names: true
|
179
|
+
|
180
|
+
local:
|
181
|
+
<<: *default
|
182
|
+
username: root
|
183
|
+
database: blog
|
184
|
+
password:
|
185
|
+
socket: /tmp/mysql.sock
|
186
|
+
|
187
|
+
dev:
|
188
|
+
<<: *default
|
189
|
+
host: devdb.mycompany.com
|
190
|
+
port: 3306
|
191
|
+
username: root
|
192
|
+
password: 123456
|
193
|
+
database: blog
|
194
|
+
ssh:
|
195
|
+
host: dev.mycompany.com
|
196
|
+
port: 22
|
197
|
+
user: deploy
|
198
|
+
password: 12345678
|
199
|
+
local_port: 3307
|
200
|
+
#+end_example
|
201
|
+
|
202
|
+
示例中定义了一个通用的配置项 =default= ,以及两个具体的数据库环境 =local= 和 =dev= 。 =local= 和 =dev= 同 =<<:
|
203
|
+
*default= 的方式继承了 =default= 的配置项。
|
204
|
+
|
205
|
+
执行命令 =arql -e dev= 时,arql 会使用配置文件中的 =dev= 配置; 执行命令 =arql -e local= 时,arql 会使用配置文件中的
|
206
|
+
=local= 配置。
|
207
|
+
|
208
|
+
=dev= 环境使用了 SSH 隧道,连接到 =devdb.mycompany.com= 数据库时,会先建立一个 SSH 隧道到 =dev.mycompany.com= ,然
|
209
|
+
后通过 SSH 隧道连接到数据库。
|
210
|
+
|
211
|
+
*** 作为 REPL 使用
|
212
|
+
|
213
|
+
如果既没有指定 =[ruby file]= 也没有指定 =-E= 选项,并且 STDIN 是一个 =tty= ,arql 会启动一个 Pry REPL。例如执行:
|
214
|
+
|
215
|
+
#+BEGIN_EXAMPLE
|
216
|
+
arql -e dev
|
217
|
+
#+END_EXAMPLE
|
218
|
+
|
219
|
+
|
220
|
+
Arql 提供了一些 Pry 命令:
|
221
|
+
|
222
|
+
**** =info=
|
223
|
+
|
224
|
+
=info= 命令打印当前的数据库连接信息和 SSH 代理信息,例如:
|
225
|
+
|
226
|
+
#+begin_example
|
227
|
+
Database Connection Information:
|
228
|
+
Host:
|
229
|
+
Port:
|
230
|
+
Username: root
|
231
|
+
Password:
|
232
|
+
Database: test
|
233
|
+
Adapter: mysql2
|
234
|
+
Encoding: utf8
|
235
|
+
Pool Size: 5
|
236
|
+
#+end_example
|
237
|
+
|
238
|
+
**** =m= 或者 =l=
|
239
|
+
|
240
|
+
=m= (或者 =l= ) 命令打印所有表名及对应的模型类名和缩写类名,例如:
|
241
|
+
|
242
|
+
#+begin_example
|
243
|
+
+--------------------+------------------+------+---------+
|
244
|
+
| Table Name | Model Class | Abbr | Comment |
|
245
|
+
+--------------------+------------------+------+---------+
|
246
|
+
| post | Post | P | 帖子 |
|
247
|
+
| org | Org | O | 组织 |
|
248
|
+
| user_org | UserOrg | UO | |
|
249
|
+
| student | Student | S | 学生 |
|
250
|
+
| course | Course | C | |
|
251
|
+
| score | Score | S2 | |
|
252
|
+
| users | Users | U | |
|
253
|
+
| posts | Posts | P2 | |
|
254
|
+
| authors | Authors | A | |
|
255
|
+
+--------------------+------------------+------+---------+
|
256
|
+
#+end_example
|
257
|
+
|
258
|
+
其中:
|
259
|
+
|
260
|
+
- =Table Name= : 表名
|
261
|
+
- =Model Class= : 模型类名
|
262
|
+
- =Abbr= : 缩写类名
|
263
|
+
- =Comment= : 注释
|
264
|
+
|
265
|
+
=m= / =l= 命令还可以接受一个参数,用于通过表名或表注释来对列表进行过滤, 例如:
|
266
|
+
|
267
|
+
=m perm= 只会列出表名或表注释中包含 =perm= 的表;如果要使用正则表达式匹配,可以使用 =m /perm/i= 来进行匹配。
|
268
|
+
|
269
|
+
**** =t=
|
270
|
+
|
271
|
+
=t= 命令接受一个表名或模型类名作为参数,打印表的定义信息,例如:
|
272
|
+
|
273
|
+
执行 =t Person= 命令会打印 =person= 表的定义信息:
|
274
|
+
|
275
|
+
#+begin_example
|
276
|
+
Table: person
|
277
|
+
+----|------------|------------------|-----------|-------|-----------|-------|---------|----------|---------+
|
278
|
+
| PK | Name | SQL Type | Ruby Type | Limit | Precision | Scale | Default | Nullable | Comment |
|
279
|
+
+----|------------|------------------|-----------|-------|-----------|-------|---------|----------|---------+
|
280
|
+
| Y | id | int(11) unsigned | integer | 4 | | | | false | |
|
281
|
+
| | name | varchar(64) | string | 64 | | | | true | |
|
282
|
+
| | age | int(11) | integer | 4 | | | | true | |
|
283
|
+
| | gender | int(4) | integer | 4 | | | | true | |
|
284
|
+
| | grade | int(4) | integer | 4 | | | | true | |
|
285
|
+
| | blood_type | varchar(4) | string | 4 | | | | true | |
|
286
|
+
+----|------------|------------------|-----------|-------|-----------|-------|---------|----------|---------+
|
287
|
+
#+end_example
|
288
|
+
|
289
|
+
另外, =t= 同时也是模型类的一个类方法,执行 =Person.t= 会同样会打印出上述信息。
|
290
|
+
|
291
|
+
其中:
|
292
|
+
|
293
|
+
- =PK= : 是否为主键
|
294
|
+
- =Name= : 列名
|
295
|
+
- =SQL Type= : 数据库类型
|
296
|
+
- =Ruby Type= : Ruby 类型
|
297
|
+
- =Limit= : 长度限制
|
298
|
+
- =Precision= : 精度
|
299
|
+
- =Scale= : 小数位数
|
300
|
+
- =Default= : 默认值
|
301
|
+
- =Nullable= : 是否可为空
|
302
|
+
- =Comment= : 注释
|
303
|
+
|
304
|
+
**** =vd=
|
305
|
+
|
306
|
+
=t= 命令在终端中以表格的形式打印表的定义信息,缺点是如果表的列数过多,会导致表格这行,不方便查看。而 =vd=
|
307
|
+
(visidata) 是一个使用 Python 编写的终端数据分析工具,可以在终端中以表格的形式打印表的定义信息,但是支持水平滚动,方
|
308
|
+
便查看。
|
309
|
+
|
310
|
+
如果要使用 Arql 的 =vd= 命令,需要先安装 =visidata=:
|
311
|
+
|
312
|
+
#+begin_src sh
|
313
|
+
pipx install visidata
|
314
|
+
#+end_src
|
315
|
+
|
316
|
+
=vd= 命令和用法和 =t= 命令基本相同,另外, =Array= / =ActiveRecord::Base= 等对象也可以使用 =vd= 方法。
|
317
|
+
|
318
|
+
**** =show-sql= / =hide-sql=
|
319
|
+
|
320
|
+
这对命令可以切换 Pry REPL 中 SQL 日志的显示。
|
321
|
+
|
322
|
+
默认情况下,SQL 日志是不显示的:
|
323
|
+
|
324
|
+
#+begin_example
|
325
|
+
ARQL@demo247(main) [2] ❯ Student.count
|
326
|
+
=> 0
|
327
|
+
#+end_example
|
328
|
+
|
329
|
+
而打开 SQL 日志后,会显示每次执行的 SQL 语句:
|
330
|
+
|
331
|
+
#+begin_example
|
332
|
+
ARQL@demo247(main) [3] ❯ show-sql
|
333
|
+
ARQL@demo247(main) [4] ❯ Student.count
|
334
|
+
D, [2024-04-07T13:31:32.053903 #20440] DEBUG -- : Student Count (29.8ms) SELECT COUNT(*) FROM `student`
|
335
|
+
=> 0
|
336
|
+
#+end_example
|
337
|
+
|
338
|
+
**** =reconnect=
|
339
|
+
|
340
|
+
=reconnect= 命令用于重新连接当前的数据库连接。当因网络原因导致连接断开时,可以使用该命令重新连接。重新连接,当前的
|
341
|
+
Pry 会话中的对象不会丢失。 =reconnect= 首先会判断当前连接是否还是有效的,如果是有效的,则不会重新连接;如果
|
342
|
+
=reconnect= 对连接的有效性判断错误,可以使用 =reconnect!= 命令强制重新连接。
|
343
|
+
|
344
|
+
**** =redefine=
|
345
|
+
|
346
|
+
=redefine= 命令用于重新定义 ActiveRecord 模型类,根据数据库表的信息重新生成模型类。对于在 =init.rb= 中添加了新的关
|
347
|
+
系定义,想使新定义的关系在当前 Pry 会话中生效,可以使用 =redefine= 命令。
|
348
|
+
|
349
|
+
**** 沙盒模式
|
350
|
+
|
351
|
+
=sandbox-enter= 命令用于开启沙盒模式。在沙盒模式下,所有的数据库操作都会在事务中执行,该事务不会自动提交,需要手动提交或回滚。
|
352
|
+
|
353
|
+
1. 开启沙盒模式:
|
354
|
+
#+begin_example
|
355
|
+
ARQL@demo247(main) [6] ❯ sandbox-enter
|
356
|
+
ARQL@demo247 [sandbox] (main) [7] ❯
|
357
|
+
#+end_example
|
358
|
+
2. 退出沙盒模式:
|
359
|
+
#+begin_example
|
360
|
+
ARQL@demo247 [sandbox] (main) [7] ❯ sandbox-quit
|
361
|
+
begin_transaction callbacks removed.
|
362
|
+
You still have open 1 transactions open, don't forget commit or rollback them.
|
363
|
+
#+end_example
|
364
|
+
3. 提交事务:
|
365
|
+
#+begin_example
|
366
|
+
ARQL@demo247(main) [7] ❯ $C.commit_transaction
|
367
|
+
#+end_example
|
368
|
+
4. 回滚事务:
|
369
|
+
#+begin_example
|
370
|
+
ARQL@demo247(main) [7] ❯ $C.rollback_transaction
|
371
|
+
#+end_example
|
372
|
+
|
373
|
+
|
374
|
+
|
375
|
+
*** 作为代码解释器使用
|
376
|
+
|
377
|
+
如果指定了一个 Ruby 文件作为命令行参数,或者使用了 =-E= 选项,或者 STDIN 不是一个 =tty= ,那么 Arql 不会启动 Pry,而是直
|
378
|
+
接执行指定的文件或代码片段(或从标准输入读取代码)。在执行代码片段之前,会先加载模型类定义。你可以把这种用法看作类似
|
379
|
+
是 =rails= 的 =runner= 子命令。
|
380
|
+
|
381
|
+
**** 使用 =-E= 选项
|
382
|
+
|
383
|
+
通过 =-E= 选项可以直接执行代码片段,而不启动 Pry:
|
384
|
+
|
385
|
+
#+begin_example
|
386
|
+
$ arql -e dev -E 'puts Person.count'
|
387
|
+
#+end_example
|
388
|
+
|
389
|
+
**** 指定 Ruby 文件作为命令行参数
|
390
|
+
|
391
|
+
通过指定 Ruby 文件作为命令行参数,可以直接执行 Ruby 文件中的代码:
|
392
|
+
|
393
|
+
=test.rb=:
|
394
|
+
|
395
|
+
#+BEGIN_SRC ruby
|
396
|
+
puts Person.count
|
397
|
+
#+END_SRC
|
398
|
+
|
399
|
+
#+begin_example
|
400
|
+
$ arql -e dev test.rb
|
401
|
+
#+end_example
|
402
|
+
|
403
|
+
**** 从标准输入读取代码
|
404
|
+
|
405
|
+
从标准输入读取代码,可以直接执行代码片段:
|
406
|
+
|
407
|
+
#+begin_example
|
408
|
+
$ echo 'puts Person.count' | arql -e dev
|
409
|
+
#+end_example
|
410
|
+
|
411
|
+
*** 额外的扩展方法
|
412
|
+
**** =to_insert_sql= / =to_upsert_sql=
|
413
|
+
|
414
|
+
可以在任何 ActiveRecord 模型实例上调用 =to_insert_sql= / =to_upsert_sql= 方法,获取该对象的插入或更新 SQL 语句。
|
415
|
+
这两个方法也可以在包含 ActiveRecord 模型实例对象的数组对象上调用。
|
416
|
+
|
417
|
+
#+begin_example
|
418
|
+
ARQL ❯ Person.all.to_a.to_insert_sql
|
419
|
+
=> "INSERT INTO `person` (`id`,`name`,`age`,`gender`,`grade`,`blood_type`) VALUES (1, 'Jack', 30, NULL, NULL, NULL), (2, 'Jack', 11, 1, NULL, NULL), (3, 'Jack', 12, 1, NULL, NULL), (4, 'Jack', 30, 1, NULL, NULL), (5, 'Jack', 12, 2, NULL, NULL), (6, 'Jack', 2, 2, 2, NULL), (7, 'Jack', 3, 2, 2, NULL), (8, 'Jack', 30, 2, 2, 'AB'), (9, 'Jack', 30, 2, 2, 'AB'), (10, 'Jack', 30, 2, 2, 'AB'), (11, 'Jackson', 30, 2, 2, 'AB') ON DUPLICATE KEY UPDATE `id`=`id`;"
|
420
|
+
#+end_example
|
421
|
+
|
422
|
+
**** =to_create_sql=
|
423
|
+
|
424
|
+
可以在任何 ActiveRecord 模型类上调用 =to_create_sql= 方法,获取该模型类对应的表的创建 SQL 语句。
|
425
|
+
|
426
|
+
#+begin_example
|
427
|
+
ARQL@demo247(main) [16] ❯ puts Post.to_create_sql
|
428
|
+
D, [2024-04-07T14:15:11.106693 #20440] DEBUG -- : SQL (24.9ms) show create table post
|
429
|
+
CREATE TABLE `post` (
|
430
|
+
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
|
431
|
+
`name` varchar(256) DEFAULT NULL,
|
432
|
+
`gender` varchar(256) DEFAULT NULL,
|
433
|
+
`phone` varchar(256) DEFAULT NULL,
|
434
|
+
`id_no` varchar(256) DEFAULT NULL,
|
435
|
+
`note` varchar(256) DEFAULT NULL,
|
436
|
+
`gmt_created` datetime NOT NULL COMMENT '创建时间',
|
437
|
+
`gmt_modified` datetime NOT NULL COMMENT '最后修改时间',
|
438
|
+
PRIMARY KEY (`id`),
|
439
|
+
KEY `index_post_on_name` (`name`)
|
440
|
+
) ENGINE=InnoDB AUTO_INCREMENT=83 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
|
441
|
+
#+end_example
|
442
|
+
|
443
|
+
**** =t=
|
444
|
+
|
445
|
+
=t= 除了可以作为类方法在 ActiveRecord 模型类上调用,也可以作为实例方法在 ActiveRecord 模型实例对象上调用。
|
446
|
+
|
447
|
+
#+begin_example
|
448
|
+
ARQL ❯ Person.last.t
|
449
|
+
+----------------|-----------------|------------------|---------+
|
450
|
+
| Attribute Name | Attribute Value | SQL Type | Comment |
|
451
|
+
+----------------|-----------------|------------------|---------+
|
452
|
+
| id | 11 | int(11) unsigned | |
|
453
|
+
| name | Jackson | varchar(64) | |
|
454
|
+
| age | 30 | int(11) | |
|
455
|
+
| gender | 2 | int(4) | |
|
456
|
+
| grade | 2 | int(4) | |
|
457
|
+
| blood_type | AB | varchar(4) | |
|
458
|
+
+----------------|-----------------|------------------|---------+
|
459
|
+
#+end_example
|
460
|
+
|
461
|
+
=t= 方法可以接受以下两个选项:
|
462
|
+
|
463
|
+
+ =:except= 选项,用于指定不显示的属性名,值可以是字符串或正则表达式,例如:
|
464
|
+
#+BEGIN_EXAMPLE
|
465
|
+
Person.last.t(except: 'id')
|
466
|
+
Student.where(condition).t(except: /id|name/)
|
467
|
+
#+END_EXAMPLE
|
468
|
+
+ =:compact= 选项,用于指定是否紧凑显示,值可以是 =true= 或 =false= ,如果启用紧凑显示,那些值全部为 =NULL= 的列将不
|
469
|
+
会显示,这对于查看那些数据稀疏的表很有帮助,例如:
|
470
|
+
#+BEGIN_EXAMPLE
|
471
|
+
Person.last.t(compact: true)
|
472
|
+
Student.where(condition).t(compact: false)
|
473
|
+
#+END_EXAMPLE
|
474
|
+
|
475
|
+
**** =v=
|
476
|
+
|
477
|
+
=v= 方法用于与 Emacs org babel 集成。
|
478
|
+
|
479
|
+
***** =v= 作为模型类的实例方法
|
480
|
+
|
481
|
+
在任何 ActiveRecord 模型实例对象上调用 =v= 方法,可以打印一个数组,数组的第一个元素是 =['Attribute Name',
|
482
|
+
'Attribute Value', 'SQL Type', 'Comment']= ,第二个元素是 =nil= ,剩下的元素是对象的属性名和值。在Emacs org-mode
|
483
|
+
中,如果 =:result= 类型是 =value= (默认值),这个返回值会被渲染成一个漂亮的表格。
|
484
|
+
|
485
|
+
#+begin_example
|
486
|
+
ARQL ❯ Person.last.v
|
487
|
+
=> [["Attribute Name", "Attribute Value", "SQL Type", "Comment"],
|
488
|
+
nil,
|
489
|
+
["id", 11, "int(11) unsigned", ""],
|
490
|
+
["name", "Jackson", "varchar(64)", ""],
|
491
|
+
["age", 30, "int(11)", ""],
|
492
|
+
["gender", 2, "int(4)", ""],
|
493
|
+
["grade", 2, "int(4)", ""],
|
494
|
+
["blood_type", "AB", "varchar(4)", ""]]
|
495
|
+
#+end_example
|
496
|
+
|
497
|
+
***** 只包含模型实例的数组
|
498
|
+
#+begin_example
|
499
|
+
ARQL ❯ Person.all.to_a.v
|
500
|
+
=> [["id", "name", "age", "gender", "grade", "blood_type"],
|
501
|
+
nil,
|
502
|
+
[1, "Jack", 30, nil, nil, nil],
|
503
|
+
[2, "Jack", 11, 1, nil, nil],
|
504
|
+
[3, "Jack", 12, 1, nil, nil],
|
505
|
+
[4, "Jack", 30, 1, nil, nil],
|
506
|
+
[5, "Jack", 12, 2, nil, nil],
|
507
|
+
[6, "Jack", 2, 2, 2, nil],
|
508
|
+
[7, "Jack", 3, 2, 2, nil],
|
509
|
+
[8, "Jack", 30, 2, 2, "AB"],
|
510
|
+
[9, "Jack", 30, 2, 2, "AB"],
|
511
|
+
[10, "Jack", 30, 2, 2, "AB"],
|
512
|
+
[11, "Jackson", 30, 2, 2, "AB"]]
|
513
|
+
#+end_example
|
514
|
+
|
515
|
+
***** 只包含同构 Hash 对象的数组
|
516
|
+
|
517
|
+
#+begin_example
|
518
|
+
ARQL ❯ arr = [{name: 'Jack', age: 10}, {name: 'Lucy', age: 20}]
|
519
|
+
=> [{:name=>"Jack", :age=>10}, {:name=>"Lucy", :age=>20}]
|
520
|
+
ARQL ❯ arr.v
|
521
|
+
=> [[:name, :age], nil, ["Jack", 10], ["Lucy", 20]]
|
522
|
+
#+end_example
|
523
|
+
|
524
|
+
**** =q=
|
525
|
+
|
526
|
+
#+begin_example
|
527
|
+
ARQL ❯ rs = q 'select count(0) from person;'
|
528
|
+
=> #<ActiveRecord::Result:0x00007fd1f8026ad0 @column_types={}, @columns=["count(0)"], @hash_rows=nil, @rows=[[11]]>
|
529
|
+
ARQL ❯ rs.rows
|
530
|
+
=> [[11]]
|
531
|
+
#+end_example
|
532
|
+
|
533
|
+
**** JSON 转换和格式化
|
534
|
+
|
535
|
+
在任何对象上调用 =j= 方法,可以得到 JSON 格式的字符串,调用 =jj= 方法可以得到格式化后的 JSON 字符串。
|
536
|
+
|
537
|
+
使用 =jp= 方法打印 JSON,使用 =jjp= 方法打印格式化后的 JSON。
|
538
|
+
|
539
|
+
**** $C 全局变量
|
540
|
+
|
541
|
+
Arql 将 =ActiveRecord::Base.connection= 对象赋值给全局可用的 =$C= 全局变量,它代表当前的数据库连接。
|
542
|
+
|
543
|
+
上文中的 =q= 方法实际上是 =$C.exec_query= 方法, =$C= 对象的其他方法也很有用:
|
544
|
+
|
545
|
+
***** 创建表
|
546
|
+
#+begin_example
|
547
|
+
ARQL ❯ $C.create_table :post, id: false, primary_key: :id do |t|
|
548
|
+
ARQL ❯ t.column :id, :bigint, precison: 19, comment: 'ID'
|
549
|
+
ARQL ❯ t.column :name, :string, comment: '名称'
|
550
|
+
ARQL ❯ t.column :gmt_created, :datetime, comment: '创建时间'
|
551
|
+
ARQL ❯ t.column :gmt_modified, :datetime, comment: '最后修改时间'
|
552
|
+
ARQL ❯ end
|
553
|
+
#+end_example
|
554
|
+
|
555
|
+
=create_table= 同样也被加入到 =Kernel= 下面,所以也可以直接调用 =create_table= 方法:
|
556
|
+
|
557
|
+
#+begin_example
|
558
|
+
ARQL ❯ create_table :post, id: false, primary_key: :id do |t|
|
559
|
+
ARQL ❯ t.column :id, :bigint, precison: 19, comment: 'ID'
|
560
|
+
ARQL ❯ t.column :name, :string, comment: '名称'
|
561
|
+
ARQL ❯ t.column :gmt_created, :datetime, comment: '创建时间'
|
562
|
+
ARQL ❯ t.column :gmt_modified, :datetime, comment: '最后修改时间'
|
563
|
+
ARQL ❯ end
|
564
|
+
#+end_example
|
565
|
+
|
566
|
+
***** 添加字段
|
567
|
+
|
568
|
+
#+begin_example
|
569
|
+
$C.add_column :post, :note, :string, comment: '备注'
|
570
|
+
#+end_example
|
571
|
+
|
572
|
+
=add_column= 也被加入到模型类的类方法中,所以也可以直接在模型类上调用 =add_column= 方法:
|
573
|
+
|
574
|
+
#+begin_example
|
575
|
+
Post.add_column :note, :string, comment: '备注'
|
576
|
+
#+end_example
|
577
|
+
|
578
|
+
***** 修改字段
|
579
|
+
|
580
|
+
#+begin_example
|
581
|
+
$C.change_column :post, :note, :text, comment: '备注'
|
582
|
+
#+end_example
|
583
|
+
|
584
|
+
=change_column= 也被加入到模型类的类方法中,所以也可以直接在模型类上调用 =change_column= 方法:
|
585
|
+
|
586
|
+
#+begin_example
|
587
|
+
Post.change_column :note, :text, comment: '备注'
|
588
|
+
#+end_example
|
589
|
+
|
590
|
+
***** 删除字段
|
591
|
+
|
592
|
+
#+begin_example
|
593
|
+
$C.remove_column :post, :note
|
594
|
+
#+end_example
|
595
|
+
|
596
|
+
=remove_column= 也被加入到模型类的类方法中,所以也可以直接在模型类上调用 =remove_column= 方法:
|
597
|
+
|
598
|
+
#+begin_example
|
599
|
+
Post.remove_column :note
|
600
|
+
#+end_example
|
601
|
+
|
602
|
+
***** 删除表
|
603
|
+
|
604
|
+
#+begin_example
|
605
|
+
$C.drop_table :post
|
606
|
+
#+end_example
|
607
|
+
|
608
|
+
=drop_table= 也被加入到模型类的类方法中,所以也可以直接在模型类上调用 =drop_table= 方法:
|
609
|
+
|
610
|
+
#+begin_example
|
611
|
+
Post.drop_table
|
612
|
+
#+end_example
|
613
|
+
|
614
|
+
***** 添加索引
|
615
|
+
|
616
|
+
#+begin_example
|
617
|
+
ARQL ❯ $C.add_index :post, :name
|
618
|
+
ARQL ❯ $C.add_index(:accounts, [:branch_id, :party_id], unique: true, name: 'by_branch_party')
|
619
|
+
#+end_example
|
620
|
+
|
621
|
+
=add_index= 也被加入到模型类的类方法中,所以也可以直接在模型类上调用 =add_index= 方法:
|
622
|
+
|
623
|
+
#+begin_example
|
624
|
+
Post.add_index :name
|
625
|
+
Post.add_index [:branch_id, :party_id], unique: true, name: 'by_branch_party'
|
626
|
+
#+end_example
|
627
|
+
|
628
|
+
**** =Kernel= 扩展方法
|
629
|
+
|
630
|
+
=Kernel= 模块下的函数可以想语言内置函数一样直接调用,不需要指定模块名。 以下是 Arql 扩展的 =Kernel= 方法:
|
631
|
+
|
632
|
+
Pry 内建了 =show-source= (别名 =$= ) 和 =show-doc= (别名 =?= )命令,可以查看方法的源码和文档。可以通过 =show-doc= 查看方法的文档。例如:
|
633
|
+
|
634
|
+
#+BEGIN_EXAMPLE
|
635
|
+
ARQL ❯ ? create_table
|
636
|
+
#+END_EXAMPLE
|
637
|
+
|
638
|
+
|
639
|
+
***** 创建表 =create_table=
|
640
|
+
#+BEGIN_EXAMPLE
|
641
|
+
create_table :post, id: false, primary_key: :id do |t|
|
642
|
+
t.column :id, :bigint, precison: 19, comment: 'ID'
|
643
|
+
t.column :name, :string, comment: '名称'
|
644
|
+
t.column :gmt_created, :datetime, comment: '创建时间'
|
645
|
+
t.column :gmt_modified, :datetime, comment: '最后修改时间'
|
646
|
+
end
|
647
|
+
#+END_EXAMPLE
|
648
|
+
***** 创建多对多关系的中间表 =create_join_table=
|
649
|
+
#+BEGIN_EXAMPLE
|
650
|
+
create_join_table :products, :categories do |t|
|
651
|
+
t.index :product_id
|
652
|
+
t.index :category_id
|
653
|
+
end
|
654
|
+
#+END_EXAMPLE
|
655
|
+
***** 删除表 =drop_table=
|
656
|
+
#+BEGIN_EXAMPLE
|
657
|
+
drop_table :post
|
658
|
+
#+END_EXAMPLE
|
659
|
+
***** 删除多对多关系的中间表 =drop_join_table=
|
660
|
+
#+BEGIN_EXAMPLE
|
661
|
+
drop_join_table :products, :categories
|
662
|
+
#+END_EXAMPLE
|
663
|
+
***** 修改表名 =rename_table=
|
664
|
+
#+BEGIN_EXAMPLE
|
665
|
+
rename_table :post, :posts
|
666
|
+
#+END_EXAMPLE
|
667
|
+
|
668
|
+
***** =print_tables=
|
669
|
+
|
670
|
+
Arql 提供了一个 =print_tables= 方法,可以将当前数据库中的所有表的信息,导出为:
|
671
|
+
|
672
|
+
+ markdown 表格格式: ~print_tables(:md)~
|
673
|
+
+ org-mode 表格格式: ~print_tables(:org)~
|
674
|
+
+ create table SQL: ~print_tables(:sql)~
|
675
|
+
|
676
|
+
**** 模型类类方法扩展
|
677
|
+
|
678
|
+
Pry 内建了 =show-source= (别名 =$= ) 和 =show-doc= (别名 =?= )命令,可以查看方法的源码和文档。可以通过 =show-doc= 查看方法的文档。例如:
|
679
|
+
|
680
|
+
#+BEGIN_EXAMPLE
|
681
|
+
ARQL ❯ ? Student.add_column
|
682
|
+
#+END_EXAMPLE
|
683
|
+
|
684
|
+
***** 添加字段 =add_column=
|
685
|
+
#+BEGIN_EXAMPLE
|
686
|
+
Student.add_column :note, :text, comment: '备注'
|
687
|
+
#+END_EXAMPLE
|
688
|
+
|
689
|
+
***** 修改字段 =change_column=
|
690
|
+
#+BEGIN_EXAMPLE
|
691
|
+
Student.change_column :note, :string, comment: '备注'
|
692
|
+
#+END_EXAMPLE
|
693
|
+
|
694
|
+
***** 删除字段 =remove_column=
|
695
|
+
#+BEGIN_EXAMPLE
|
696
|
+
Student.remove_column :note
|
697
|
+
#+END_EXAMPLE
|
698
|
+
|
699
|
+
***** 添加索引 =add_index=
|
700
|
+
#+BEGIN_EXAMPLE
|
701
|
+
Student.add_index :name
|
702
|
+
Student.add_index [:branch_id, :party_id], unique: true, name: 'by_branch_party'
|
703
|
+
#+END_EXAMPLE
|
704
|
+
|
705
|
+
***** 修改字段注释 =change_column_comment=
|
706
|
+
#+BEGIN_EXAMPLE
|
707
|
+
Student.change_column_comment :note, '备注'
|
708
|
+
#+END_EXAMPLE
|
709
|
+
|
710
|
+
***** 修改字段默认值 =change_column_default=
|
711
|
+
#+BEGIN_EXAMPLE
|
712
|
+
Student.change_column_default :note, '默认值'
|
713
|
+
#+END_EXAMPLE
|
714
|
+
|
715
|
+
***** 修改字段名称 =rename_column=
|
716
|
+
#+BEGIN_EXAMPLE
|
717
|
+
Student.rename_column :note, :remark
|
718
|
+
#+END_EXAMPLE
|
719
|
+
|
720
|
+
***** 修改表名 =rename_table=
|
721
|
+
#+BEGIN_EXAMPLE
|
722
|
+
Student.rename_table :seitou
|
723
|
+
#+END_EXAMPLE
|
724
|
+
|
725
|
+
***** 修改表注释 =change_table_comment=
|
726
|
+
#+BEGIN_EXAMPLE
|
727
|
+
Student.change_table_comment from: '', to: '学生表'
|
728
|
+
#+END_EXAMPLE
|
729
|
+
|
730
|
+
***** 删除表 =drop_table=
|
731
|
+
#+BEGIN_EXAMPLE
|
732
|
+
Student.drop_table
|
733
|
+
#+END_EXAMPLE
|
734
|
+
|
735
|
+
***** 删除索引 =remove_index=
|
736
|
+
#+BEGIN_EXAMPLE
|
737
|
+
Student.remove_index :age
|
738
|
+
Student.remove_index name: 'by_branch_party'
|
739
|
+
#+END_EXAMPLE
|
740
|
+
|
741
|
+
***** 查询表注释 =table_comment=
|
742
|
+
#+BEGIN_EXAMPLE
|
743
|
+
Student.table_comment
|
744
|
+
#+END_EXAMPLE
|
745
|
+
|
746
|
+
***** 列出表的索引 =indexes=
|
747
|
+
#+BEGIN_EXAMPLE
|
748
|
+
Student.indexes
|
749
|
+
#+END_EXAMPLE
|
750
|
+
|
751
|
+
**** 读写 Excel 和 CSV 文件
|
752
|
+
|
753
|
+
Arql 集成了 =roo= 和 =caxlsx= 两个 Excel 库,提供了用于解析和生成 Excel 文件的方法。同时,Arql 也提供了用于读写 CSV 文件的方法。
|
754
|
+
|
755
|
+
***** 解析 Excel
|
756
|
+
|
757
|
+
Arql 为 =Kernel= 模块添加了 =parse_excel= 方法,可以用来解析 Excel 文件。例如:
|
758
|
+
|
759
|
+
#+BEGIN_EXAMPLE
|
760
|
+
ARQL ❯ parse_excel 'path/to/excel.xlsx'
|
761
|
+
#+END_EXAMPLE
|
762
|
+
|
763
|
+
文件路径中可以使用 =~/= 表示用户的主目录,Arql 会自动展开。
|
764
|
+
|
765
|
+
|
766
|
+
也可以在一个表示文件路径的 =String= 对象上调用 =parse_excel= 方法:
|
767
|
+
|
768
|
+
#+BEGIN_EXAMPLE
|
769
|
+
ARQL ❯ 'path/to/excel.xlsx'.parse_excel
|
770
|
+
#+END_EXAMPLE
|
771
|
+
|
772
|
+
=parse_excel= 方法会返回一个 =Hash= 对象,Key 为 Sheet 名称,Value 为 Sheet 的数据,Value 是一个二维数组。例如:
|
773
|
+
|
774
|
+
#+BEGIN_EXAMPLE
|
775
|
+
{
|
776
|
+
'Sheet1' => [
|
777
|
+
['A1', 'B1', 'C1'],
|
778
|
+
['A2', 'B2', 'C2'],
|
779
|
+
['A3', 'B3', 'C3']
|
780
|
+
],
|
781
|
+
'Sheet2' => [
|
782
|
+
['A1', 'B1', 'C1'],
|
783
|
+
['A2', 'B2', 'C2'],
|
784
|
+
['A3', 'B3', 'C3']
|
785
|
+
]
|
786
|
+
}
|
787
|
+
#+END_EXAMPLE
|
788
|
+
|
789
|
+
***** 生成 Excel
|
790
|
+
|
791
|
+
Arql 为 =Hash= / =Array= / =ActiveRecord::Relation= / =ActiveRecord::Base= 对象添加了 =write_excel= 方法,可以用来
|
792
|
+
生成 Excel 文件:
|
793
|
+
|
794
|
+
****** 从 =Hash= 对象生成 Excel
|
795
|
+
|
796
|
+
#+BEGIN_EXAMPLE
|
797
|
+
ARQL ❯ obj.write_excel 'path/to/excel.xlsx'
|
798
|
+
#+END_EXAMPLE
|
799
|
+
|
800
|
+
=Hash#write_excel= 要求 Hash 对象 Key 是 Sheet 名称,Value 是 Sheet 的数据,Value 的类型可以是:
|
801
|
+
|
802
|
+
+ 一个数组,数组的元素可以是:
|
803
|
+
+ 一个数组,表示一行数据
|
804
|
+
+ 一个 Hash 对象,表示一行数据,Key 是列名,Value 是列值
|
805
|
+
+ 一个 ActiveRecord::Base 对象,表示一行数据
|
806
|
+
+ 一个 Hash 对象,一共包含两个键值对:
|
807
|
+
+ =:fields=, 一个数组,表示列名
|
808
|
+
+ =:data=, 一个二维数组,表示数据
|
809
|
+
|
810
|
+
****** 从 =Array= 对象生成 Excel
|
811
|
+
|
812
|
+
#+BEGIN_EXAMPLE
|
813
|
+
ARQL ❯ obj.write_excel 'path/to/excel.xlsx', :name, :age, :gender, sheet_name: '订单数据'
|
814
|
+
#+END_EXAMPLE
|
815
|
+
|
816
|
+
其中:
|
817
|
+
|
818
|
+
+ =:name, :age, :gender= 这几个参数是列名,如果不指定,会根据数组的第一个元素来确定列名:
|
819
|
+
- 如果元素是 =ActiveRecord::Base= 对象,会使用对象的全部属性名(即数据库字段列表)作为列名
|
820
|
+
- 如果元素是 =Hash= 对象,会使用 =Hash= 的 全部 Key 作为列名
|
821
|
+
+ =sheet_name= 指定 Sheet 名称,如果不指定,会使用默认的 Sheet 名称 =Sheet1=
|
822
|
+
|
823
|
+
=Array= 对象的每一个元素表示一行数据, =Array#write_excel= 要求 Array 对象每个元素:
|
824
|
+
|
825
|
+
+ 一个 =ActiveRecord::Base= 对象
|
826
|
+
+ 一个 =Hash= 对象,表示一行数据,Key 是列名,Value 是列值
|
827
|
+
+ 一个数组,表示一行数据
|
828
|
+
|
829
|
+
****** 从 =ActiveRecord::Base= 对象生成 Excel
|
830
|
+
|
831
|
+
#+BEGIN_EXAMPLE
|
832
|
+
ARQL ❯ Student.find(123).write_excel 'path/to/excel.xlsx', sheet_name: '学生数据'
|
833
|
+
#+END_EXAMPLE
|
834
|
+
|
835
|
+
=ActiveRecord::Base= 的 =write_excel= 对象实际上就是把这个 =ActiveRecord::Base= 对象包装成一个只有一个元素的 =Array= 对
|
836
|
+
象,然后调用 =Array= 的 =write_excel= 方法。
|
837
|
+
|
838
|
+
****** 从 =ActiveRecord::Relation= 对象生成 Excel
|
839
|
+
|
840
|
+
#+BEGIN_EXAMPLE
|
841
|
+
ARQL ❯ Student.where(gender: 'M').write_excel 'path/to/excel.xlsx', sheet_name: '男学生'
|
842
|
+
#+END_EXAMPLE
|
843
|
+
|
844
|
+
=ActiveRecord::Relation= 的 =write_excel= 对象实际上就是把这个 =ActiveRecord::Relation= 对象转换成一个 =Array= 对象,然
|
845
|
+
后调用 =Array= 的 =write_excel= 方法。
|
846
|
+
|
847
|
+
***** 解析 CSV
|
848
|
+
|
849
|
+
Arql 提供了 =parse_csv= 方法,可以用来解析 CSV 文件:
|
850
|
+
|
851
|
+
#+BEGIN_EXAMPLE
|
852
|
+
ARQL ❯ parse_csv 'path/to/csv.csv'
|
853
|
+
#+END_EXAMPLE
|
854
|
+
|
855
|
+
=parse_csv= 方法返回一个标准库中的 CSV 对象。
|
856
|
+
|
857
|
+
=parse_csv= 可以有以下选项参数:
|
858
|
+
|
859
|
+
- =encoding=, 指定 CSV 文件的编码,默认是 =UTF-16= (with BOM)
|
860
|
+
- =headers=, 指定是否包含表头,默认是 =false=
|
861
|
+
- =col_sep=, 指定列分隔符,默认是 =\t=
|
862
|
+
- =row_sep=, 指定行分隔符,默认是 =\r\n=
|
863
|
+
|
864
|
+
(以上默认值实际就是 Microsoft Office Excel 保存 CSV 文件时默认使用的配置)
|
865
|
+
|
866
|
+
也可以在一个表示文件路径的 =String= 对象上调用 =parse_csv= 方法:
|
867
|
+
|
868
|
+
#+BEGIN_EXAMPLE
|
869
|
+
ARQL ❯ 'path/to/csv.csv'.parse_csv
|
870
|
+
#+END_EXAMPLE
|
871
|
+
|
872
|
+
***** 生成 CSV
|
873
|
+
Arql 为 =Array= / =ActiveRecord::Relation= / =ActiveRecord::Base= 对象添加了 =write_csv= 方法,可以用来生成 CSV 文件:
|
874
|
+
|
875
|
+
****** 从 =Array= 对象生成 CSV
|
876
|
+
|
877
|
+
#+BEGIN_EXAMPLE
|
878
|
+
ARQL ❯ obj.write_csv 'path/to/csv.csv', :name, :age, :gender, sheet_name: '订单数据'
|
879
|
+
#+END_EXAMPLE
|
880
|
+
|
881
|
+
用法和 =Array= 对象的 =write_excel= 方法类似。
|
882
|
+
|
883
|
+
|
884
|
+
****** 从 =ActiveRecord::Base= 对象生成 CSV
|
885
|
+
|
886
|
+
#+BEGIN_EXAMPLE
|
887
|
+
ARQL ❯ Student.find(123).write_csv 'path/to/csv.csv', sheet_name: '学生数据'
|
888
|
+
#+END_EXAMPLE
|
889
|
+
|
890
|
+
用法和 =ActiveRecord::Base= 对象的 =write_excel= 方法类似。
|
891
|
+
|
892
|
+
****** 从 =ActiveRecord::Relation= 对象生成 CSV
|
893
|
+
|
894
|
+
#+BEGIN_EXAMPLE
|
895
|
+
ARQL ❯ Student.where(gender: 'M').write_csv 'path/to/csv.csv', sheet_name: '男学生'
|
896
|
+
#+END_EXAMPLE
|
897
|
+
|
898
|
+
用法和 =ActiveRecord::Relation= 对象的 =write_excel= 方法类似。
|
899
|
+
|
900
|
+
**** dump 数据
|
901
|
+
|
902
|
+
注意: 仅支持 MySQL 数据库
|
903
|
+
|
904
|
+
Arql 为 =Array= / =ActiveRecord::Base= / =ActiveRecord::Relation= 等对象添加了 =dump= 方法,可以用来导出数据到 SQL 文件:
|
905
|
+
|
906
|
+
|
907
|
+
***** 从 Array 对象导出数据
|
908
|
+
|
909
|
+
#+BEGIN_EXAMPLE
|
910
|
+
ARQL ❯ obj.dump 'path/to/dump.sql', batch_size: 5000
|
911
|
+
#+END_EXAMPLE
|
912
|
+
|
913
|
+
=Array= 对象的每一个元素必须是一个 =ActiveRecord::Base= 对象
|
914
|
+
|
915
|
+
=batch_size= 参数指定每个批次查询出的数据,默认值为 500
|
916
|
+
|
917
|
+
***** 从 ActiveRecord::Base 对象导出数据
|
918
|
+
|
919
|
+
#+BEGIN_EXAMPLE
|
920
|
+
ARQL ❯ Student.find(123).dump 'path/to/dump.sql', batch_size: 5000
|
921
|
+
#+END_EXAMPLE
|
922
|
+
|
923
|
+
=ActiveRecord::Base= 对象的 =dump= 方法实际上就是把这个 =ActiveRecord::Base= 对象包装成一个只有一个元素的 =Array= 对象,然后调用 =Array= 的 =dump= 方法。
|
924
|
+
|
925
|
+
***** 从 ActiveRecord::Relation 对象导出数据
|
926
|
+
|
927
|
+
#+BEGIN_EXAMPLE
|
928
|
+
ARQL ❯ Student.where(gender: 'M').dump 'path/to/dump.sql', batch_size: 5000
|
929
|
+
#+END_EXAMPLE
|
930
|
+
|
931
|
+
=ActiveRecord::Relation= 的 =dump= 对象实际上就是把这个 =ActiveRecord::Relation= 对象转换成一个 =Array= 对象,然后调用 =Array= 的 =dump= 方法。
|
932
|
+
|
933
|
+
|
934
|
+
***** 调用 ActiveRecord::Base 的 dump 类方法
|
935
|
+
|
936
|
+
#+BEGIN_EXAMPLE
|
937
|
+
ARQL ❯ Student.dump 'path/to/dump.sql', no_create_table: false
|
938
|
+
#+END_EXAMPLE
|
939
|
+
|
940
|
+
这个方法会通过 =mysqldump= 命令 把 =Student= 表中的所有数据导出到 SQL 文件中。
|
941
|
+
|
942
|
+
=no_create_table= 参数指定是否在 SQL 文件中包含创建表的语句,默认值为 =false= 。
|
943
|
+
|
944
|
+
|
945
|
+
|
946
|
+
***** 在全局连接对象 =$C= 上调用 dump 方法
|
947
|
+
|
948
|
+
#+BEGIN_EXAMPLE
|
949
|
+
ARQL ❯ $C.dump 'path/to/dump.sql', no_create_db: false
|
950
|
+
#+END_EXAMPLE
|
951
|
+
|
952
|
+
这个方法会通过 mysqldump 命令把当前数据库中的所有表的数据导出到 SQL 文件中。
|
953
|
+
|
954
|
+
=no_create_db= 参数指定是否在 SQL 文件中包含创建数据库的语句,默认值为 =false= 。
|
955
|
+
|
956
|
+
|
957
|
+
**** Plot
|
958
|
+
|
959
|
+
Arql 集成了 Ruby 的 =youplot= 库,为 =Array= 添加了一些可以用来绘制图表的方法:
|
960
|
+
|
961
|
+
+ =barplot=
|
962
|
+
+ =countplot=
|
963
|
+
+ =histo=
|
964
|
+
+ =lineplot=
|
965
|
+
+ =lineplots=
|
966
|
+
+ =scatter=
|
967
|
+
+ =density=
|
968
|
+
+ =boxplot=
|
969
|
+
|
970
|
+
示例:
|
971
|
+
|
972
|
+
数量统计图:
|
973
|
+
|
974
|
+
#+BEGIN_EXAMPLE
|
975
|
+
ARQL@demo247(main) [44] ❯ Student.pluck(:gender)
|
976
|
+
=> ["M", "M", "M", "M", "M", "M", "M", "F", "M", "F", "M", "M", "M", "M", "M"]
|
977
|
+
ARQL@demo247(main) [45] ❯ Student.pluck(:gender).countplot
|
978
|
+
┌ ┐
|
979
|
+
M ┤■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 13.0
|
980
|
+
F ┤■■■■■ 2.0
|
981
|
+
└ ┘
|
982
|
+
#+END_EXAMPLE
|
983
|
+
|
984
|
+
分布图:
|
985
|
+
|
986
|
+
#+BEGIN_EXAMPLE
|
987
|
+
ARQL@jicai.dev(main) [18] ❯ Order.last(20).pluck(:order_sum)
|
988
|
+
=> [0.21876e5, 0.336571e5, 0.1934e5, 0.966239e4, 0.38748e3, 0.31092e4, 0.483e5, 0.445121e5, 0.1305e4, 0.2296e6, 0.943e5, 0.352e4, 0.3756e5, 0.323781e5, 0.7937622e5, 0.982e4, 0.338393e5, 0.316597e5, 0.213678e5, 0.336845e5]
|
989
|
+
ARQL@jicai.dev(main) [19] ❯ Order.last(20).pluck(:order_sum).histo
|
990
|
+
┌ ┐
|
991
|
+
[ 0.0, 50000.0) ┤▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 17
|
992
|
+
[ 50000.0, 100000.0) ┤▇▇▇▇ 2
|
993
|
+
[100000.0, 150000.0) ┤ 0
|
994
|
+
[150000.0, 200000.0) ┤ 0
|
995
|
+
[200000.0, 250000.0) ┤▇▇ 1
|
996
|
+
└ ┘
|
997
|
+
Frequency
|
998
|
+
|
999
|
+
#+END_EXAMPLE
|
1000
|
+
|
1001
|
+
**** =String=
|
1002
|
+
|
1003
|
+
***** =Srting#p=
|
1004
|
+
|
1005
|
+
=p= 方法的定义如下:
|
1006
|
+
|
1007
|
+
#+begin_example
|
1008
|
+
class String
|
1009
|
+
def p
|
1010
|
+
puts self
|
1011
|
+
end
|
1012
|
+
end
|
1013
|
+
#+end_example
|
1014
|
+
|
1015
|
+
="hello".p= 等价于 =puts "hello"= 。
|
1016
|
+
|
1017
|
+
***** =String#parse=
|
1018
|
+
|
1019
|
+
对于一个表示文件路径的字符串,可以调用 =parse= 方法通过文件路径中的后缀名来分别对 Excel、CSV、JSON 文件进行解析。
|
1020
|
+
|
1021
|
+
#+BEGIN_EXAMPLE
|
1022
|
+
excel = 'path/to/excel.xlsx'.parse
|
1023
|
+
csv = 'path/to/csv.csv'.parse
|
1024
|
+
json = 'path/to/json.json'.parse
|
1025
|
+
#+END_EXAMPLE
|
1026
|
+
|
1027
|
+
**** =ID=
|
1028
|
+
|
1029
|
+
Arql 提供了一个 =ID= 类,用来生成雪花算法 ID 和 UUID。
|
1030
|
+
|
1031
|
+
#+BEGIN_EXAMPLE
|
1032
|
+
id = ID.long # 生成一个雪花算法 ID
|
1033
|
+
id = ID.uuid # 生成一个 UUID
|
1034
|
+
#+END_EXAMPLE
|
1035
|
+
|
1036
|
+
**** Ransack
|
1037
|
+
|
1038
|
+
Arql 集成了 =Ransack=:
|
1039
|
+
|
1040
|
+
#+BEGIN_EXAMPLE
|
1041
|
+
Student.ransack(name_cont: 'Tom').result # 模糊查询名字中包含 'Tom' 的学生
|
1042
|
+
Student.ransack(name_start: 'Tom').result # 模糊查询名字以 'Tom' 开头的学生
|
1043
|
+
#+END_EXAMPLE
|
1044
|
+
|
1045
|
+
*** Emacs Org Babel 集成
|
1046
|
+
|
1047
|
+
这里有一个 [[https://github.com/lululau/spacemacs-layers/blob/master/ob-arql/local/ob-arql/ob-arql.el][ob-arql]] 用于集成 Emacs org babel。
|
1048
|
+
|
1049
|
+
** Guides and Tips
|
1050
|
+
*** [[./define-associations-zh_CN.org][在 Initializer 文件中定义关联关系]]
|
1051
|
+
*** [[./initializer-structure-zh_CN.org][将不同环境的初始化代码放在不同的文件中]]
|
1052
|
+
*** [[./helper-for-datetime-range-query-zh_CN.org][定义快速按时间查询的便利方法]]
|
1053
|
+
*** [[./auto-set-id-before-save-zh_CN.org][新建对象在保存之前自动设置 ID]]
|
1054
|
+
*** [[./custom-configurations-zh_CN.org][配置文件中的自定义配置项]]
|
1055
|
+
*** [[./sql-log-zh_CN.org][自动记录 SQL 日志和 REPL 输入历史]]
|
1056
|
+
*** [[./fuzzy-field-query-zh_CN.org][字段名 Fuzzy 化查询]]
|
1057
|
+
*** [[./oss-files-zh_CN.org][OSS 数据下载和查看]]
|
1058
|
+
*** 使用 Arql 查看 SQLite3 数据库文件
|
1059
|
+
|
1060
|
+
可以使用 Arql 查看 SQLite3 数据库文件,例如:
|
1061
|
+
|
1062
|
+
#+BEGIN_EXAMPLE
|
1063
|
+
arql -d db/development.sqlite3
|
1064
|
+
#+END_EXAMPLE
|
1065
|
+
|
1066
|
+
*** 根据名称或注释查找字段
|
1067
|
+
|
1068
|
+
我们在熟悉一个项目的时候,经常会遇到这样的情况:我们知道某个字段的名称或注释,但是不知道它对应的表名和字段名。这时候我们可以使用如下方法来查找:
|
1069
|
+
|
1070
|
+
#+BEGIN_SRC ruby
|
1071
|
+
puts model_classes.flat_map { |m| m.columns.select {|c| c.name =~ /amount/ || c.comment =~ /金额/ }.map {|c| "Table: #{m.table_name}, Column: #{c.name} (#{c.comment})"} }
|
1072
|
+
|
1073
|
+
# 输出:
|
1074
|
+
# Table: order, Column: entry_amount (订单金额)
|
1075
|
+
# Table: sub_order, Column: entry_price (金额)
|
1076
|
+
#+END_SRC
|
1077
|
+
|
1078
|
+
** 开发
|
1079
|
+
|
1080
|
+
检出代码后,运行 =bin/setup= 安装依赖。你也可以运行 =bin/console= 进入交互式控制台。
|
1081
|
+
|
1082
|
+
运行 =bundle exec rake install= 将这个 gem 安装到本地。发布新版本时,更新 =version.rb= 中的版本号,然后运行 =bundle
|
1083
|
+
exec rake release= ,这将为该版本创建一个 git 标签,推送 git 提交和标签,并将 =.gem= 文件推送到 [[https://rubygems.org][rubygems.org]]。
|
1084
|
+
|
1085
|
+
** 贡献代码
|
1086
|
+
|
1087
|
+
欢迎在 GitHub 上提交 bug 报告和 pull request: https://github.com/lululau/arql 。这个项目旨在成为一个安全、友好的协作
|
1088
|
+
空间,期望贡献者遵守 [[https://github.com/lululau/arql/blob/master/CODE_OF_CONDUCT.md][行为准则]]。
|
1089
|
+
|
1090
|
+
** 许可证
|
1091
|
+
|
1092
|
+
这个 gem 是根据 [[https://opensource.org/licenses/MIT][MIT License]] 条款开源的。
|
1093
|
+
|
1094
|
+
** Code of Conduct
|
1095
|
+
|
1096
|
+
与 Arql 项目的代码库、问题跟踪器、聊天室和邮件列表中的每个人都应遵守 [[https://github.com/lululau/arql/blob/master/CODE_OF_CONDUCT.md][行为准则]]。
|