arql 0.3.30 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.vscode/launch.json +1 -1
- data/Gemfile.lock +1 -1
- data/README-zh_CN.org +712 -429
- data/README.org +3 -0
- data/auto-set-id-before-save-zh_CN.org +1 -1
- data/custom-configurations-zh_CN.org +40 -3
- data/define-associations-zh_CN.org +31 -17
- data/initializer-structure-zh_CN.org +22 -4
- data/lib/arql/app.rb +98 -71
- data/lib/arql/cli.rb +31 -15
- data/lib/arql/commands/info.rb +41 -28
- data/lib/arql/commands/models.rb +108 -33
- data/lib/arql/commands/reconnect.rb +8 -4
- data/lib/arql/commands/redefine.rb +3 -1
- data/lib/arql/commands/sandbox.rb +6 -4
- data/lib/arql/commands.rb +0 -2
- data/lib/arql/concerns/global_data_definition.rb +40 -6
- data/lib/arql/concerns/model_extension.rb +168 -0
- data/lib/arql/concerns/table_data_definition.rb +20 -20
- data/lib/arql/concerns.rb +1 -0
- data/lib/arql/definition.rb +169 -317
- data/lib/arql/ext/active_record/relation.rb +29 -0
- data/lib/arql/ext/active_record/result.rb +29 -0
- data/lib/arql/ext/array.rb +40 -1
- data/lib/arql/ext/kernel.rb +70 -61
- data/lib/arql/ext/object.rb +14 -0
- data/lib/arql/ext/ransack/search.rb +29 -0
- data/lib/arql/mysqldump.rb +0 -1
- data/lib/arql/ssh_proxy.rb +25 -22
- data/lib/arql/version.rb +1 -1
- data/lib/arql.rb +11 -7
- data/ruby-guides-for-java-developer-zh_CN.org +766 -0
- data/simple-active-record-guide-zh_CN.org +83 -0
- data/simple-pry-guides-zh_CN.org +114 -0
- data/sql-log-zh_CN.org +8 -3
- metadata +9 -5
- data/lib/arql/commands/table.rb +0 -55
- data/lib/arql/commands/vd.rb +0 -46
- data/lib/arql/connection.rb +0 -16
data/README-zh_CN.org
CHANGED
@@ -29,7 +29,6 @@
|
|
29
29
|
#+end_example
|
30
30
|
|
31
31
|
** 使用方法
|
32
|
-
|
33
32
|
*** 命令行选项
|
34
33
|
|
35
34
|
#+begin_example
|
@@ -73,7 +72,33 @@
|
|
73
72
|
|
74
73
|
**** =-e, --env=ENVIRON=
|
75
74
|
|
76
|
-
|
75
|
+
指定一个或多个在配置文件中的环境名称,多个环境名称之间用逗号/加号/冒号分隔。
|
76
|
+
|
77
|
+
Arql 为每个环境所生成的模型类将放在该环境的 =namespace= 配置所指定的命名空间下。例如:
|
78
|
+
|
79
|
+
#+BEGIN_SRC yaml
|
80
|
+
development:
|
81
|
+
adapter: mysql2
|
82
|
+
host: localhost
|
83
|
+
username: root
|
84
|
+
database: myapp_development
|
85
|
+
pool: 5
|
86
|
+
namespace: Dev
|
87
|
+
#+END_SRC
|
88
|
+
|
89
|
+
假设 =myapp_development= 数据库中有一个名为 =users=, =posts= 等表,那么在 =development= 环境下生成的模型类将是:
|
90
|
+
|
91
|
+
+ =Dev::User=
|
92
|
+
+ =Dev::Post=
|
93
|
+
|
94
|
+
如果没有指定 =namespace= 配置,那么默认的命名空间为环境名称的 CamelCase 形式。例如这里的 =Development=, 那么生成的模型类将是:
|
95
|
+
|
96
|
+
+ =Development::User=
|
97
|
+
+ =Development::Post=
|
98
|
+
|
99
|
+
Arql 通过覆盖 =Object.const_missing= 的方式,为那些类名和已有常量不重名的模型类,在顶层命名空间下也定义了一个「别名」,例如在不和已有常量重名的情况下,可以直接使用 =User=, =Post= 等类名。
|
100
|
+
|
101
|
+
如果指定的多个环境中有重名的表,那么按照指定的环境的顺序,将为前面的环境中的表的模型类定义一个「别名」
|
77
102
|
|
78
103
|
**** =-E, --eval=CODE=
|
79
104
|
|
@@ -166,6 +191,28 @@
|
|
166
191
|
6. =ssh.password= : ssh 密码
|
167
192
|
7. =ssh.local_port= : ssh 本地端口
|
168
193
|
8. =singularized_table_names=: 是否使用单数表名,默认为 =false=, 如果为 =false=, 则 =students= 表将定义为 =Student= 模型,如果为 =true=, 则 =students= 表将定义为 =Students= 模型
|
194
|
+
9. =table_name_prefixes=: 表名前缀数组,默认为空数组,如果指定了此项,在生成模型时将忽略这些前缀,例如,如果指定了 =["t_"]=, 则 =t_students= 表将定义为 =Student= 模型
|
195
|
+
10. =namespace=: 模型命名空间,默认为环境名称的 CamelCase 形式,生成的模型将放在指定的命名空间下
|
196
|
+
11. =model_names=: 这个配置项的值是一个 Hash(Map) , Key 为表名, Value 为将要为该表生成的模型名称; Arql 默认使用
|
197
|
+
ActiveRecord 的命名规则生成模型名称,如果指定了这个配置项,该配置项所指定的表将使用改配置项指定的模型名称Value
|
198
|
+
除了可以是表示模型名称的字符串外,还可以是一个字符串数组,数组的第一个元素表示模型名称,第二个元素表示为该模型创
|
199
|
+
建的常量别名(Arql 默认也会按照一定的规则自动为生成的模型类创建别名,如果这里指定了别名,将会使用用户提供的值作
|
200
|
+
为别名)
|
201
|
+
|
202
|
+
=model_names= 配置项的例子:
|
203
|
+
|
204
|
+
#+BEGIN_SRC yaml
|
205
|
+
development:
|
206
|
+
host: localhost
|
207
|
+
database: test
|
208
|
+
username: root
|
209
|
+
model_names:
|
210
|
+
students: Seito
|
211
|
+
teachers: ["LaoShi", "LS"]
|
212
|
+
#+END_SRC
|
213
|
+
|
214
|
+
以上配置文件中,将为 =students= 表生成一个名为 =Seito= 的模型,为 =teachers= 表生成一个名为 =LaoShi= 的模型,并为该模型创建一个名为 =LS= 的常量别名;
|
215
|
+
还会为 =students= 表生成一个别名: =S=
|
169
216
|
|
170
217
|
**** 配置文件示例
|
171
218
|
|
@@ -182,7 +229,9 @@
|
|
182
229
|
username: root
|
183
230
|
database: blog
|
184
231
|
password:
|
232
|
+
table_name_prefixes: ["t_"]
|
185
233
|
socket: /tmp/mysql.sock
|
234
|
+
namespace: B
|
186
235
|
|
187
236
|
dev:
|
188
237
|
<<: *default
|
@@ -191,6 +240,8 @@
|
|
191
240
|
username: root
|
192
241
|
password: 123456
|
193
242
|
database: blog
|
243
|
+
table_name_prefixes: ["t_"]
|
244
|
+
namespace: B
|
194
245
|
ssh:
|
195
246
|
host: dev.mycompany.com
|
196
247
|
port: 22
|
@@ -224,7 +275,7 @@
|
|
224
275
|
=info= 命令打印当前的数据库连接信息和 SSH 代理信息,例如:
|
225
276
|
|
226
277
|
#+begin_example
|
227
|
-
Database Connection Information:
|
278
|
+
my_env Database Connection Information:
|
228
279
|
Host:
|
229
280
|
Port:
|
230
281
|
Username: root
|
@@ -235,6 +286,12 @@
|
|
235
286
|
Pool Size: 5
|
236
287
|
#+end_example
|
237
288
|
|
289
|
+
=info= 默认显示指定的所有环境的连接信息,如果只想显示当前环境的连接信息, =info= 命令接受一个正则表达式参数,只显示匹配的环境信息,例如:
|
290
|
+
|
291
|
+
#+BEGIN_EXAMPLE
|
292
|
+
info .*dev
|
293
|
+
#+END_EXAMPLE
|
294
|
+
|
238
295
|
**** =m= 或者 =l=
|
239
296
|
|
240
297
|
=m= (或者 =l= ) 命令打印所有表名及对应的模型类名和缩写类名,例如:
|
@@ -262,9 +319,24 @@
|
|
262
319
|
- =Abbr= : 缩写类名
|
263
320
|
- =Comment= : 注释
|
264
321
|
|
265
|
-
=m= / =l=
|
322
|
+
=m= / =l= 命令三个可选的选项:
|
323
|
+
|
324
|
+
+ =-e=, =--env= : 指定环境,正则表达式,只显示匹配的环境下的表名,默认显示所有环境
|
325
|
+
+ =-f=, =--format= : 输出格式:
|
326
|
+
- =terminal= : 默认的表格格式
|
327
|
+
- =md= : markdown 表格格式
|
328
|
+
- =org= : org mode 表格格式
|
329
|
+
- =sql= : 输出 create table SQL
|
330
|
+
+ =-c=, =--column= : 正则表达式,列出字段,而不是表,按照字段名或字段注释筛选
|
266
331
|
|
267
|
-
=m
|
332
|
+
=m= / =l= 命令还可以接受一个可选的正则表达式参数,只显示(按照表名或表注释)匹配的表的信息,例如:
|
333
|
+
|
334
|
+
#+BEGIN_EXAMPLE
|
335
|
+
l # 显示所有表的信息
|
336
|
+
l ^post # 只显示表名以 post 开头的表的信息
|
337
|
+
l -e dev -f md # 显示 dev 环境下的表信息,并以 markdown 格式输出
|
338
|
+
l -c no|num # 只显示字段名、字段注释中包含 no 或 num 的字段信息
|
339
|
+
#+END_EXAMPLE
|
268
340
|
|
269
341
|
**** =t=
|
270
342
|
|
@@ -346,9 +418,9 @@
|
|
346
418
|
=redefine= 命令用于重新定义 ActiveRecord 模型类,根据数据库表的信息重新生成模型类。对于在 =init.rb= 中添加了新的关
|
347
419
|
系定义,想使新定义的关系在当前 Pry 会话中生效,可以使用 =redefine= 命令。
|
348
420
|
|
349
|
-
****
|
421
|
+
**** =sandbox-enter= 和 =sandbox-quit=
|
350
422
|
|
351
|
-
=sandbox-enter=
|
423
|
+
=sandbox-enter= 命令用于开启沙盒模式。在沙盒模式下,所有的数据库操作都会在事务中执行,该事务不会自动提交,退出沙盒模式时,会自动回滚事务。
|
352
424
|
|
353
425
|
1. 开启沙盒模式:
|
354
426
|
#+begin_example
|
@@ -358,19 +430,7 @@
|
|
358
430
|
2. 退出沙盒模式:
|
359
431
|
#+begin_example
|
360
432
|
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
433
|
#+end_example
|
368
|
-
4. 回滚事务:
|
369
|
-
#+begin_example
|
370
|
-
ARQL@demo247(main) [7] ❯ $C.rollback_transaction
|
371
|
-
#+end_example
|
372
|
-
|
373
|
-
|
374
434
|
|
375
435
|
*** 作为代码解释器使用
|
376
436
|
|
@@ -408,23 +468,79 @@
|
|
408
468
|
$ echo 'puts Person.count' | arql -e dev
|
409
469
|
#+end_example
|
410
470
|
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
可以在任何 ActiveRecord 模型实例上调用 =to_insert_sql= / =to_upsert_sql= 方法,获取该对象的插入或更新 SQL 语句。
|
415
|
-
这两个方法也可以在包含 ActiveRecord 模型实例对象的数组对象上调用。
|
471
|
+
** 额外的扩展方法
|
472
|
+
*** 命名空间模块的模块方法
|
473
|
+
**** =q=
|
416
474
|
|
475
|
+
=q= 用于执行 SQL 查询
|
476
|
+
|
417
477
|
#+begin_example
|
418
|
-
ARQL ❯
|
419
|
-
=>
|
478
|
+
ARQL ❯ rs = Blog::q 'select count(0) from person;'
|
479
|
+
=> #<ActiveRecord::Result:0x00007fd1f8026ad0 @column_types={}, @columns=["count(0)"], @hash_rows=nil, @rows=[[11]]>
|
480
|
+
ARQL ❯ rs.rows
|
481
|
+
=> [[11]]
|
420
482
|
#+end_example
|
483
|
+
**** =models=
|
484
|
+
|
485
|
+
=models= 返回该命名空间下的所有模型类
|
486
|
+
|
487
|
+
#+begin_example
|
488
|
+
ARQL ❯ Blog::models
|
489
|
+
=> [Blog::Person(id: integer, name: string, age: integer, created_at: datetime, updated_at: datetime), Blog::Post(id: integer, title: string, content: text, created_at: datetime, updated_at: datetime)]
|
490
|
+
#+end_example
|
491
|
+
|
492
|
+
**** =tables=
|
493
|
+
|
494
|
+
=tables= 返回该命名空间下的所有表名
|
495
|
+
|
496
|
+
#+begin_example
|
497
|
+
ARQL ❯ Blog::tables
|
498
|
+
=> ["people", "posts"]
|
499
|
+
#+end_example
|
500
|
+
|
501
|
+
**** =model_names=
|
502
|
+
|
503
|
+
=model_names= 返回该命名空间下的所有模型类的名称
|
504
|
+
|
505
|
+
#+begin_example
|
506
|
+
ARQL ❯ Blog::model_names
|
507
|
+
=> ["Demo::Person", "Demo::Post"]
|
508
|
+
#+end_example
|
509
|
+
|
510
|
+
**** =create_table=
|
511
|
+
|
512
|
+
=create_table= 用于在该命名空间所对应的环境中创建表
|
513
|
+
|
514
|
+
#+begin_example
|
515
|
+
ARQL ❯ Blog::create_table :people do |t|
|
516
|
+
ARQL ❯ t.string :name
|
517
|
+
ARQL ❯ t.integer :age
|
518
|
+
ARQL ❯ t.timestamps
|
519
|
+
ARQL ❯ end
|
520
|
+
#+end_example
|
521
|
+
|
522
|
+
**** =dump=
|
523
|
+
|
524
|
+
=dump= 通过 =mysqldump= 将该命名空间对应的数据库导出到指定的文件中
|
525
|
+
|
526
|
+
#+begin_example
|
527
|
+
ARQL ❯ Blog::dump('~/data/blog.sql')
|
528
|
+
#+end_example
|
529
|
+
|
530
|
+
*** 模型的类方法
|
531
|
+
|
532
|
+
Pry 内建了 =show-source= (别名 =$= ) 和 =show-doc= (别名 =?= )命令,可以查看方法的源码和文档。可以通过 =show-doc= 查看方法的文档。例如:
|
421
533
|
|
534
|
+
#+BEGIN_EXAMPLE
|
535
|
+
ARQL ❯ ? Student.add_column
|
536
|
+
#+END_EXAMPLE
|
537
|
+
|
422
538
|
**** =to_create_sql=
|
423
539
|
|
424
540
|
可以在任何 ActiveRecord 模型类上调用 =to_create_sql= 方法,获取该模型类对应的表的创建 SQL 语句。
|
425
541
|
|
426
542
|
#+begin_example
|
427
|
-
ARQL@demo247(main) [16] ❯ puts Post.to_create_sql
|
543
|
+
ARQL@demo247(main) [16] ❯ puts Blog::Post.to_create_sql
|
428
544
|
D, [2024-04-07T14:15:11.106693 #20440] DEBUG -- : SQL (24.9ms) show create table post
|
429
545
|
CREATE TABLE `post` (
|
430
546
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
|
@@ -440,6 +556,167 @@
|
|
440
556
|
) ENGINE=InnoDB AUTO_INCREMENT=83 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
|
441
557
|
#+end_example
|
442
558
|
|
559
|
+
**** =t=
|
560
|
+
|
561
|
+
=t= 类方法用于打印模型类的表结构
|
562
|
+
|
563
|
+
执行 =Blog::Person.t= 命令会打印 =person= 表的定义信息:
|
564
|
+
|
565
|
+
#+begin_example
|
566
|
+
Table: person
|
567
|
+
+----|------------|------------------|-----------|-------|-----------|-------|---------|----------|---------+
|
568
|
+
| PK | Name | SQL Type | Ruby Type | Limit | Precision | Scale | Default | Nullable | Comment |
|
569
|
+
+----|------------|------------------|-----------|-------|-----------|-------|---------|----------|---------+
|
570
|
+
| Y | id | int(11) unsigned | integer | 4 | | | | false | |
|
571
|
+
| | name | varchar(64) | string | 64 | | | | true | |
|
572
|
+
| | age | int(11) | integer | 4 | | | | true | |
|
573
|
+
| | gender | int(4) | integer | 4 | | | | true | |
|
574
|
+
| | grade | int(4) | integer | 4 | | | | true | |
|
575
|
+
| | blood_type | varchar(4) | string | 4 | | | | true | |
|
576
|
+
+----|------------|------------------|-----------|-------|-----------|-------|---------|----------|---------+
|
577
|
+
#+end_example
|
578
|
+
|
579
|
+
=t= 接受一个可选的 =format= 命名参数,可选值为:
|
580
|
+
|
581
|
+
+ =md=
|
582
|
+
+ =org=
|
583
|
+
+ =sql=
|
584
|
+
+ =terminal= (默认值)
|
585
|
+
|
586
|
+
例如:
|
587
|
+
|
588
|
+
#+begin_example
|
589
|
+
ARQL ❯ Blog::Person.t :sql
|
590
|
+
#+end_example
|
591
|
+
|
592
|
+
输出:
|
593
|
+
|
594
|
+
#+begin_example
|
595
|
+
CREATE TABLE `person` (
|
596
|
+
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
|
597
|
+
`name` varchar(64) DEFAULT NULL,
|
598
|
+
`age` int(11) DEFAULT NULL,
|
599
|
+
`gender` int(4) DEFAULT NULL,
|
600
|
+
`grade` int(4) DEFAULT NULL,
|
601
|
+
`blood_type` varchar(4) DEFAULT NULL,
|
602
|
+
PRIMARY KEY (`id`)
|
603
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='人员表';
|
604
|
+
#+end_example
|
605
|
+
|
606
|
+
**** =v=
|
607
|
+
|
608
|
+
=v= 类方法用于和 Emacs 的 org babel 集成,可以在 org 文件中直接调用 =v= 方法,获取模型类的表结构。
|
609
|
+
|
610
|
+
例如:
|
611
|
+
|
612
|
+
#+begin_example
|
613
|
+
ARQL ❯ Blog::Post.v
|
614
|
+
#+end_example
|
615
|
+
|
616
|
+
输出:
|
617
|
+
|
618
|
+
#+BEGIN_EXAMPLE
|
619
|
+
ARQL@demo247(main) [10] ❯ Demo::Post.v
|
620
|
+
=> [["PK", "Name", "SQL Type", "Ruby Type", "Limit", "Precision", "Scale", "Default", "Nullable", "Comment"],
|
621
|
+
nil,
|
622
|
+
["Y", "id", "int(10) unsigned", :integer, 4, "", "", "", false, "ID"],
|
623
|
+
["", "name", "varchar(256)", :string, 256, "", "", "", true, ""],
|
624
|
+
["", "gender", "varchar(256)", :string, 256, "", "", "", true, ""],
|
625
|
+
["", "phone", "varchar(256)", :string, 256, "", "", "", true, ""],
|
626
|
+
["", "id_no", "varchar(256)", :string, 256, "", "", "", true, ""],
|
627
|
+
["", "note", "varchar(256)", :string, 256, "", "", "", true, ""],
|
628
|
+
["", "gmt_created", "datetime", :datetime, "", 0, "", "", false, "创建时间"],
|
629
|
+
["", "gmt_modified", "datetime", :datetime, "", 0, "", "", false, "最后修改时间"],
|
630
|
+
["", "sasa", "varchar(255)", :string, 255, "", "", "", true, ""]]
|
631
|
+
#+END_EXAMPLE
|
632
|
+
|
633
|
+
**** =vd=
|
634
|
+
|
635
|
+
使用 =visidata= 显示表结构
|
636
|
+
**** =table_comment=
|
637
|
+
|
638
|
+
返回该模型的表注释
|
639
|
+
|
640
|
+
例如:
|
641
|
+
|
642
|
+
#+begin_example
|
643
|
+
ARQL ❯ Blog::Post.table_comment
|
644
|
+
#+end_example
|
645
|
+
|
646
|
+
输出:
|
647
|
+
|
648
|
+
#+begin_example
|
649
|
+
"文章表"
|
650
|
+
#+end_example
|
651
|
+
|
652
|
+
**** 添加字段 =add_column=
|
653
|
+
#+BEGIN_EXAMPLE
|
654
|
+
Blog::Student.add_column :note, :text, comment: '备注'
|
655
|
+
#+END_EXAMPLE
|
656
|
+
|
657
|
+
**** 修改字段 =change_column=
|
658
|
+
#+BEGIN_EXAMPLE
|
659
|
+
Blog::Student.change_column :note, :string, comment: '备注'
|
660
|
+
#+END_EXAMPLE
|
661
|
+
|
662
|
+
**** 删除字段 =remove_column=
|
663
|
+
#+BEGIN_EXAMPLE
|
664
|
+
Blog::Student.remove_column :note
|
665
|
+
#+END_EXAMPLE
|
666
|
+
|
667
|
+
**** 添加索引 =add_index=
|
668
|
+
#+BEGIN_EXAMPLE
|
669
|
+
Blog::Student.add_index :name
|
670
|
+
Blog::Student.add_index [:branch_id, :party_id], unique: true, name: 'by_branch_party'
|
671
|
+
#+END_EXAMPLE
|
672
|
+
|
673
|
+
**** 修改字段注释 =change_column_comment=
|
674
|
+
#+BEGIN_EXAMPLE
|
675
|
+
Blog::Student.change_column_comment :note, '备注'
|
676
|
+
#+END_EXAMPLE
|
677
|
+
|
678
|
+
**** 修改字段默认值 =change_column_default=
|
679
|
+
#+BEGIN_EXAMPLE
|
680
|
+
Blog::Student.change_column_default :note, '默认值'
|
681
|
+
#+END_EXAMPLE
|
682
|
+
|
683
|
+
**** 修改字段名称 =rename_column=
|
684
|
+
#+BEGIN_EXAMPLE
|
685
|
+
Blog::Student.rename_column :note, :remark
|
686
|
+
#+END_EXAMPLE
|
687
|
+
|
688
|
+
**** 修改表名 =rename_table=
|
689
|
+
#+BEGIN_EXAMPLE
|
690
|
+
Blog::Student.rename_table :seitou
|
691
|
+
#+END_EXAMPLE
|
692
|
+
|
693
|
+
**** 修改表注释 =change_table_comment=
|
694
|
+
#+BEGIN_EXAMPLE
|
695
|
+
Blog::Student.change_table_comment from: '', to: '学生表'
|
696
|
+
#+END_EXAMPLE
|
697
|
+
|
698
|
+
**** 删除表 =drop_table=
|
699
|
+
#+BEGIN_EXAMPLE
|
700
|
+
Blog::Student.drop_table
|
701
|
+
#+END_EXAMPLE
|
702
|
+
|
703
|
+
**** 删除索引 =remove_index=
|
704
|
+
#+BEGIN_EXAMPLE
|
705
|
+
Blog::Student.remove_index :age
|
706
|
+
Blog::Student.remove_index name: 'by_branch_party'
|
707
|
+
#+END_EXAMPLE
|
708
|
+
|
709
|
+
**** 查询表注释 =table_comment=
|
710
|
+
#+BEGIN_EXAMPLE
|
711
|
+
Blog::Student.table_comment
|
712
|
+
#+END_EXAMPLE
|
713
|
+
|
714
|
+
**** 列出表的索引 =indexes=
|
715
|
+
#+BEGIN_EXAMPLE
|
716
|
+
Blog::Student.indexes
|
717
|
+
#+END_EXAMPLE
|
718
|
+
|
719
|
+
*** 模型的实例方法
|
443
720
|
**** =t=
|
444
721
|
|
445
722
|
=t= 除了可以作为类方法在 ActiveRecord 模型类上调用,也可以作为实例方法在 ActiveRecord 模型实例对象上调用。
|
@@ -460,22 +737,31 @@
|
|
460
737
|
|
461
738
|
=t= 方法可以接受以下两个选项:
|
462
739
|
|
463
|
-
+ =:except= 选项,用于指定不显示的属性名,值可以是字符串或正则表达式,例如:
|
464
|
-
#+BEGIN_EXAMPLE
|
465
|
-
Person.last.t(except: 'id')
|
466
|
-
Student.where(condition).t(except: /id|name/)
|
467
|
-
#+END_EXAMPLE
|
468
740
|
+ =:compact= 选项,用于指定是否紧凑显示,值可以是 =true= 或 =false= ,如果启用紧凑显示,那些值全部为 =NULL= 的列将不
|
469
741
|
会显示,这对于查看那些数据稀疏的表很有帮助,例如:
|
470
742
|
#+BEGIN_EXAMPLE
|
471
743
|
Person.last.t(compact: true)
|
472
744
|
Student.where(condition).t(compact: false)
|
473
745
|
#+END_EXAMPLE
|
746
|
+
+ =:format= 选项,用于指定输出格式,值可以是:
|
747
|
+
- =:terminal= 默认的输出格式,适合在终端中查看
|
748
|
+
- =:org= org-mode 表格格式
|
749
|
+
- =:md= markdown 表格格式
|
750
|
+
|
751
|
+
**** =to_insert_sql= / =to_upsert_sql=
|
752
|
+
|
753
|
+
可以在任何 ActiveRecord 模型实例上调用 =to_insert_sql= / =to_upsert_sql= 方法,获取该对象的插入或更新 SQL 语句。
|
754
|
+
这两个方法也可以在包含 ActiveRecord 模型实例对象的数组对象上调用。
|
755
|
+
|
756
|
+
#+begin_example
|
757
|
+
ARQL ❯ Person.all.to_a.to_insert_sql
|
758
|
+
=> "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`;"
|
759
|
+
#+end_example
|
474
760
|
|
475
761
|
**** =v=
|
476
762
|
|
477
763
|
=v= 方法用于与 Emacs org babel 集成。
|
478
|
-
|
764
|
+
|
479
765
|
***** =v= 作为模型类的实例方法
|
480
766
|
|
481
767
|
在任何 ActiveRecord 模型实例对象上调用 =v= 方法,可以打印一个数组,数组的第一个元素是 =['Attribute Name',
|
@@ -521,530 +807,537 @@
|
|
521
807
|
=> [[:name, :age], nil, ["Jack", 10], ["Lucy", 20]]
|
522
808
|
#+end_example
|
523
809
|
|
524
|
-
**** =q=
|
525
810
|
|
526
|
-
|
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
|
811
|
+
**** =dump=
|
532
812
|
|
533
|
-
|
534
|
-
|
535
|
-
在任何对象上调用 =j= 方法,可以得到 JSON 格式的字符串,调用 =jj= 方法可以得到格式化后的 JSON 字符串。
|
813
|
+
将实例对象导出为 =INSERT= SQL 语句,见下文 「dump 数据」章节
|
536
814
|
|
537
|
-
|
815
|
+
**** =write_excel= / =write_csv=
|
538
816
|
|
539
|
-
|
817
|
+
将实例对象导出为 Excel 或 CSV 文件,见下文 「读写 Excel 和 CSV 文件」章节
|
818
|
+
|
819
|
+
*** =ActiveRecord::Relation= / =ActiveRecord::Result= / =Ransack::Search= / =Array= 上的一些通用扩展方法
|
820
|
+
=ActiveRecord::Relation= / =ActiveRecord::Result= / =Ransack::Search= 在逻辑上都可以看成是数组,所以这些方法都可以在这些对象上调用:
|
821
|
+
**** =t=
|
540
822
|
|
541
|
-
|
823
|
+
=t= 方法还可以在包含 ActiveRecord 实例的数组上调用,也可以在 =ActiveRecord::Relation= / =ActiveRecord::Result= / =Ransack::Search= 对象上调用。
|
824
|
+
|
825
|
+
#+begin_example
|
826
|
+
ARQL ❯ Person.last.t
|
827
|
+
+----------------|-----------------|------------------|---------+
|
828
|
+
| Attribute Name | Attribute Value | SQL Type | Comment |
|
829
|
+
+----------------|-----------------|------------------|---------+
|
830
|
+
| id | 11 | int(11) unsigned | |
|
831
|
+
| name | Jackson | varchar(64) | |
|
832
|
+
| age | 30 | int(11) | |
|
833
|
+
| gender | 2 | int(4) | |
|
834
|
+
| grade | 2 | int(4) | |
|
835
|
+
| blood_type | AB | varchar(4) | |
|
836
|
+
+----------------|-----------------|------------------|---------+
|
837
|
+
#+end_example
|
542
838
|
|
543
|
-
|
839
|
+
作为数组和「类数组」对象实例方法时, =t= 方法可以接受多个用于过滤属性的参数,参数的类型可以是:
|
544
840
|
|
545
|
-
|
546
|
-
|
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
|
841
|
+
+ 字符串或 Symbol,对属性进行字面量匹配
|
842
|
+
+ 正则表达式,对属性进行正则匹配
|
554
843
|
|
555
|
-
|
844
|
+
例如, 只显示 =name=, =age= 以及所有名称包含 =time= 字样的属性:
|
556
845
|
|
557
846
|
#+begin_example
|
558
|
-
ARQL ❯
|
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
|
847
|
+
ARQL ❯ Person.last(10).t('name', :age, /time/i)
|
564
848
|
#+end_example
|
565
|
-
|
566
|
-
***** 添加字段
|
567
849
|
|
568
|
-
|
569
|
-
$C.add_column :post, :note, :string, comment: '备注'
|
570
|
-
#+end_example
|
850
|
+
作为数组和「类数组」对象的实例方法的 =t= 还可以接受以下三个选项:
|
571
851
|
|
572
|
-
|
852
|
+
+ =:except= 选项,用于指定不显示的属性名,值可以是字符串或正则表达式,例如:
|
853
|
+
#+BEGIN_EXAMPLE
|
854
|
+
Person.last(10).t(except: 'id')
|
855
|
+
Student.where(condition).t(except: /id|name/)
|
856
|
+
#+END_EXAMPLE
|
857
|
+
+ =:compact= 选项,用于指定是否紧凑显示,值可以是 =true= 或 =false= ,如果启用紧凑显示,那些值全部为 =NULL= 的列将不
|
858
|
+
会显示,这对于查看那些数据稀疏的表很有帮助,例如:
|
859
|
+
#+BEGIN_EXAMPLE
|
860
|
+
Person.last(10).t(compact: true)
|
861
|
+
Student.where(condition).t(compact: false)
|
862
|
+
#+END_EXAMPLE
|
863
|
+
+ =:format= 选项,用于指定输出格式,值可以是:
|
864
|
+
- =:terminal= 默认的输出格式,适合在终端中查看
|
865
|
+
- =:org= org-mode 表格格式
|
866
|
+
- =:md= markdown 表格格式
|
573
867
|
|
868
|
+
**** =v=
|
869
|
+
=v= 方法用于与 Emacs org babel 集成。
|
870
|
+
|
574
871
|
#+begin_example
|
575
|
-
|
872
|
+
ARQL ❯ Person.last.v
|
873
|
+
=> [["Attribute Name", "Attribute Value", "SQL Type", "Comment"],
|
874
|
+
nil,
|
875
|
+
["id", 11, "int(11) unsigned", ""],
|
876
|
+
["name", "Jackson", "varchar(64)", ""],
|
877
|
+
["age", 30, "int(11)", ""],
|
878
|
+
["gender", 2, "int(4)", ""],
|
879
|
+
["grade", 2, "int(4)", ""],
|
880
|
+
["blood_type", "AB", "varchar(4)", ""]]
|
576
881
|
#+end_example
|
882
|
+
**** =vd=
|
577
883
|
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
884
|
+
使用 =visidata= 显示「数组」数据
|
885
|
+
|
886
|
+
**** =write_csv= / =write_excel=
|
887
|
+
|
888
|
+
=write_csv= 和 =write_excel= 用于将「数组」数据导出为 CSV 或 Excel 文件,见下文 「读写 Excel 和 CSV 文件」章节
|
889
|
+
|
890
|
+
**** =dump=
|
583
891
|
|
584
|
-
=
|
892
|
+
=dump= 方法用于将 ActiveRecord::Relation / ActiveRecord::Result / Ransack::Search 对象导出为 INSERT SQL 语句,见下文 「dump 数据」章节
|
893
|
+
|
894
|
+
*** =Kernel= 扩展方法
|
585
895
|
|
586
|
-
|
587
|
-
Post.change_column :note, :text, comment: '备注'
|
588
|
-
#+end_example
|
896
|
+
下列对应某种 DDL 操作的方法,在使用时都有一个限制:如果连接了多个环境,那么在调用这些方法时,必须通过 =:env= 选项指定环境名。例如:
|
589
897
|
|
590
|
-
|
898
|
+
#+BEGIN_SRC ruby
|
899
|
+
create_table :users, env: 'development', comment: '用户表' do |t|
|
900
|
+
t.string :name, comment: '姓名'
|
901
|
+
t.integer :age, comment: '年龄'
|
902
|
+
end
|
903
|
+
#+END_SRC
|
904
|
+
|
905
|
+
**** 创建表 =create_table=
|
906
|
+
#+BEGIN_EXAMPLE
|
907
|
+
create_table :post, id: false, primary_key: :id do |t|
|
908
|
+
t.column :id, :bigint, precison: 19, comment: 'ID'
|
909
|
+
t.column :name, :string, comment: '名称'
|
910
|
+
t.column :gmt_created, :datetime, comment: '创建时间'
|
911
|
+
t.column :gmt_modified, :datetime, comment: '最后修改时间'
|
912
|
+
end
|
913
|
+
#+END_EXAMPLE
|
914
|
+
**** 创建多对多关系的中间表 =create_join_table=
|
915
|
+
#+BEGIN_EXAMPLE
|
916
|
+
create_join_table :products, :categories do |t|
|
917
|
+
t.index :product_id
|
918
|
+
t.index :category_id
|
919
|
+
end
|
920
|
+
#+END_EXAMPLE
|
921
|
+
**** 删除表 =drop_table=
|
922
|
+
#+BEGIN_EXAMPLE
|
923
|
+
drop_table :post
|
924
|
+
#+END_EXAMPLE
|
925
|
+
**** 删除多对多关系的中间表 =drop_join_table=
|
926
|
+
#+BEGIN_EXAMPLE
|
927
|
+
drop_join_table :products, :categories
|
928
|
+
#+END_EXAMPLE
|
929
|
+
**** 修改表名 =rename_table=
|
930
|
+
#+BEGIN_EXAMPLE
|
931
|
+
rename_table :post, :posts
|
932
|
+
#+END_EXAMPLE
|
591
933
|
|
592
|
-
|
593
|
-
|
594
|
-
#+end_example
|
934
|
+
|
935
|
+
**** =models=
|
595
936
|
|
596
|
-
|
937
|
+
返回将所有环境命名空间下的模型类
|
597
938
|
|
598
|
-
|
599
|
-
Post.remove_column :note
|
600
|
-
#+end_example
|
939
|
+
**** =table_names=
|
601
940
|
|
602
|
-
|
603
|
-
|
604
|
-
#+begin_example
|
605
|
-
$C.drop_table :post
|
606
|
-
#+end_example
|
941
|
+
返回所有环境下的表名
|
607
942
|
|
608
|
-
|
943
|
+
**** =model_names=
|
609
944
|
|
610
|
-
|
611
|
-
Post.drop_table
|
612
|
-
#+end_example
|
945
|
+
返回所有环境下的模型类名
|
613
946
|
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
947
|
+
**** =q=
|
948
|
+
|
949
|
+
如果只指定了一个环境,那么可以直接使用 =q= 方法来执行原生 SQL 查询,而不需要在 =q= 前面指定命名空间模块,如 =Blog::q=
|
950
|
+
|
951
|
+
*** 其它扩展方法
|
952
|
+
**** JSON 转换和格式化
|
953
|
+
|
954
|
+
在任何对象上调用 =j= 方法,可以得到 JSON 格式的字符串,调用 =jj= 方法可以得到格式化后的 JSON 字符串。
|
620
955
|
|
621
|
-
|
956
|
+
使用 =jp= 方法打印 JSON,使用 =jjp= 方法打印格式化后的 JSON。
|
957
|
+
|
958
|
+
**** =String=
|
959
|
+
|
960
|
+
***** =Srting#p=
|
961
|
+
|
962
|
+
=p= 方法的定义如下:
|
622
963
|
|
623
964
|
#+begin_example
|
624
|
-
|
625
|
-
|
965
|
+
class String
|
966
|
+
def p
|
967
|
+
puts self
|
968
|
+
end
|
969
|
+
end
|
626
970
|
#+end_example
|
627
971
|
|
628
|
-
|
629
|
-
|
630
|
-
=Kernel= 模块下的函数可以想语言内置函数一样直接调用,不需要指定模块名。 以下是 Arql 扩展的 =Kernel= 方法:
|
972
|
+
="hello".p= 等价于 =puts "hello"= 。
|
631
973
|
|
632
|
-
|
974
|
+
***** =String#parse=
|
633
975
|
|
634
|
-
|
635
|
-
ARQL ❯ ? create_table
|
636
|
-
#+END_EXAMPLE
|
976
|
+
对于一个表示文件路径的字符串,可以调用 =parse= 方法通过文件路径中的后缀名来分别对 Excel、CSV、JSON 文件进行解析。
|
637
977
|
|
638
|
-
|
639
|
-
***** 创建表 =create_table=
|
640
978
|
#+BEGIN_EXAMPLE
|
641
|
-
|
642
|
-
|
643
|
-
|
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
|
979
|
+
excel = 'path/to/excel.xlsx'.parse
|
980
|
+
csv = 'path/to/csv.csv'.parse
|
981
|
+
json = 'path/to/json.json'.parse
|
666
982
|
#+END_EXAMPLE
|
667
983
|
|
668
|
-
|
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
|
-
**** 模型类类方法扩展
|
984
|
+
**** =ID=
|
677
985
|
|
678
|
-
|
986
|
+
Arql 提供了一个 =ID= 类,用来生成雪花算法 ID 和 UUID。
|
679
987
|
|
680
988
|
#+BEGIN_EXAMPLE
|
681
|
-
|
989
|
+
id = ID.long # 生成一个雪花算法 ID
|
990
|
+
id = ID.uuid # 生成一个 UUID
|
682
991
|
#+END_EXAMPLE
|
992
|
+
|
993
|
+
*** $C 全局变量
|
683
994
|
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
995
|
+
Arql 将 =ActiveRecord::Base.connection= 对象赋值给全局可用的 =$C= 全局变量,它代表当前的数据库连接。
|
996
|
+
|
997
|
+
上文中的 =q= 方法实际上是 =$C.exec_query= 方法, =$C= 对象的其他方法也很有用:
|
998
|
+
|
999
|
+
**** 创建表
|
1000
|
+
#+begin_example
|
1001
|
+
ARQL ❯ $C.create_table :post, id: false, primary_key: :id do |t|
|
1002
|
+
ARQL ❯ t.column :id, :bigint, precison: 19, comment: 'ID'
|
1003
|
+
ARQL ❯ t.column :name, :string, comment: '名称'
|
1004
|
+
ARQL ❯ t.column :gmt_created, :datetime, comment: '创建时间'
|
1005
|
+
ARQL ❯ t.column :gmt_modified, :datetime, comment: '最后修改时间'
|
1006
|
+
ARQL ❯ end
|
1007
|
+
#+end_example
|
1008
|
+
|
1009
|
+
=create_table= 同样也被加入到 =Kernel= 下面,所以也可以直接调用 =create_table= 方法:
|
1010
|
+
|
1011
|
+
#+begin_example
|
1012
|
+
ARQL ❯ create_table :post, id: false, primary_key: :id do |t|
|
1013
|
+
ARQL ❯ t.column :id, :bigint, precison: 19, comment: 'ID'
|
1014
|
+
ARQL ❯ t.column :name, :string, comment: '名称'
|
1015
|
+
ARQL ❯ t.column :gmt_created, :datetime, comment: '创建时间'
|
1016
|
+
ARQL ❯ t.column :gmt_modified, :datetime, comment: '最后修改时间'
|
1017
|
+
ARQL ❯ end
|
1018
|
+
#+end_example
|
1019
|
+
|
1020
|
+
**** 添加字段
|
688
1021
|
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
#+END_EXAMPLE
|
1022
|
+
#+begin_example
|
1023
|
+
$C.add_column :post, :note, :string, comment: '备注'
|
1024
|
+
#+end_example
|
693
1025
|
|
694
|
-
|
695
|
-
#+BEGIN_EXAMPLE
|
696
|
-
Student.remove_column :note
|
697
|
-
#+END_EXAMPLE
|
1026
|
+
=add_column= 也被加入到模型类的类方法中,所以也可以直接在模型类上调用 =add_column= 方法:
|
698
1027
|
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
Student.add_index [:branch_id, :party_id], unique: true, name: 'by_branch_party'
|
703
|
-
#+END_EXAMPLE
|
1028
|
+
#+begin_example
|
1029
|
+
Post.add_column :note, :string, comment: '备注'
|
1030
|
+
#+end_example
|
704
1031
|
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
1032
|
+
**** 修改字段
|
1033
|
+
|
1034
|
+
#+begin_example
|
1035
|
+
$C.change_column :post, :note, :text, comment: '备注'
|
1036
|
+
#+end_example
|
709
1037
|
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
1038
|
+
=change_column= 也被加入到模型类的类方法中,所以也可以直接在模型类上调用 =change_column= 方法:
|
1039
|
+
|
1040
|
+
#+begin_example
|
1041
|
+
Post.change_column :note, :text, comment: '备注'
|
1042
|
+
#+end_example
|
1043
|
+
|
1044
|
+
**** 删除字段
|
714
1045
|
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
#+END_EXAMPLE
|
1046
|
+
#+begin_example
|
1047
|
+
$C.remove_column :post, :note
|
1048
|
+
#+end_example
|
719
1049
|
|
720
|
-
|
721
|
-
#+BEGIN_EXAMPLE
|
722
|
-
Student.rename_table :seitou
|
723
|
-
#+END_EXAMPLE
|
1050
|
+
=remove_column= 也被加入到模型类的类方法中,所以也可以直接在模型类上调用 =remove_column= 方法:
|
724
1051
|
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
#+END_EXAMPLE
|
1052
|
+
#+begin_example
|
1053
|
+
Post.remove_column :note
|
1054
|
+
#+end_example
|
729
1055
|
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
1056
|
+
**** 删除表
|
1057
|
+
|
1058
|
+
#+begin_example
|
1059
|
+
$C.drop_table :post
|
1060
|
+
#+end_example
|
734
1061
|
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
1062
|
+
=drop_table= 也被加入到模型类的类方法中,所以也可以直接在模型类上调用 =drop_table= 方法:
|
1063
|
+
|
1064
|
+
#+begin_example
|
1065
|
+
Post.drop_table
|
1066
|
+
#+end_example
|
1067
|
+
|
1068
|
+
**** 添加索引
|
740
1069
|
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
1070
|
+
#+begin_example
|
1071
|
+
ARQL ❯ $C.add_index :post, :name
|
1072
|
+
ARQL ❯ $C.add_index(:accounts, [:branch_id, :party_id], unique: true, name: 'by_branch_party')
|
1073
|
+
#+end_example
|
745
1074
|
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
1075
|
+
=add_index= 也被加入到模型类的类方法中,所以也可以直接在模型类上调用 =add_index= 方法:
|
1076
|
+
|
1077
|
+
#+begin_example
|
1078
|
+
Post.add_index :name
|
1079
|
+
Post.add_index [:branch_id, :party_id], unique: true, name: 'by_branch_party'
|
1080
|
+
#+end_example
|
750
1081
|
|
751
|
-
|
1082
|
+
*** 读写 Excel 和 CSV 文件
|
752
1083
|
|
753
|
-
|
1084
|
+
Arql 集成了 =roo= 和 =caxlsx= 两个 Excel 库,提供了用于解析和生成 Excel 文件的方法。同时,Arql 也提供了用于读写 CSV 文件的方法。
|
754
1085
|
|
755
|
-
|
1086
|
+
**** 解析 Excel
|
756
1087
|
|
757
|
-
|
1088
|
+
Arql 为 =Kernel= 模块添加了 =parse_excel= 方法,可以用来解析 Excel 文件。例如:
|
758
1089
|
|
759
|
-
|
760
|
-
|
761
|
-
|
1090
|
+
#+BEGIN_EXAMPLE
|
1091
|
+
ARQL ❯ parse_excel 'path/to/excel.xlsx'
|
1092
|
+
#+END_EXAMPLE
|
762
1093
|
|
763
|
-
|
1094
|
+
文件路径中可以使用 =~/= 表示用户的主目录,Arql 会自动展开。
|
764
1095
|
|
765
1096
|
|
766
|
-
|
1097
|
+
也可以在一个表示文件路径的 =String= 对象上调用 =parse_excel= 方法:
|
767
1098
|
|
768
|
-
|
769
|
-
|
770
|
-
|
1099
|
+
#+BEGIN_EXAMPLE
|
1100
|
+
ARQL ❯ 'path/to/excel.xlsx'.parse_excel
|
1101
|
+
#+END_EXAMPLE
|
771
1102
|
|
772
|
-
|
1103
|
+
=parse_excel= 方法会返回一个 =Hash= 对象,Key 为 Sheet 名称,Value 为 Sheet 的数据,Value 是一个二维数组。例如:
|
773
1104
|
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
1105
|
+
#+BEGIN_EXAMPLE
|
1106
|
+
{
|
1107
|
+
'Sheet1' => [
|
1108
|
+
['A1', 'B1', 'C1'],
|
1109
|
+
['A2', 'B2', 'C2'],
|
1110
|
+
['A3', 'B3', 'C3']
|
1111
|
+
],
|
1112
|
+
'Sheet2' => [
|
1113
|
+
['A1', 'B1', 'C1'],
|
1114
|
+
['A2', 'B2', 'C2'],
|
1115
|
+
['A3', 'B3', 'C3']
|
1116
|
+
]
|
1117
|
+
}
|
1118
|
+
#+END_EXAMPLE
|
788
1119
|
|
789
|
-
|
1120
|
+
**** 生成 Excel
|
790
1121
|
|
791
|
-
|
792
|
-
|
1122
|
+
Arql 为 =Hash= / =Array= / =ActiveRecord::Relation= / =ActiveRecord::Base= 对象添加了 =write_excel= 方法,可以用来
|
1123
|
+
生成 Excel 文件:
|
793
1124
|
|
794
|
-
|
1125
|
+
***** 从 =Hash= 对象生成 Excel
|
795
1126
|
|
796
|
-
|
797
|
-
|
798
|
-
|
1127
|
+
#+BEGIN_EXAMPLE
|
1128
|
+
ARQL ❯ obj.write_excel 'path/to/excel.xlsx'
|
1129
|
+
#+END_EXAMPLE
|
799
1130
|
|
800
|
-
|
1131
|
+
=Hash#write_excel= 要求 Hash 对象 Key 是 Sheet 名称,Value 是 Sheet 的数据,Value 的类型可以是:
|
801
1132
|
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
1133
|
+
+ 一个数组,数组的元素可以是:
|
1134
|
+
+ 一个数组,表示一行数据
|
1135
|
+
+ 一个 Hash 对象,表示一行数据,Key 是列名,Value 是列值
|
1136
|
+
+ 一个 ActiveRecord::Base 对象,表示一行数据
|
1137
|
+
+ 一个 Hash 对象,一共包含两个键值对:
|
1138
|
+
+ =:fields=, 一个数组,表示列名
|
1139
|
+
+ =:data=, 一个二维数组,表示数据
|
809
1140
|
|
810
|
-
|
1141
|
+
***** 从 =Array= 对象生成 Excel
|
811
1142
|
|
812
|
-
|
813
|
-
|
814
|
-
|
1143
|
+
#+BEGIN_EXAMPLE
|
1144
|
+
ARQL ❯ obj.write_excel 'path/to/excel.xlsx', :name, :age, :gender, sheet_name: '订单数据'
|
1145
|
+
#+END_EXAMPLE
|
815
1146
|
|
816
|
-
|
1147
|
+
其中:
|
817
1148
|
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
1149
|
+
+ =:name, :age, :gender= 这几个参数是列名,如果不指定,会根据数组的第一个元素来确定列名:
|
1150
|
+
- 如果元素是 =ActiveRecord::Base= 对象,会使用对象的全部属性名(即数据库字段列表)作为列名
|
1151
|
+
- 如果元素是 =Hash= 对象,会使用 =Hash= 的 全部 Key 作为列名
|
1152
|
+
+ =sheet_name= 指定 Sheet 名称,如果不指定,会使用默认的 Sheet 名称 =Sheet1=
|
822
1153
|
|
823
|
-
|
1154
|
+
=Array= 对象的每一个元素表示一行数据, =Array#write_excel= 要求 Array 对象每个元素:
|
824
1155
|
|
825
|
-
|
826
|
-
|
827
|
-
|
1156
|
+
+ 一个 =ActiveRecord::Base= 对象
|
1157
|
+
+ 一个 =Hash= 对象,表示一行数据,Key 是列名,Value 是列值
|
1158
|
+
+ 一个数组,表示一行数据
|
828
1159
|
|
829
|
-
|
1160
|
+
***** 从 =ActiveRecord::Base= 对象生成 Excel
|
830
1161
|
|
831
|
-
|
832
|
-
|
833
|
-
|
1162
|
+
#+BEGIN_EXAMPLE
|
1163
|
+
ARQL ❯ Student.find(123).write_excel 'path/to/excel.xlsx', sheet_name: '学生数据'
|
1164
|
+
#+END_EXAMPLE
|
834
1165
|
|
835
|
-
|
836
|
-
|
1166
|
+
=ActiveRecord::Base= 的 =write_excel= 对象实际上就是把这个 =ActiveRecord::Base= 对象包装成一个只有一个元素的 =Array= 对
|
1167
|
+
象,然后调用 =Array= 的 =write_excel= 方法。
|
837
1168
|
|
838
|
-
|
1169
|
+
***** 从 =ActiveRecord::Relation= 对象生成 Excel
|
839
1170
|
|
840
|
-
|
841
|
-
|
842
|
-
|
1171
|
+
#+BEGIN_EXAMPLE
|
1172
|
+
ARQL ❯ Student.where(gender: 'M').write_excel 'path/to/excel.xlsx', sheet_name: '男学生'
|
1173
|
+
#+END_EXAMPLE
|
843
1174
|
|
844
|
-
|
845
|
-
|
1175
|
+
=ActiveRecord::Relation= 的 =write_excel= 对象实际上就是把这个 =ActiveRecord::Relation= 对象转换成一个 =Array= 对象,然
|
1176
|
+
后调用 =Array= 的 =write_excel= 方法。
|
846
1177
|
|
847
|
-
|
1178
|
+
**** 解析 CSV
|
848
1179
|
|
849
|
-
|
1180
|
+
Arql 提供了 =parse_csv= 方法,可以用来解析 CSV 文件:
|
850
1181
|
|
851
|
-
|
852
|
-
|
853
|
-
|
1182
|
+
#+BEGIN_EXAMPLE
|
1183
|
+
ARQL ❯ parse_csv 'path/to/csv.csv'
|
1184
|
+
#+END_EXAMPLE
|
854
1185
|
|
855
|
-
|
1186
|
+
=parse_csv= 方法返回一个标准库中的 CSV 对象。
|
856
1187
|
|
857
|
-
|
1188
|
+
=parse_csv= 可以有以下选项参数:
|
858
1189
|
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
1190
|
+
- =encoding=, 指定 CSV 文件的编码,默认是 =UTF-16= (with BOM)
|
1191
|
+
- =headers=, 指定是否包含表头,默认是 =false=
|
1192
|
+
- =col_sep=, 指定列分隔符,默认是 =\t=
|
1193
|
+
- =row_sep=, 指定行分隔符,默认是 =\r\n=
|
863
1194
|
|
864
|
-
|
1195
|
+
(以上默认值实际就是 Microsoft Office Excel 保存 CSV 文件时默认使用的配置)
|
865
1196
|
|
866
|
-
|
1197
|
+
也可以在一个表示文件路径的 =String= 对象上调用 =parse_csv= 方法:
|
867
1198
|
|
868
|
-
|
869
|
-
|
870
|
-
|
1199
|
+
#+BEGIN_EXAMPLE
|
1200
|
+
ARQL ❯ 'path/to/csv.csv'.parse_csv
|
1201
|
+
#+END_EXAMPLE
|
871
1202
|
|
872
|
-
|
873
|
-
|
1203
|
+
**** 生成 CSV
|
1204
|
+
Arql 为 =Array= / =ActiveRecord::Relation= / =ActiveRecord::Base= 对象添加了 =write_csv= 方法,可以用来生成 CSV 文件:
|
874
1205
|
|
875
|
-
|
1206
|
+
***** 从 =Array= 对象生成 CSV
|
876
1207
|
|
877
|
-
|
878
|
-
|
879
|
-
|
1208
|
+
#+BEGIN_EXAMPLE
|
1209
|
+
ARQL ❯ obj.write_csv 'path/to/csv.csv', :name, :age, :gender, sheet_name: '订单数据'
|
1210
|
+
#+END_EXAMPLE
|
880
1211
|
|
881
|
-
|
1212
|
+
用法和 =Array= 对象的 =write_excel= 方法类似。
|
882
1213
|
|
883
1214
|
|
884
|
-
|
1215
|
+
***** 从 =ActiveRecord::Base= 对象生成 CSV
|
885
1216
|
|
886
|
-
|
887
|
-
|
888
|
-
|
1217
|
+
#+BEGIN_EXAMPLE
|
1218
|
+
ARQL ❯ Student.find(123).write_csv 'path/to/csv.csv', sheet_name: '学生数据'
|
1219
|
+
#+END_EXAMPLE
|
889
1220
|
|
890
|
-
|
1221
|
+
用法和 =ActiveRecord::Base= 对象的 =write_excel= 方法类似。
|
891
1222
|
|
892
|
-
|
1223
|
+
***** 从 =ActiveRecord::Relation= 对象生成 CSV
|
893
1224
|
|
894
|
-
|
895
|
-
|
896
|
-
|
1225
|
+
#+BEGIN_EXAMPLE
|
1226
|
+
ARQL ❯ Student.where(gender: 'M').write_csv 'path/to/csv.csv', sheet_name: '男学生'
|
1227
|
+
#+END_EXAMPLE
|
897
1228
|
|
898
|
-
|
1229
|
+
用法和 =ActiveRecord::Relation= 对象的 =write_excel= 方法类似。
|
899
1230
|
|
900
|
-
|
1231
|
+
*** dump 数据
|
901
1232
|
|
902
|
-
|
1233
|
+
注意: 仅支持 MySQL 数据库
|
903
1234
|
|
904
|
-
|
1235
|
+
Arql 为 =Array= / =ActiveRecord::Base= / =ActiveRecord::Relation= 等对象添加了 =dump= 方法,可以用来导出数据到 SQL 文件:
|
905
1236
|
|
906
1237
|
|
907
|
-
|
1238
|
+
**** 从 Array 对象导出数据
|
908
1239
|
|
909
|
-
|
910
|
-
|
911
|
-
|
1240
|
+
#+BEGIN_EXAMPLE
|
1241
|
+
ARQL ❯ obj.dump 'path/to/dump.sql', batch_size: 5000
|
1242
|
+
#+END_EXAMPLE
|
912
1243
|
|
913
|
-
|
1244
|
+
=Array= 对象的每一个元素必须是一个 =ActiveRecord::Base= 对象
|
914
1245
|
|
915
|
-
|
1246
|
+
=batch_size= 参数指定每个批次查询出的数据,默认值为 500
|
916
1247
|
|
917
|
-
|
1248
|
+
**** 从 ActiveRecord::Base 对象导出数据
|
918
1249
|
|
919
|
-
|
920
|
-
|
921
|
-
|
1250
|
+
#+BEGIN_EXAMPLE
|
1251
|
+
ARQL ❯ Student.find(123).dump 'path/to/dump.sql', batch_size: 5000
|
1252
|
+
#+END_EXAMPLE
|
922
1253
|
|
923
|
-
|
1254
|
+
=ActiveRecord::Base= 对象的 =dump= 方法实际上就是把这个 =ActiveRecord::Base= 对象包装成一个只有一个元素的 =Array= 对象,然后调用 =Array= 的 =dump= 方法。
|
924
1255
|
|
925
|
-
|
1256
|
+
**** 从 ActiveRecord::Relation 对象导出数据
|
926
1257
|
|
927
|
-
|
928
|
-
|
929
|
-
|
1258
|
+
#+BEGIN_EXAMPLE
|
1259
|
+
ARQL ❯ Student.where(gender: 'M').dump 'path/to/dump.sql', batch_size: 5000
|
1260
|
+
#+END_EXAMPLE
|
930
1261
|
|
931
|
-
|
1262
|
+
=ActiveRecord::Relation= 的 =dump= 对象实际上就是把这个 =ActiveRecord::Relation= 对象转换成一个 =Array= 对象,然后调用 =Array= 的 =dump= 方法。
|
932
1263
|
|
933
|
-
|
934
|
-
***** 调用 ActiveRecord::Base 的 dump 类方法
|
1264
|
+
**** 调用 ActiveRecord::Base 的 dump 类方法
|
935
1265
|
|
936
|
-
|
937
|
-
|
938
|
-
|
1266
|
+
#+BEGIN_EXAMPLE
|
1267
|
+
ARQL ❯ Student.dump 'path/to/dump.sql', no_create_table: false
|
1268
|
+
#+END_EXAMPLE
|
939
1269
|
|
940
|
-
|
1270
|
+
这个方法会通过 =mysqldump= 命令 把 =Student= 表中的所有数据导出到 SQL 文件中。
|
941
1271
|
|
942
|
-
|
1272
|
+
=no_create_table= 参数指定是否在 SQL 文件中包含创建表的语句,默认值为 =false= 。
|
943
1273
|
|
944
1274
|
|
945
|
-
|
946
|
-
***** 在全局连接对象 =$C= 上调用 dump 方法
|
1275
|
+
**** 在全局连接对象 =$C= 上调用 dump 方法
|
947
1276
|
|
948
|
-
|
949
|
-
|
950
|
-
|
1277
|
+
#+BEGIN_EXAMPLE
|
1278
|
+
ARQL ❯ $C.dump 'path/to/dump.sql', no_create_db: false
|
1279
|
+
#+END_EXAMPLE
|
951
1280
|
|
952
|
-
|
1281
|
+
这个方法会通过 mysqldump 命令把当前数据库中的所有表的数据导出到 SQL 文件中。
|
953
1282
|
|
954
|
-
|
1283
|
+
=no_create_db= 参数指定是否在 SQL 文件中包含创建数据库的语句,默认值为 =false= 。
|
955
1284
|
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
|
967
|
-
|
968
|
-
+ =boxplot=
|
1285
|
+
*** Plot
|
1286
|
+
|
1287
|
+
Arql 集成了 Ruby 的 =youplot= 库,为 =Array= 添加了一些可以用来绘制图表的方法:
|
1288
|
+
|
1289
|
+
+ =barplot=
|
1290
|
+
+ =countplot=
|
1291
|
+
+ =histo=
|
1292
|
+
+ =lineplot=
|
1293
|
+
+ =lineplots=
|
1294
|
+
+ =scatter=
|
1295
|
+
+ =density=
|
1296
|
+
+ =boxplot=
|
969
1297
|
|
970
|
-
|
1298
|
+
示例:
|
971
1299
|
|
972
|
-
|
1300
|
+
数量统计图:
|
973
1301
|
|
974
|
-
|
975
|
-
|
976
|
-
|
977
|
-
|
978
|
-
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
|
1302
|
+
#+BEGIN_EXAMPLE
|
1303
|
+
ARQL@demo247(main) [44] ❯ Student.pluck(:gender)
|
1304
|
+
=> ["M", "M", "M", "M", "M", "M", "M", "F", "M", "F", "M", "M", "M", "M", "M"]
|
1305
|
+
ARQL@demo247(main) [45] ❯ Student.pluck(:gender).countplot
|
1306
|
+
┌ ┐
|
1307
|
+
M ┤■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 13.0
|
1308
|
+
F ┤■■■■■ 2.0
|
1309
|
+
└ ┘
|
1310
|
+
#+END_EXAMPLE
|
983
1311
|
|
984
|
-
|
1312
|
+
分布图:
|
985
1313
|
|
986
|
-
|
987
|
-
|
988
|
-
|
989
|
-
|
990
|
-
|
991
|
-
|
992
|
-
|
993
|
-
|
994
|
-
|
995
|
-
|
996
|
-
|
997
|
-
|
1314
|
+
#+BEGIN_EXAMPLE
|
1315
|
+
ARQL@jicai.dev(main) [18] ❯ Order.last(20).pluck(:order_sum)
|
1316
|
+
=> [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]
|
1317
|
+
ARQL@jicai.dev(main) [19] ❯ Order.last(20).pluck(:order_sum).histo
|
1318
|
+
┌ ┐
|
1319
|
+
[ 0.0, 50000.0) ┤▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 17
|
1320
|
+
[ 50000.0, 100000.0) ┤▇▇▇▇ 2
|
1321
|
+
[100000.0, 150000.0) ┤ 0
|
1322
|
+
[150000.0, 200000.0) ┤ 0
|
1323
|
+
[200000.0, 250000.0) ┤▇▇ 1
|
1324
|
+
└ ┘
|
1325
|
+
Frequency
|
998
1326
|
|
999
|
-
|
1000
|
-
|
1001
|
-
**** =String=
|
1327
|
+
#+END_EXAMPLE
|
1002
1328
|
|
1003
|
-
|
1329
|
+
*** Ransack
|
1004
1330
|
|
1005
|
-
|
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。
|
1331
|
+
Arql 集成了 =Ransack=:
|
1030
1332
|
|
1031
1333
|
#+BEGIN_EXAMPLE
|
1032
|
-
|
1033
|
-
|
1334
|
+
Student.ransack(name_cont: 'Tom').result # 模糊查询名字中包含 'Tom' 的学生
|
1335
|
+
Student.ransack(name_start: 'Tom').result # 模糊查询名字以 'Tom' 开头的学生
|
1034
1336
|
#+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
1337
|
|
1045
|
-
|
1338
|
+
** Emacs Org Babel 集成
|
1046
1339
|
|
1047
|
-
|
1340
|
+
这里有一个 [[https://github.com/lululau/spacemacs-layers/blob/master/ob-arql/local/ob-arql/ob-arql.el][ob-arql]] 用于集成 Emacs org babel。
|
1048
1341
|
|
1049
1342
|
** Guides and Tips
|
1050
1343
|
*** [[./define-associations-zh_CN.org][在 Initializer 文件中定义关联关系]]
|
@@ -1062,19 +1355,9 @@
|
|
1062
1355
|
#+BEGIN_EXAMPLE
|
1063
1356
|
arql -d db/development.sqlite3
|
1064
1357
|
#+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
|
-
|
1358
|
+
*** [[./ruby-guides-for-java-developer-zh_CN.org][给 Java 开发者的 Ruby 入门简明教程]]
|
1359
|
+
*** [[./simple-pry-guides-zh_CN.org][简明 Pry 使用指南]]
|
1360
|
+
*** [[./simple-active-record-guide-zh_CN.org][简明 ActiveRecord 使用指南]]
|
1078
1361
|
** 开发
|
1079
1362
|
|
1080
1363
|
检出代码后,运行 =bin/setup= 安装依赖。你也可以运行 =bin/console= 进入交互式控制台。
|