arql 0.3.31 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/.vscode/launch.json +1 -1
  3. data/Gemfile.lock +1 -1
  4. data/README-zh_CN.org +616 -491
  5. data/README.org +803 -628
  6. data/auto-set-id-before-save-zh_CN.org +1 -1
  7. data/auto-set-id-before-save.org +1 -1
  8. data/custom-configurations-zh_CN.org +40 -3
  9. data/custom-configurations.org +71 -32
  10. data/define-associations-zh_CN.org +31 -17
  11. data/define-associations.org +52 -29
  12. data/initializer-structure-zh_CN.org +23 -5
  13. data/initializer-structure.org +46 -18
  14. data/lib/arql/app.rb +98 -71
  15. data/lib/arql/cli.rb +37 -15
  16. data/lib/arql/commands/info.rb +41 -28
  17. data/lib/arql/commands/models.rb +106 -61
  18. data/lib/arql/commands/reconnect.rb +8 -4
  19. data/lib/arql/commands/redefine.rb +3 -1
  20. data/lib/arql/commands/sandbox.rb +6 -4
  21. data/lib/arql/commands.rb +0 -2
  22. data/lib/arql/concerns/global_data_definition.rb +40 -6
  23. data/lib/arql/concerns/model_extension.rb +168 -0
  24. data/lib/arql/concerns/table_data_definition.rb +20 -20
  25. data/lib/arql/concerns.rb +1 -0
  26. data/lib/arql/definition.rb +169 -317
  27. data/lib/arql/ext/active_record/relation.rb +29 -0
  28. data/lib/arql/ext/active_record/result.rb +29 -0
  29. data/lib/arql/ext/array.rb +40 -1
  30. data/lib/arql/ext/kernel.rb +70 -61
  31. data/lib/arql/ext/object.rb +14 -0
  32. data/lib/arql/ext/ransack/search.rb +29 -0
  33. data/lib/arql/mysqldump.rb +0 -1
  34. data/lib/arql/repl.rb +1 -1
  35. data/lib/arql/ssh_proxy.rb +25 -22
  36. data/lib/arql/version.rb +1 -1
  37. data/lib/arql.rb +11 -7
  38. data/oss-files-zh_CN.org +2 -2
  39. data/oss-files.org +2 -2
  40. data/sql-log-zh_CN.org +8 -3
  41. data/sql-log.org +8 -3
  42. metadata +6 -5
  43. data/lib/arql/commands/table.rb +0 -55
  44. data/lib/arql/commands/vd.rb +0 -46
  45. 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
 
@@ -167,6 +192,27 @@
167
192
  7. =ssh.local_port= : ssh 本地端口
168
193
  8. =singularized_table_names=: 是否使用单数表名,默认为 =false=, 如果为 =false=, 则 =students= 表将定义为 =Student= 模型,如果为 =true=, 则 =students= 表将定义为 =Students= 模型
169
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=
170
216
 
171
217
  **** 配置文件示例
172
218
 
@@ -185,6 +231,7 @@
185
231
  password:
186
232
  table_name_prefixes: ["t_"]
187
233
  socket: /tmp/mysql.sock
234
+ namespace: B
188
235
 
189
236
  dev:
190
237
  <<: *default
@@ -194,6 +241,7 @@
194
241
  password: 123456
195
242
  database: blog
196
243
  table_name_prefixes: ["t_"]
244
+ namespace: B
197
245
  ssh:
198
246
  host: dev.mycompany.com
199
247
  port: 22
@@ -227,7 +275,7 @@
227
275
  =info= 命令打印当前的数据库连接信息和 SSH 代理信息,例如:
228
276
 
229
277
  #+begin_example
230
- Database Connection Information:
278
+ my_env Database Connection Information:
231
279
  Host:
232
280
  Port:
233
281
  Username: root
@@ -238,6 +286,12 @@
238
286
  Pool Size: 5
239
287
  #+end_example
240
288
 
289
+ =info= 默认显示指定的所有环境的连接信息,如果只想显示当前环境的连接信息, =info= 命令接受一个正则表达式参数,只显示匹配的环境信息,例如:
290
+
291
+ #+BEGIN_EXAMPLE
292
+ info .*dev
293
+ #+END_EXAMPLE
294
+
241
295
  **** =m= 或者 =l=
242
296
 
243
297
  =m= (或者 =l= ) 命令打印所有表名及对应的模型类名和缩写类名,例如:
@@ -265,59 +319,25 @@
265
319
  - =Abbr= : 缩写类名
266
320
  - =Comment= : 注释
267
321
 
268
- =m= / =l= 命令还可以接受一个参数,用于通过表名或表注释来对列表进行过滤, 例如:
269
-
270
- =m perm= 只会列出表名或表注释中包含 =perm= 的表;如果要使用正则表达式匹配,可以使用 =m /perm/i= 来进行匹配。
271
-
272
- **** =t=
273
-
274
- =t= 命令接受一个表名或模型类名作为参数,打印表的定义信息,例如:
275
-
276
- 执行 =t Person= 命令会打印 =person= 表的定义信息:
277
-
278
- #+begin_example
279
- Table: person
280
- +----|------------|------------------|-----------|-------|-----------|-------|---------|----------|---------+
281
- | PK | Name | SQL Type | Ruby Type | Limit | Precision | Scale | Default | Nullable | Comment |
282
- +----|------------|------------------|-----------|-------|-----------|-------|---------|----------|---------+
283
- | Y | id | int(11) unsigned | integer | 4 | | | | false | |
284
- | | name | varchar(64) | string | 64 | | | | true | |
285
- | | age | int(11) | integer | 4 | | | | true | |
286
- | | gender | int(4) | integer | 4 | | | | true | |
287
- | | grade | int(4) | integer | 4 | | | | true | |
288
- | | blood_type | varchar(4) | string | 4 | | | | true | |
289
- +----|------------|------------------|-----------|-------|-----------|-------|---------|----------|---------+
290
- #+end_example
291
-
292
- 另外, =t= 同时也是模型类的一个类方法,执行 =Person.t= 会同样会打印出上述信息。
293
-
294
- 其中:
295
-
296
- - =PK= : 是否为主键
297
- - =Name= : 列名
298
- - =SQL Type= : 数据库类型
299
- - =Ruby Type= : Ruby 类型
300
- - =Limit= : 长度限制
301
- - =Precision= : 精度
302
- - =Scale= : 小数位数
303
- - =Default= : 默认值
304
- - =Nullable= : 是否可为空
305
- - =Comment= : 注释
306
-
307
- **** =vd=
322
+ =m= / =l= 命令三个可选的选项:
308
323
 
309
- =t= 命令在终端中以表格的形式打印表的定义信息,缺点是如果表的列数过多,会导致表格这行,不方便查看。而 =vd=
310
- (visidata) 是一个使用 Python 编写的终端数据分析工具,可以在终端中以表格的形式打印表的定义信息,但是支持水平滚动,方
311
- 便查看。
324
+ + =-e=, =--env= : 指定环境,正则表达式,只显示匹配的环境下的表名,默认显示所有环境
325
+ + =-f=, =--format= : 输出格式:
326
+ - =terminal= : 默认的表格格式
327
+ - =md= : markdown 表格格式
328
+ - =org= : org mode 表格格式
329
+ - =sql= : 输出 create table SQL
330
+ + =-c=, =--column= : 正则表达式,列出字段,而不是表,按照字段名或字段注释筛选
312
331
 
313
- 如果要使用 Arql =vd= 命令,需要先安装 =visidata=:
332
+ =m= / =l= 命令还可以接受一个可选的正则表达式参数,只显示(按照表名或表注释)匹配的表的信息,例如:
314
333
 
315
- #+begin_src sh
316
- pipx install visidata
317
- #+end_src
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
318
340
 
319
- =vd= 命令和用法和 =t= 命令基本相同,另外, =Array= / =ActiveRecord::Base= 等对象也可以使用 =vd= 方法。
320
-
321
341
  **** =show-sql= / =hide-sql=
322
342
 
323
343
  这对命令可以切换 Pry REPL 中 SQL 日志的显示。
@@ -349,9 +369,9 @@
349
369
  =redefine= 命令用于重新定义 ActiveRecord 模型类,根据数据库表的信息重新生成模型类。对于在 =init.rb= 中添加了新的关
350
370
  系定义,想使新定义的关系在当前 Pry 会话中生效,可以使用 =redefine= 命令。
351
371
 
352
- **** 沙盒模式
372
+ **** =sandbox-enter= 和 =sandbox-quit=
353
373
 
354
- =sandbox-enter= 命令用于开启沙盒模式。在沙盒模式下,所有的数据库操作都会在事务中执行,该事务不会自动提交,需要手动提交或回滚。
374
+ =sandbox-enter= 命令用于开启沙盒模式。在沙盒模式下,所有的数据库操作都会在事务中执行,该事务不会自动提交,退出沙盒模式时,会自动回滚事务。
355
375
 
356
376
  1. 开启沙盒模式:
357
377
  #+begin_example
@@ -361,19 +381,7 @@
361
381
  2. 退出沙盒模式:
362
382
  #+begin_example
363
383
  ARQL@demo247 [sandbox] (main) [7] ❯ sandbox-quit
364
- begin_transaction callbacks removed.
365
- You still have open 1 transactions open, don't forget commit or rollback them.
366
- #+end_example
367
- 3. 提交事务:
368
- #+begin_example
369
- ARQL@demo247(main) [7] ❯ $C.commit_transaction
370
384
  #+end_example
371
- 4. 回滚事务:
372
- #+begin_example
373
- ARQL@demo247(main) [7] ❯ $C.rollback_transaction
374
- #+end_example
375
-
376
-
377
385
 
378
386
  *** 作为代码解释器使用
379
387
 
@@ -411,23 +419,79 @@
411
419
  $ echo 'puts Person.count' | arql -e dev
412
420
  #+end_example
413
421
 
414
- *** 额外的扩展方法
415
- **** =to_insert_sql= / =to_upsert_sql=
416
-
417
- 可以在任何 ActiveRecord 模型实例上调用 =to_insert_sql= / =to_upsert_sql= 方法,获取该对象的插入或更新 SQL 语句。
418
- 这两个方法也可以在包含 ActiveRecord 模型实例对象的数组对象上调用。
422
+ ** 额外的扩展方法
423
+ *** 命名空间模块的模块方法
424
+ **** =q=
419
425
 
426
+ =q= 用于执行 SQL 查询
427
+
420
428
  #+begin_example
421
- ARQL ❯ Person.all.to_a.to_insert_sql
422
- => "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`;"
429
+ ARQL ❯ rs = Blog::q 'select count(0) from person;'
430
+ => #<ActiveRecord::Result:0x00007fd1f8026ad0 @column_types={}, @columns=["count(0)"], @hash_rows=nil, @rows=[[11]]>
431
+ ARQL ❯ rs.rows
432
+ => [[11]]
423
433
  #+end_example
434
+ **** =models=
435
+
436
+ =models= 返回该命名空间下的所有模型类
437
+
438
+ #+begin_example
439
+ ARQL ❯ Blog::models
440
+ => [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)]
441
+ #+end_example
442
+
443
+ **** =tables=
444
+
445
+ =tables= 返回该命名空间下的所有表名
446
+
447
+ #+begin_example
448
+ ARQL ❯ Blog::tables
449
+ => ["people", "posts"]
450
+ #+end_example
451
+
452
+ **** =model_names=
453
+
454
+ =model_names= 返回该命名空间下的所有模型类的名称
455
+
456
+ #+begin_example
457
+ ARQL ❯ Blog::model_names
458
+ => ["Demo::Person", "Demo::Post"]
459
+ #+end_example
460
+
461
+ **** =create_table=
462
+
463
+ =create_table= 用于在该命名空间所对应的环境中创建表
464
+
465
+ #+begin_example
466
+ ARQL ❯ Blog::create_table :people do |t|
467
+ ARQL ❯ t.string :name
468
+ ARQL ❯ t.integer :age
469
+ ARQL ❯ t.timestamps
470
+ ARQL ❯ end
471
+ #+end_example
472
+
473
+ **** =dump=
474
+
475
+ =dump= 通过 =mysqldump= 将该命名空间对应的数据库导出到指定的文件中
476
+
477
+ #+begin_example
478
+ ARQL ❯ Blog::dump('~/data/blog.sql')
479
+ #+end_example
480
+
481
+ *** 模型的类方法
482
+
483
+ Pry 内建了 =show-source= (别名 =$= ) 和 =show-doc= (别名 =?= )命令,可以查看方法的源码和文档。可以通过 =show-doc= 查看方法的文档。例如:
424
484
 
485
+ #+BEGIN_EXAMPLE
486
+ ARQL ❯ ? Student.add_column
487
+ #+END_EXAMPLE
488
+
425
489
  **** =to_create_sql=
426
490
 
427
491
  可以在任何 ActiveRecord 模型类上调用 =to_create_sql= 方法,获取该模型类对应的表的创建 SQL 语句。
428
492
 
429
493
  #+begin_example
430
- ARQL@demo247(main) [16] ❯ puts Post.to_create_sql
494
+ ARQL@demo247(main) [16] ❯ puts Blog::Post.to_create_sql
431
495
  D, [2024-04-07T14:15:11.106693 #20440] DEBUG -- : SQL (24.9ms) show create table post
432
496
  CREATE TABLE `post` (
433
497
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
@@ -443,6 +507,167 @@
443
507
  ) ENGINE=InnoDB AUTO_INCREMENT=83 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
444
508
  #+end_example
445
509
 
510
+ **** =t=
511
+
512
+ =t= 类方法用于打印模型类的表结构
513
+
514
+ 执行 =Blog::Person.t= 命令会打印 =person= 表的定义信息:
515
+
516
+ #+begin_example
517
+ Table: person
518
+ +----|------------|------------------|-----------|-------|-----------|-------|---------|----------|---------+
519
+ | PK | Name | SQL Type | Ruby Type | Limit | Precision | Scale | Default | Nullable | Comment |
520
+ +----|------------|------------------|-----------|-------|-----------|-------|---------|----------|---------+
521
+ | Y | id | int(11) unsigned | integer | 4 | | | | false | |
522
+ | | name | varchar(64) | string | 64 | | | | true | |
523
+ | | age | int(11) | integer | 4 | | | | true | |
524
+ | | gender | int(4) | integer | 4 | | | | true | |
525
+ | | grade | int(4) | integer | 4 | | | | true | |
526
+ | | blood_type | varchar(4) | string | 4 | | | | true | |
527
+ +----|------------|------------------|-----------|-------|-----------|-------|---------|----------|---------+
528
+ #+end_example
529
+
530
+ =t= 接受一个可选的 =format= 命名参数,可选值为:
531
+
532
+ + =md=
533
+ + =org=
534
+ + =sql=
535
+ + =terminal= (默认值)
536
+
537
+ 例如:
538
+
539
+ #+begin_example
540
+ ARQL ❯ Blog::Person.t :sql
541
+ #+end_example
542
+
543
+ 输出:
544
+
545
+ #+begin_example
546
+ CREATE TABLE `person` (
547
+ `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
548
+ `name` varchar(64) DEFAULT NULL,
549
+ `age` int(11) DEFAULT NULL,
550
+ `gender` int(4) DEFAULT NULL,
551
+ `grade` int(4) DEFAULT NULL,
552
+ `blood_type` varchar(4) DEFAULT NULL,
553
+ PRIMARY KEY (`id`)
554
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='人员表';
555
+ #+end_example
556
+
557
+ **** =v=
558
+
559
+ =v= 类方法用于和 Emacs 的 org babel 集成,可以在 org 文件中直接调用 =v= 方法,获取模型类的表结构。
560
+
561
+ 例如:
562
+
563
+ #+begin_example
564
+ ARQL ❯ Blog::Post.v
565
+ #+end_example
566
+
567
+ 输出:
568
+
569
+ #+BEGIN_EXAMPLE
570
+ ARQL@demo247(main) [10] ❯ Demo::Post.v
571
+ => [["PK", "Name", "SQL Type", "Ruby Type", "Limit", "Precision", "Scale", "Default", "Nullable", "Comment"],
572
+ nil,
573
+ ["Y", "id", "int(10) unsigned", :integer, 4, "", "", "", false, "ID"],
574
+ ["", "name", "varchar(256)", :string, 256, "", "", "", true, ""],
575
+ ["", "gender", "varchar(256)", :string, 256, "", "", "", true, ""],
576
+ ["", "phone", "varchar(256)", :string, 256, "", "", "", true, ""],
577
+ ["", "id_no", "varchar(256)", :string, 256, "", "", "", true, ""],
578
+ ["", "note", "varchar(256)", :string, 256, "", "", "", true, ""],
579
+ ["", "gmt_created", "datetime", :datetime, "", 0, "", "", false, "创建时间"],
580
+ ["", "gmt_modified", "datetime", :datetime, "", 0, "", "", false, "最后修改时间"],
581
+ ["", "sasa", "varchar(255)", :string, 255, "", "", "", true, ""]]
582
+ #+END_EXAMPLE
583
+
584
+ **** =vd=
585
+
586
+ 使用 =visidata= 显示表结构
587
+ **** =table_comment=
588
+
589
+ 返回该模型的表注释
590
+
591
+ 例如:
592
+
593
+ #+begin_example
594
+ ARQL ❯ Blog::Post.table_comment
595
+ #+end_example
596
+
597
+ 输出:
598
+
599
+ #+begin_example
600
+ "文章表"
601
+ #+end_example
602
+
603
+ **** 添加字段 =add_column=
604
+ #+BEGIN_EXAMPLE
605
+ Blog::Student.add_column :note, :text, comment: '备注'
606
+ #+END_EXAMPLE
607
+
608
+ **** 修改字段 =change_column=
609
+ #+BEGIN_EXAMPLE
610
+ Blog::Student.change_column :note, :string, comment: '备注'
611
+ #+END_EXAMPLE
612
+
613
+ **** 删除字段 =remove_column=
614
+ #+BEGIN_EXAMPLE
615
+ Blog::Student.remove_column :note
616
+ #+END_EXAMPLE
617
+
618
+ **** 添加索引 =add_index=
619
+ #+BEGIN_EXAMPLE
620
+ Blog::Student.add_index :name
621
+ Blog::Student.add_index [:branch_id, :party_id], unique: true, name: 'by_branch_party'
622
+ #+END_EXAMPLE
623
+
624
+ **** 修改字段注释 =change_column_comment=
625
+ #+BEGIN_EXAMPLE
626
+ Blog::Student.change_column_comment :note, '备注'
627
+ #+END_EXAMPLE
628
+
629
+ **** 修改字段默认值 =change_column_default=
630
+ #+BEGIN_EXAMPLE
631
+ Blog::Student.change_column_default :note, '默认值'
632
+ #+END_EXAMPLE
633
+
634
+ **** 修改字段名称 =rename_column=
635
+ #+BEGIN_EXAMPLE
636
+ Blog::Student.rename_column :note, :remark
637
+ #+END_EXAMPLE
638
+
639
+ **** 修改表名 =rename_table=
640
+ #+BEGIN_EXAMPLE
641
+ Blog::Student.rename_table :seitou
642
+ #+END_EXAMPLE
643
+
644
+ **** 修改表注释 =change_table_comment=
645
+ #+BEGIN_EXAMPLE
646
+ Blog::Student.change_table_comment from: '', to: '学生表'
647
+ #+END_EXAMPLE
648
+
649
+ **** 删除表 =drop_table=
650
+ #+BEGIN_EXAMPLE
651
+ Blog::Student.drop_table
652
+ #+END_EXAMPLE
653
+
654
+ **** 删除索引 =remove_index=
655
+ #+BEGIN_EXAMPLE
656
+ Blog::Student.remove_index :age
657
+ Blog::Student.remove_index name: 'by_branch_party'
658
+ #+END_EXAMPLE
659
+
660
+ **** 查询表注释 =table_comment=
661
+ #+BEGIN_EXAMPLE
662
+ Blog::Student.table_comment
663
+ #+END_EXAMPLE
664
+
665
+ **** 列出表的索引 =indexes=
666
+ #+BEGIN_EXAMPLE
667
+ Blog::Student.indexes
668
+ #+END_EXAMPLE
669
+
670
+ *** 模型的实例方法
446
671
  **** =t=
447
672
 
448
673
  =t= 除了可以作为类方法在 ActiveRecord 模型类上调用,也可以作为实例方法在 ActiveRecord 模型实例对象上调用。
@@ -463,22 +688,31 @@
463
688
 
464
689
  =t= 方法可以接受以下两个选项:
465
690
 
466
- + =:except= 选项,用于指定不显示的属性名,值可以是字符串或正则表达式,例如:
467
- #+BEGIN_EXAMPLE
468
- Person.last.t(except: 'id')
469
- Student.where(condition).t(except: /id|name/)
470
- #+END_EXAMPLE
471
691
  + =:compact= 选项,用于指定是否紧凑显示,值可以是 =true= 或 =false= ,如果启用紧凑显示,那些值全部为 =NULL= 的列将不
472
692
  会显示,这对于查看那些数据稀疏的表很有帮助,例如:
473
693
  #+BEGIN_EXAMPLE
474
694
  Person.last.t(compact: true)
475
695
  Student.where(condition).t(compact: false)
476
696
  #+END_EXAMPLE
697
+ + =:format= 选项,用于指定输出格式,值可以是:
698
+ - =:terminal= 默认的输出格式,适合在终端中查看
699
+ - =:org= org-mode 表格格式
700
+ - =:md= markdown 表格格式
701
+
702
+ **** =to_insert_sql= / =to_upsert_sql=
703
+
704
+ 可以在任何 ActiveRecord 模型实例上调用 =to_insert_sql= / =to_upsert_sql= 方法,获取该对象的插入或更新 SQL 语句。
705
+ 这两个方法也可以在包含 ActiveRecord 模型实例对象的数组对象上调用。
706
+
707
+ #+begin_example
708
+ ARQL ❯ Person.all.to_a.to_insert_sql
709
+ => "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`;"
710
+ #+end_example
477
711
 
478
712
  **** =v=
479
713
 
480
714
  =v= 方法用于与 Emacs org babel 集成。
481
-
715
+
482
716
  ***** =v= 作为模型类的实例方法
483
717
 
484
718
  在任何 ActiveRecord 模型实例对象上调用 =v= 方法,可以打印一个数组,数组的第一个元素是 =['Attribute Name',
@@ -524,530 +758,434 @@
524
758
  => [[:name, :age], nil, ["Jack", 10], ["Lucy", 20]]
525
759
  #+end_example
526
760
 
527
- **** =q=
528
761
 
529
- #+begin_example
530
- ARQL ❯ rs = q 'select count(0) from person;'
531
- => #<ActiveRecord::Result:0x00007fd1f8026ad0 @column_types={}, @columns=["count(0)"], @hash_rows=nil, @rows=[[11]]>
532
- ARQL ❯ rs.rows
533
- => [[11]]
534
- #+end_example
762
+ **** =dump=
535
763
 
536
- **** JSON 转换和格式化
537
-
538
- 在任何对象上调用 =j= 方法,可以得到 JSON 格式的字符串,调用 =jj= 方法可以得到格式化后的 JSON 字符串。
764
+ 将实例对象导出为 =INSERT= SQL 语句,见下文 「dump 数据」章节
539
765
 
540
- 使用 =jp= 方法打印 JSON,使用 =jjp= 方法打印格式化后的 JSON。
766
+ **** =write_excel= / =write_csv=
541
767
 
542
- **** $C 全局变量
768
+ 将实例对象导出为 Excel 或 CSV 文件,见下文 「读写 Excel 和 CSV 文件」章节
769
+
770
+ *** =ActiveRecord::Relation= / =ActiveRecord::Result= / =Ransack::Search= / =Array= 上的一些通用扩展方法
771
+ =ActiveRecord::Relation= / =ActiveRecord::Result= / =Ransack::Search= 在逻辑上都可以看成是数组,所以这些方法都可以在这些对象上调用:
772
+ **** =t=
543
773
 
544
- Arql =ActiveRecord::Base.connection= 对象赋值给全局可用的 =$C= 全局变量,它代表当前的数据库连接。
774
+ =t= 方法还可以在包含 ActiveRecord 实例的数组上调用,也可以在 =ActiveRecord::Relation= / =ActiveRecord::Result= / =Ransack::Search= 对象上调用。
545
775
 
546
- 上文中的 =q= 方法实际上是 =$C.exec_query= 方法, =$C= 对象的其他方法也很有用:
776
+ #+begin_example
777
+ ARQL ❯ Person.last(2).t
778
+ +----+----------+--------+----------------------------------+-------+------+---------------------------+---------------------------+
779
+ | id | name | gender | id_no | phone | note | gmt_created | gmt_modified |
780
+ +----+----------+--------+----------------------------------+-------+------+---------------------------+---------------------------+
781
+ | 90 | Zhangsan | M | f09288fb381cc47dd2e56389cf15f0bf | | | 2021-04-26 15:32:05 +0800 | 2021-04-26 15:32:05 +0800 |
782
+ | 91 | Lisi | F | fb6fea4b23b1d3c54739774946246e4c | | | 2021-04-26 15:32:05 +0800 | 2021-04-26 15:32:05 +0800 |
783
+ +----+----------+--------+----------------------------------+-------+------+---------------------------+---------------------------+
784
+ #+end_example
547
785
 
548
- ***** 创建表
549
- #+begin_example
550
- ARQL ❯ $C.create_table :post, id: false, primary_key: :id do |t|
551
- ARQL ❯ t.column :id, :bigint, precison: 19, comment: 'ID'
552
- ARQL ❯ t.column :name, :string, comment: '名称'
553
- ARQL ❯ t.column :gmt_created, :datetime, comment: '创建时间'
554
- ARQL ❯ t.column :gmt_modified, :datetime, comment: '最后修改时间'
555
- ARQL ❯ end
556
- #+end_example
786
+ 作为数组和「类数组」对象实例方法时, =t= 方法可以接受多个用于过滤属性的参数,参数的类型可以是:
557
787
 
558
- =create_table= 同样也被加入到 =Kernel= 下面,所以也可以直接调用 =create_table= 方法:
788
+ + 字符串或 Symbol,对属性进行字面量匹配
789
+ + 正则表达式,对属性进行正则匹配
559
790
 
560
- #+begin_example
561
- ARQL ❯ create_table :post, id: false, primary_key: :id do |t|
562
- ARQL ❯ t.column :id, :bigint, precison: 19, comment: 'ID'
563
- ARQL ❯ t.column :name, :string, comment: '名称'
564
- ARQL ❯ t.column :gmt_created, :datetime, comment: '创建时间'
565
- ARQL ❯ t.column :gmt_modified, :datetime, comment: '最后修改时间'
566
- ARQL ❯ end
567
- #+end_example
791
+ 例如, 只显示 =name=, =gender= 以及所有名称包含 =time= 字样的属性:
568
792
 
569
- ***** 添加字段
570
-
571
793
  #+begin_example
572
- $C.add_column :post, :note, :string, comment: '备注'
794
+ ARQL Person.last(2).t('name', :gender, /time/i)
573
795
  #+end_example
574
-
575
- =add_column= 也被加入到模型类的类方法中,所以也可以直接在模型类上调用 =add_column= 方法:
576
-
577
- #+begin_example
578
- Post.add_column :note, :string, comment: '备注'
579
- #+end_example
580
-
581
- ***** 修改字段
582
796
 
583
- #+begin_example
584
- $C.change_column :post, :note, :text, comment: '备注'
585
- #+end_example
586
-
587
- =change_column= 也被加入到模型类的类方法中,所以也可以直接在模型类上调用 =change_column= 方法:
797
+ 作为数组和「类数组」对象的实例方法的 =t= 还可以接受以下三个选项:
588
798
 
589
- #+begin_example
590
- Post.change_column :note, :text, comment: '备注'
591
- #+end_example
799
+ + =:except= 选项,用于指定不显示的属性名,值可以是字符串或正则表达式,例如:
800
+ #+BEGIN_EXAMPLE
801
+ Person.last(10).t(except: 'id')
802
+ Student.where(condition).t(except: /id|gender/)
803
+ #+END_EXAMPLE
804
+ + =:compact= 选项,用于指定是否紧凑显示,值可以是 =true= 或 =false= ,如果启用紧凑显示,那些值全部为 =NULL= 的列将不
805
+ 会显示,这对于查看那些数据稀疏的表很有帮助,例如:
806
+ #+BEGIN_EXAMPLE
807
+ Person.last(10).t(compact: true)
808
+ Student.where(condition).t(compact: false)
809
+ #+END_EXAMPLE
810
+ + =:format= 选项,用于指定输出格式,值可以是:
811
+ - =:terminal= 默认的输出格式,适合在终端中查看
812
+ - =:org= org-mode 表格格式
813
+ - =:md= markdown 表格格式
592
814
 
593
- ***** 删除字段
594
-
815
+ **** =v=
816
+ =v= 方法用于与 Emacs org babel 集成。
817
+
595
818
  #+begin_example
596
- $C.remove_column :post, :note
819
+ ARQL Person.last.v
820
+ => [["Attribute Name", "Attribute Value", "SQL Type", "Comment"],
821
+ nil,
822
+ ["id", 11, "int(11) unsigned", ""],
823
+ ["name", "Jackson", "varchar(64)", ""],
824
+ ["age", 30, "int(11)", ""],
825
+ ["gender", 2, "int(4)", ""],
826
+ ["grade", 2, "int(4)", ""],
827
+ ["blood_type", "AB", "varchar(4)", ""]]
597
828
  #+end_example
829
+ **** =vd=
598
830
 
599
- =remove_column= 也被加入到模型类的类方法中,所以也可以直接在模型类上调用 =remove_column= 方法:
600
-
601
- #+begin_example
602
- Post.remove_column :note
603
- #+end_example
831
+ 使用 =visidata= 显示「数组」数据
832
+
833
+ **** =write_csv= / =write_excel=
604
834
 
605
- ***** 删除表
606
-
607
- #+begin_example
608
- $C.drop_table :post
609
- #+end_example
835
+ =write_csv= 和 =write_excel= 用于将「数组」数据导出为 CSV 或 Excel 文件,见下文 「读写 Excel 和 CSV 文件」章节
836
+
837
+ **** =dump=
610
838
 
611
- =drop_table= 也被加入到模型类的类方法中,所以也可以直接在模型类上调用 =drop_table= 方法:
839
+ =dump= 方法用于将 ActiveRecord::Relation / ActiveRecord::Result / Ransack::Search 对象导出为 INSERT SQL 语句,见下文 「dump 数据」章节
840
+
841
+ *** =Kernel= 扩展方法
612
842
 
613
- #+begin_example
614
- Post.drop_table
615
- #+end_example
843
+ 下列对应某种 DDL 操作的方法,在使用时都有一个限制:如果连接了多个环境,那么在调用这些方法时,必须通过 =:env= 选项指定环境名。例如:
616
844
 
617
- ***** 添加索引
845
+ #+BEGIN_SRC ruby
846
+ create_table :users, env: 'development', comment: '用户表' do |t|
847
+ t.string :name, comment: '姓名'
848
+ t.integer :age, comment: '年龄'
849
+ end
850
+ #+END_SRC
851
+
852
+ **** 创建表 =create_table=
853
+ #+BEGIN_EXAMPLE
854
+ create_table :post, id: false, primary_key: :id do |t|
855
+ t.column :id, :bigint, precison: 19, comment: 'ID'
856
+ t.column :name, :string, comment: '名称'
857
+ t.column :gmt_created, :datetime, comment: '创建时间'
858
+ t.column :gmt_modified, :datetime, comment: '最后修改时间'
859
+ end
860
+ #+END_EXAMPLE
861
+ **** 创建多对多关系的中间表 =create_join_table=
862
+ #+BEGIN_EXAMPLE
863
+ create_join_table :products, :categories do |t|
864
+ t.index :product_id
865
+ t.index :category_id
866
+ end
867
+ #+END_EXAMPLE
868
+ **** 删除表 =drop_table=
869
+ #+BEGIN_EXAMPLE
870
+ drop_table :post
871
+ #+END_EXAMPLE
872
+ **** 删除多对多关系的中间表 =drop_join_table=
873
+ #+BEGIN_EXAMPLE
874
+ drop_join_table :products, :categories
875
+ #+END_EXAMPLE
876
+ **** 修改表名 =rename_table=
877
+ #+BEGIN_EXAMPLE
878
+ rename_table :post, :posts
879
+ #+END_EXAMPLE
618
880
 
619
- #+begin_example
620
- ARQL ❯ $C.add_index :post, :name
621
- ARQL ❯ $C.add_index(:accounts, [:branch_id, :party_id], unique: true, name: 'by_branch_party')
622
- #+end_example
623
-
624
- =add_index= 也被加入到模型类的类方法中,所以也可以直接在模型类上调用 =add_index= 方法:
625
-
626
- #+begin_example
627
- Post.add_index :name
628
- Post.add_index [:branch_id, :party_id], unique: true, name: 'by_branch_party'
629
- #+end_example
630
-
631
- **** =Kernel= 扩展方法
881
+
882
+ **** =models=
632
883
 
633
- =Kernel= 模块下的函数可以想语言内置函数一样直接调用,不需要指定模块名。 以下是 Arql 扩展的 =Kernel= 方法:
884
+ 返回将所有环境命名空间下的模型类
634
885
 
635
- Pry 内建了 =show-source= (别名 =$= ) 和 =show-doc= (别名 =?= )命令,可以查看方法的源码和文档。可以通过 =show-doc= 查看方法的文档。例如:
886
+ **** =table_names=
636
887
 
637
- #+BEGIN_EXAMPLE
638
- ARQL ❯ ? create_table
639
- #+END_EXAMPLE
888
+ 返回所有环境下的表名
640
889
 
641
-
642
- ***** 创建表 =create_table=
643
- #+BEGIN_EXAMPLE
644
- create_table :post, id: false, primary_key: :id do |t|
645
- t.column :id, :bigint, precison: 19, comment: 'ID'
646
- t.column :name, :string, comment: '名称'
647
- t.column :gmt_created, :datetime, comment: '创建时间'
648
- t.column :gmt_modified, :datetime, comment: '最后修改时间'
649
- end
650
- #+END_EXAMPLE
651
- ***** 创建多对多关系的中间表 =create_join_table=
652
- #+BEGIN_EXAMPLE
653
- create_join_table :products, :categories do |t|
654
- t.index :product_id
655
- t.index :category_id
656
- end
657
- #+END_EXAMPLE
658
- ***** 删除表 =drop_table=
659
- #+BEGIN_EXAMPLE
660
- drop_table :post
661
- #+END_EXAMPLE
662
- ***** 删除多对多关系的中间表 =drop_join_table=
663
- #+BEGIN_EXAMPLE
664
- drop_join_table :products, :categories
665
- #+END_EXAMPLE
666
- ***** 修改表名 =rename_table=
667
- #+BEGIN_EXAMPLE
668
- rename_table :post, :posts
669
- #+END_EXAMPLE
670
-
671
- ***** =print_tables=
890
+ **** =model_names=
672
891
 
673
- Arql 提供了一个 =print_tables= 方法,可以将当前数据库中的所有表的信息,导出为:
892
+ 返回所有环境下的模型类名
674
893
 
675
- + markdown 表格格式: ~print_tables(:md)~
676
- + org-mode 表格格式: ~print_tables(:org)~
677
- + create table SQL: ~print_tables(:sql)~
678
-
679
- **** 模型类类方法扩展
894
+ **** =q=
680
895
 
681
- Pry 内建了 =show-source= (别名 =$= ) =show-doc= (别名 =?= )命令,可以查看方法的源码和文档。可以通过 =show-doc= 查看方法的文档。例如:
896
+ 如果只指定了一个环境,那么可以直接使用 =q= 方法来执行原生 SQL 查询,而不需要在 =q= 前面指定命名空间模块,如 =Blog::q=
682
897
 
683
- #+BEGIN_EXAMPLE
684
- ARQL ? Student.add_column
685
- #+END_EXAMPLE
898
+ *** 其它扩展方法
899
+ **** JSON 转换和格式化
686
900
 
687
- ***** 添加字段 =add_column=
688
- #+BEGIN_EXAMPLE
689
- Student.add_column :note, :text, comment: '备注'
690
- #+END_EXAMPLE
691
-
692
- ***** 修改字段 =change_column=
693
- #+BEGIN_EXAMPLE
694
- Student.change_column :note, :string, comment: '备注'
695
- #+END_EXAMPLE
901
+ 在任何对象上调用 =j= 方法,可以得到 JSON 格式的字符串,调用 =jj= 方法可以得到格式化后的 JSON 字符串。
696
902
 
697
- ***** 删除字段 =remove_column=
698
- #+BEGIN_EXAMPLE
699
- Student.remove_column :note
700
- #+END_EXAMPLE
903
+ 使用 =jp= 方法打印 JSON,使用 =jjp= 方法打印格式化后的 JSON。
701
904
 
702
- ***** 添加索引 =add_index=
703
- #+BEGIN_EXAMPLE
704
- Student.add_index :name
705
- Student.add_index [:branch_id, :party_id], unique: true, name: 'by_branch_party'
706
- #+END_EXAMPLE
905
+ **** =String=
906
+
907
+ ***** =Srting#p=
707
908
 
708
- ***** 修改字段注释 =change_column_comment=
709
- #+BEGIN_EXAMPLE
710
- Student.change_column_comment :note, '备注'
711
- #+END_EXAMPLE
909
+ =p= 方法的定义如下:
712
910
 
713
- ***** 修改字段默认值 =change_column_default=
714
- #+BEGIN_EXAMPLE
715
- Student.change_column_default :note, '默认值'
716
- #+END_EXAMPLE
717
-
718
- ***** 修改字段名称 =rename_column=
719
- #+BEGIN_EXAMPLE
720
- Student.rename_column :note, :remark
721
- #+END_EXAMPLE
911
+ #+begin_example
912
+ class String
913
+ def p
914
+ puts self
915
+ end
916
+ end
917
+ #+end_example
722
918
 
723
- ***** 修改表名 =rename_table=
724
- #+BEGIN_EXAMPLE
725
- Student.rename_table :seitou
726
- #+END_EXAMPLE
919
+ =​"hello".p= 等价于 =puts "hello"​= 。
727
920
 
728
- ***** 修改表注释 =change_table_comment=
729
- #+BEGIN_EXAMPLE
730
- Student.change_table_comment from: '', to: '学生表'
731
- #+END_EXAMPLE
921
+ ***** =String#parse=
732
922
 
733
- ***** 删除表 =drop_table=
734
- #+BEGIN_EXAMPLE
735
- Student.drop_table
736
- #+END_EXAMPLE
923
+ 对于一个表示文件路径的字符串,可以调用 =parse= 方法通过文件路径中的后缀名来分别对 Excel、CSV、JSON 文件进行解析。
737
924
 
738
- ***** 删除索引 =remove_index=
739
925
  #+BEGIN_EXAMPLE
740
- Student.remove_index :age
741
- Student.remove_index name: 'by_branch_party'
926
+ excel = 'path/to/excel.xlsx'.parse
927
+ csv = 'path/to/csv.csv'.parse
928
+ json = 'path/to/json.json'.parse
742
929
  #+END_EXAMPLE
743
930
 
744
- ***** 查询表注释 =table_comment=
745
- #+BEGIN_EXAMPLE
746
- Student.table_comment
747
- #+END_EXAMPLE
931
+ **** =ID=
748
932
 
749
- ***** 列出表的索引 =indexes=
750
- #+BEGIN_EXAMPLE
751
- Student.indexes
752
- #+END_EXAMPLE
933
+ Arql 提供了一个 =ID= 类,用来生成雪花算法 ID 和 UUID。
934
+
935
+ #+BEGIN_EXAMPLE
936
+ id = ID.long # 生成一个雪花算法 ID
937
+ id = ID.uuid # 生成一个 UUID
938
+ #+END_EXAMPLE
753
939
 
754
- **** 读写 Excel 和 CSV 文件
940
+ *** 读写 Excel 和 CSV 文件
755
941
 
756
- Arql 集成了 =roo= 和 =caxlsx= 两个 Excel 库,提供了用于解析和生成 Excel 文件的方法。同时,Arql 也提供了用于读写 CSV 文件的方法。
942
+ Arql 集成了 =roo= 和 =caxlsx= 两个 Excel 库,提供了用于解析和生成 Excel 文件的方法。同时,Arql 也提供了用于读写 CSV 文件的方法。
757
943
 
758
- ***** 解析 Excel
944
+ **** 解析 Excel
759
945
 
760
- Arql 为 =Kernel= 模块添加了 =parse_excel= 方法,可以用来解析 Excel 文件。例如:
946
+ Arql 为 =Kernel= 模块添加了 =parse_excel= 方法,可以用来解析 Excel 文件。例如:
761
947
 
762
- #+BEGIN_EXAMPLE
763
- ARQL ❯ parse_excel 'path/to/excel.xlsx'
764
- #+END_EXAMPLE
948
+ #+BEGIN_EXAMPLE
949
+ ARQL ❯ parse_excel 'path/to/excel.xlsx'
950
+ #+END_EXAMPLE
765
951
 
766
- 文件路径中可以使用 =~/= 表示用户的主目录,Arql 会自动展开。
952
+ 文件路径中可以使用 =~/= 表示用户的主目录,Arql 会自动展开。
767
953
 
768
954
 
769
- 也可以在一个表示文件路径的 =String= 对象上调用 =parse_excel= 方法:
955
+ 也可以在一个表示文件路径的 =String= 对象上调用 =parse_excel= 方法:
770
956
 
771
- #+BEGIN_EXAMPLE
772
- ARQL ❯ 'path/to/excel.xlsx'.parse_excel
773
- #+END_EXAMPLE
957
+ #+BEGIN_EXAMPLE
958
+ ARQL ❯ 'path/to/excel.xlsx'.parse_excel
959
+ #+END_EXAMPLE
774
960
 
775
- =parse_excel= 方法会返回一个 =Hash= 对象,Key 为 Sheet 名称,Value 为 Sheet 的数据,Value 是一个二维数组。例如:
961
+ =parse_excel= 方法会返回一个 =Hash= 对象,Key 为 Sheet 名称,Value 为 Sheet 的数据,Value 是一个二维数组。例如:
776
962
 
777
- #+BEGIN_EXAMPLE
778
- {
779
- 'Sheet1' => [
780
- ['A1', 'B1', 'C1'],
781
- ['A2', 'B2', 'C2'],
782
- ['A3', 'B3', 'C3']
783
- ],
784
- 'Sheet2' => [
785
- ['A1', 'B1', 'C1'],
786
- ['A2', 'B2', 'C2'],
787
- ['A3', 'B3', 'C3']
788
- ]
789
- }
790
- #+END_EXAMPLE
963
+ #+BEGIN_EXAMPLE
964
+ {
965
+ 'Sheet1' => [
966
+ ['A1', 'B1', 'C1'],
967
+ ['A2', 'B2', 'C2'],
968
+ ['A3', 'B3', 'C3']
969
+ ],
970
+ 'Sheet2' => [
971
+ ['A1', 'B1', 'C1'],
972
+ ['A2', 'B2', 'C2'],
973
+ ['A3', 'B3', 'C3']
974
+ ]
975
+ }
976
+ #+END_EXAMPLE
791
977
 
792
- ***** 生成 Excel
978
+ **** 生成 Excel
793
979
 
794
- Arql 为 =Hash= / =Array= / =ActiveRecord::Relation= / =ActiveRecord::Base= 对象添加了 =write_excel= 方法,可以用来
795
- 生成 Excel 文件:
980
+ Arql 为 =Hash= / =Array= / =ActiveRecord::Relation= / =ActiveRecord::Base= 对象添加了 =write_excel= 方法,可以用来
981
+ 生成 Excel 文件:
796
982
 
797
- ****** 从 =Hash= 对象生成 Excel
983
+ ***** 从 =Hash= 对象生成 Excel
798
984
 
799
- #+BEGIN_EXAMPLE
800
- ARQL ❯ obj.write_excel 'path/to/excel.xlsx'
801
- #+END_EXAMPLE
985
+ #+BEGIN_EXAMPLE
986
+ ARQL ❯ obj.write_excel 'path/to/excel.xlsx'
987
+ #+END_EXAMPLE
802
988
 
803
- =Hash#write_excel= 要求 Hash 对象 Key 是 Sheet 名称,Value 是 Sheet 的数据,Value 的类型可以是:
989
+ =Hash#write_excel= 要求 Hash 对象 Key 是 Sheet 名称,Value 是 Sheet 的数据,Value 的类型可以是:
804
990
 
805
- + 一个数组,数组的元素可以是:
806
- + 一个数组,表示一行数据
807
- + 一个 Hash 对象,表示一行数据,Key 是列名,Value 是列值
808
- + 一个 ActiveRecord::Base 对象,表示一行数据
809
- + 一个 Hash 对象,一共包含两个键值对:
810
- + =:fields=, 一个数组,表示列名
811
- + =:data=, 一个二维数组,表示数据
991
+ + 一个数组,数组的元素可以是:
992
+ + 一个数组,表示一行数据
993
+ + 一个 Hash 对象,表示一行数据,Key 是列名,Value 是列值
994
+ + 一个 ActiveRecord::Base 对象,表示一行数据
995
+ + 一个 Hash 对象,一共包含两个键值对:
996
+ + =:fields=, 一个数组,表示列名
997
+ + =:data=, 一个二维数组,表示数据
812
998
 
813
- ****** 从 =Array= 对象生成 Excel
999
+ ***** 从 =Array= 对象生成 Excel
814
1000
 
815
- #+BEGIN_EXAMPLE
816
- ARQL ❯ obj.write_excel 'path/to/excel.xlsx', :name, :age, :gender, sheet_name: '订单数据'
817
- #+END_EXAMPLE
1001
+ #+BEGIN_EXAMPLE
1002
+ ARQL ❯ obj.write_excel 'path/to/excel.xlsx', :name, :age, :gender, sheet_name: '订单数据'
1003
+ #+END_EXAMPLE
818
1004
 
819
- 其中:
1005
+ 其中:
820
1006
 
821
- + =:name, :age, :gender= 这几个参数是列名,如果不指定,会根据数组的第一个元素来确定列名:
822
- - 如果元素是 =ActiveRecord::Base= 对象,会使用对象的全部属性名(即数据库字段列表)作为列名
823
- - 如果元素是 =Hash= 对象,会使用 =Hash= 的 全部 Key 作为列名
824
- + =sheet_name= 指定 Sheet 名称,如果不指定,会使用默认的 Sheet 名称 =Sheet1=
1007
+ + =:name, :age, :gender= 这几个参数是列名,如果不指定,会根据数组的第一个元素来确定列名:
1008
+ - 如果元素是 =ActiveRecord::Base= 对象,会使用对象的全部属性名(即数据库字段列表)作为列名
1009
+ - 如果元素是 =Hash= 对象,会使用 =Hash= 的 全部 Key 作为列名
1010
+ + =sheet_name= 指定 Sheet 名称,如果不指定,会使用默认的 Sheet 名称 =Sheet1=
825
1011
 
826
- =Array= 对象的每一个元素表示一行数据, =Array#write_excel= 要求 Array 对象每个元素:
1012
+ =Array= 对象的每一个元素表示一行数据, =Array#write_excel= 要求 Array 对象每个元素:
827
1013
 
828
- + 一个 =ActiveRecord::Base= 对象
829
- + 一个 =Hash= 对象,表示一行数据,Key 是列名,Value 是列值
830
- + 一个数组,表示一行数据
1014
+ + 一个 =ActiveRecord::Base= 对象
1015
+ + 一个 =Hash= 对象,表示一行数据,Key 是列名,Value 是列值
1016
+ + 一个数组,表示一行数据
831
1017
 
832
- ****** 从 =ActiveRecord::Base= 对象生成 Excel
1018
+ ***** 从 =ActiveRecord::Base= 对象生成 Excel
833
1019
 
834
- #+BEGIN_EXAMPLE
835
- ARQL ❯ Student.find(123).write_excel 'path/to/excel.xlsx', sheet_name: '学生数据'
836
- #+END_EXAMPLE
1020
+ #+BEGIN_EXAMPLE
1021
+ ARQL ❯ Student.find(123).write_excel 'path/to/excel.xlsx', sheet_name: '学生数据'
1022
+ #+END_EXAMPLE
837
1023
 
838
- =ActiveRecord::Base= 的 =write_excel= 对象实际上就是把这个 =ActiveRecord::Base= 对象包装成一个只有一个元素的 =Array= 对
839
- 象,然后调用 =Array= 的 =write_excel= 方法。
1024
+ =ActiveRecord::Base= 的 =write_excel= 对象实际上就是把这个 =ActiveRecord::Base= 对象包装成一个只有一个元素的 =Array= 对
1025
+ 象,然后调用 =Array= 的 =write_excel= 方法。
840
1026
 
841
- ****** 从 =ActiveRecord::Relation= 对象生成 Excel
1027
+ ***** 从 =ActiveRecord::Relation= 对象生成 Excel
842
1028
 
843
- #+BEGIN_EXAMPLE
844
- ARQL ❯ Student.where(gender: 'M').write_excel 'path/to/excel.xlsx', sheet_name: '男学生'
845
- #+END_EXAMPLE
1029
+ #+BEGIN_EXAMPLE
1030
+ ARQL ❯ Student.where(gender: 'M').write_excel 'path/to/excel.xlsx', sheet_name: '男学生'
1031
+ #+END_EXAMPLE
846
1032
 
847
- =ActiveRecord::Relation= 的 =write_excel= 对象实际上就是把这个 =ActiveRecord::Relation= 对象转换成一个 =Array= 对象,然
848
- 后调用 =Array= 的 =write_excel= 方法。
1033
+ =ActiveRecord::Relation= 的 =write_excel= 对象实际上就是把这个 =ActiveRecord::Relation= 对象转换成一个 =Array= 对象,然
1034
+ 后调用 =Array= 的 =write_excel= 方法。
849
1035
 
850
- ***** 解析 CSV
1036
+ **** 解析 CSV
851
1037
 
852
- Arql 提供了 =parse_csv= 方法,可以用来解析 CSV 文件:
1038
+ Arql 提供了 =parse_csv= 方法,可以用来解析 CSV 文件:
853
1039
 
854
- #+BEGIN_EXAMPLE
855
- ARQL ❯ parse_csv 'path/to/csv.csv'
856
- #+END_EXAMPLE
1040
+ #+BEGIN_EXAMPLE
1041
+ ARQL ❯ parse_csv 'path/to/csv.csv'
1042
+ #+END_EXAMPLE
857
1043
 
858
- =parse_csv= 方法返回一个标准库中的 CSV 对象。
1044
+ =parse_csv= 方法返回一个标准库中的 CSV 对象。
859
1045
 
860
- =parse_csv= 可以有以下选项参数:
1046
+ =parse_csv= 可以有以下选项参数:
861
1047
 
862
- - =encoding=, 指定 CSV 文件的编码,默认是 =UTF-16= (with BOM)
863
- - =headers=, 指定是否包含表头,默认是 =false=
864
- - =col_sep=, 指定列分隔符,默认是 =\t=
865
- - =row_sep=, 指定行分隔符,默认是 =\r\n=
1048
+ - =encoding=, 指定 CSV 文件的编码,默认是 =UTF-16= (with BOM)
1049
+ - =headers=, 指定是否包含表头,默认是 =false=
1050
+ - =col_sep=, 指定列分隔符,默认是 =\t=
1051
+ - =row_sep=, 指定行分隔符,默认是 =\r\n=
866
1052
 
867
- (以上默认值实际就是 Microsoft Office Excel 保存 CSV 文件时默认使用的配置)
1053
+ (以上默认值实际就是 Microsoft Office Excel 保存 CSV 文件时默认使用的配置)
868
1054
 
869
- 也可以在一个表示文件路径的 =String= 对象上调用 =parse_csv= 方法:
1055
+ 也可以在一个表示文件路径的 =String= 对象上调用 =parse_csv= 方法:
870
1056
 
871
- #+BEGIN_EXAMPLE
872
- ARQL ❯ 'path/to/csv.csv'.parse_csv
873
- #+END_EXAMPLE
1057
+ #+BEGIN_EXAMPLE
1058
+ ARQL ❯ 'path/to/csv.csv'.parse_csv
1059
+ #+END_EXAMPLE
874
1060
 
875
- ***** 生成 CSV
876
- Arql 为 =Array= / =ActiveRecord::Relation= / =ActiveRecord::Base= 对象添加了 =write_csv= 方法,可以用来生成 CSV 文件:
1061
+ **** 生成 CSV
1062
+ Arql 为 =Array= / =ActiveRecord::Relation= / =ActiveRecord::Base= 对象添加了 =write_csv= 方法,可以用来生成 CSV 文件:
877
1063
 
878
- ****** 从 =Array= 对象生成 CSV
1064
+ ***** 从 =Array= 对象生成 CSV
879
1065
 
880
- #+BEGIN_EXAMPLE
881
- ARQL ❯ obj.write_csv 'path/to/csv.csv', :name, :age, :gender, sheet_name: '订单数据'
882
- #+END_EXAMPLE
1066
+ #+BEGIN_EXAMPLE
1067
+ ARQL ❯ obj.write_csv 'path/to/csv.csv', :name, :age, :gender, sheet_name: '订单数据'
1068
+ #+END_EXAMPLE
883
1069
 
884
- 用法和 =Array= 对象的 =write_excel= 方法类似。
1070
+ 用法和 =Array= 对象的 =write_excel= 方法类似。
885
1071
 
886
1072
 
887
- ****** 从 =ActiveRecord::Base= 对象生成 CSV
1073
+ ***** 从 =ActiveRecord::Base= 对象生成 CSV
888
1074
 
889
- #+BEGIN_EXAMPLE
890
- ARQL ❯ Student.find(123).write_csv 'path/to/csv.csv', sheet_name: '学生数据'
891
- #+END_EXAMPLE
1075
+ #+BEGIN_EXAMPLE
1076
+ ARQL ❯ Student.find(123).write_csv 'path/to/csv.csv', sheet_name: '学生数据'
1077
+ #+END_EXAMPLE
892
1078
 
893
- 用法和 =ActiveRecord::Base= 对象的 =write_excel= 方法类似。
1079
+ 用法和 =ActiveRecord::Base= 对象的 =write_excel= 方法类似。
894
1080
 
895
- ****** 从 =ActiveRecord::Relation= 对象生成 CSV
1081
+ ***** 从 =ActiveRecord::Relation= 对象生成 CSV
896
1082
 
897
- #+BEGIN_EXAMPLE
898
- ARQL ❯ Student.where(gender: 'M').write_csv 'path/to/csv.csv', sheet_name: '男学生'
899
- #+END_EXAMPLE
1083
+ #+BEGIN_EXAMPLE
1084
+ ARQL ❯ Student.where(gender: 'M').write_csv 'path/to/csv.csv', sheet_name: '男学生'
1085
+ #+END_EXAMPLE
900
1086
 
901
- 用法和 =ActiveRecord::Relation= 对象的 =write_excel= 方法类似。
1087
+ 用法和 =ActiveRecord::Relation= 对象的 =write_excel= 方法类似。
902
1088
 
903
- **** dump 数据
1089
+ *** dump 数据
904
1090
 
905
- 注意: 仅支持 MySQL 数据库
1091
+ 注意: 仅支持 MySQL 数据库
906
1092
 
907
- Arql 为 =Array= / =ActiveRecord::Base= / =ActiveRecord::Relation= 等对象添加了 =dump= 方法,可以用来导出数据到 SQL 文件:
1093
+ Arql 为 =Array= / =ActiveRecord::Base= / =ActiveRecord::Relation= 等对象添加了 =dump= 方法,可以用来导出数据到 SQL 文件:
908
1094
 
909
1095
 
910
- ***** 从 Array 对象导出数据
1096
+ **** 从 Array 对象导出数据
911
1097
 
912
- #+BEGIN_EXAMPLE
913
- ARQL ❯ obj.dump 'path/to/dump.sql', batch_size: 5000
914
- #+END_EXAMPLE
1098
+ #+BEGIN_EXAMPLE
1099
+ ARQL ❯ obj.dump 'path/to/dump.sql', batch_size: 5000
1100
+ #+END_EXAMPLE
915
1101
 
916
- =Array= 对象的每一个元素必须是一个 =ActiveRecord::Base= 对象
1102
+ =Array= 对象的每一个元素必须是一个 =ActiveRecord::Base= 对象
917
1103
 
918
- =batch_size= 参数指定每个批次查询出的数据,默认值为 500
1104
+ =batch_size= 参数指定每个批次查询出的数据,默认值为 500
919
1105
 
920
- ***** 从 ActiveRecord::Base 对象导出数据
1106
+ **** 从 ActiveRecord::Base 对象导出数据
921
1107
 
922
- #+BEGIN_EXAMPLE
923
- ARQL ❯ Student.find(123).dump 'path/to/dump.sql', batch_size: 5000
924
- #+END_EXAMPLE
1108
+ #+BEGIN_EXAMPLE
1109
+ ARQL ❯ Student.find(123).dump 'path/to/dump.sql', batch_size: 5000
1110
+ #+END_EXAMPLE
925
1111
 
926
- =ActiveRecord::Base= 对象的 =dump= 方法实际上就是把这个 =ActiveRecord::Base= 对象包装成一个只有一个元素的 =Array= 对象,然后调用 =Array= 的 =dump= 方法。
927
-
928
- ***** 从 ActiveRecord::Relation 对象导出数据
929
-
930
- #+BEGIN_EXAMPLE
931
- ARQL ❯ Student.where(gender: 'M').dump 'path/to/dump.sql', batch_size: 5000
932
- #+END_EXAMPLE
933
-
934
- =ActiveRecord::Relation= 的 =dump= 对象实际上就是把这个 =ActiveRecord::Relation= 对象转换成一个 =Array= 对象,然后调用 =Array= 的 =dump= 方法。
1112
+ =ActiveRecord::Base= 对象的 =dump= 方法实际上就是把这个 =ActiveRecord::Base= 对象包装成一个只有一个元素的 =Array= 对象,然后调用 =Array= 的 =dump= 方法。
935
1113
 
936
-
937
- ***** 调用 ActiveRecord::Base 的 dump 类方法
1114
+ **** 从 ActiveRecord::Relation 对象导出数据
938
1115
 
939
- #+BEGIN_EXAMPLE
940
- ARQL ❯ Student.dump 'path/to/dump.sql', no_create_table: false
941
- #+END_EXAMPLE
1116
+ #+BEGIN_EXAMPLE
1117
+ ARQL ❯ Student.where(gender: 'M').dump 'path/to/dump.sql', batch_size: 5000
1118
+ #+END_EXAMPLE
942
1119
 
943
- 这个方法会通过 =mysqldump= 命令 =Student= 表中的所有数据导出到 SQL 文件中。
1120
+ =ActiveRecord::Relation= =dump= 对象实际上就是把这个 =ActiveRecord::Relation= 对象转换成一个 =Array= 对象,然后调用 =Array= 的 =dump= 方法。
944
1121
 
945
- =no_create_table= 参数指定是否在 SQL 文件中包含创建表的语句,默认值为 =false=
1122
+ **** 调用 ActiveRecord::Base dump 类方法
946
1123
 
947
-
948
-
949
- ***** 在全局连接对象 =$C= 上调用 dump 方法
1124
+ #+BEGIN_EXAMPLE
1125
+ ARQL ❯ Student.dump 'path/to/dump.sql', no_create_table: false
1126
+ #+END_EXAMPLE
950
1127
 
951
- #+BEGIN_EXAMPLE
952
- ARQL ❯ $C.dump 'path/to/dump.sql', no_create_db: false
953
- #+END_EXAMPLE
1128
+ 这个方法会通过 =mysqldump= 命令 把 =Student= 表中的所有数据导出到 SQL 文件中。
954
1129
 
955
- 这个方法会通过 mysqldump 命令把当前数据库中的所有表的数据导出到 SQL 文件中。
1130
+ =no_create_table= 参数指定是否在 SQL 文件中包含创建表的语句,默认值为 =false= 。
956
1131
 
957
- =no_create_db= 参数指定是否在 SQL 文件中包含创建数据库的语句,默认值为 =false= 。
958
-
959
1132
 
960
- **** Plot
961
-
962
- Arql 集成了 Ruby 的 =youplot= 库,为 =Array= 添加了一些可以用来绘制图表的方法:
963
-
964
- + =barplot=
965
- + =countplot=
966
- + =histo=
967
- + =lineplot=
968
- + =lineplots=
969
- + =scatter=
970
- + =density=
971
- + =boxplot=
1133
+ *** Plot
1134
+
1135
+ Arql 集成了 Ruby 的 =youplot= 库,为 =Array= 添加了一些可以用来绘制图表的方法:
1136
+
1137
+ + =barplot=
1138
+ + =countplot=
1139
+ + =histo=
1140
+ + =lineplot=
1141
+ + =lineplots=
1142
+ + =scatter=
1143
+ + =density=
1144
+ + =boxplot=
972
1145
 
973
- 示例:
1146
+ 示例:
974
1147
 
975
- 数量统计图:
1148
+ 数量统计图:
976
1149
 
977
- #+BEGIN_EXAMPLE
978
- ARQL@demo247(main) [44] ❯ Student.pluck(:gender)
979
- => ["M", "M", "M", "M", "M", "M", "M", "F", "M", "F", "M", "M", "M", "M", "M"]
980
- ARQL@demo247(main) [45] ❯ Student.pluck(:gender).countplot
981
- ┌ ┐
982
- M ┤■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 13.0
983
- F ┤■■■■■ 2.0
984
- └ ┘
985
- #+END_EXAMPLE
1150
+ #+BEGIN_EXAMPLE
1151
+ ARQL@demo247(main) [44] ❯ Student.pluck(:gender)
1152
+ => ["M", "M", "M", "M", "M", "M", "M", "F", "M", "F", "M", "M", "M", "M", "M"]
1153
+ ARQL@demo247(main) [45] ❯ Student.pluck(:gender).countplot
1154
+ ┌ ┐
1155
+ M ┤■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 13.0
1156
+ F ┤■■■■■ 2.0
1157
+ └ ┘
1158
+ #+END_EXAMPLE
986
1159
 
987
- 分布图:
1160
+ 分布图:
988
1161
 
989
- #+BEGIN_EXAMPLE
990
- ARQL@jicai.dev(main) [18] ❯ Order.last(20).pluck(:order_sum)
991
- => [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]
992
- ARQL@jicai.dev(main) [19] ❯ Order.last(20).pluck(:order_sum).histo
993
- ┌ ┐
994
- [ 0.0, 50000.0) ┤▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 17
995
- [ 50000.0, 100000.0) ┤▇▇▇▇ 2
996
- [100000.0, 150000.0) ┤ 0
997
- [150000.0, 200000.0) ┤ 0
998
- [200000.0, 250000.0) ┤▇▇ 1
999
- └ ┘
1000
- Frequency
1162
+ #+BEGIN_EXAMPLE
1163
+ ARQL@jicai.dev(main) [18] ❯ Order.last(20).pluck(:order_sum)
1164
+ => [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]
1165
+ ARQL@jicai.dev(main) [19] ❯ Order.last(20).pluck(:order_sum).histo
1166
+ ┌ ┐
1167
+ [ 0.0, 50000.0) ┤▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 17
1168
+ [ 50000.0, 100000.0) ┤▇▇▇▇ 2
1169
+ [100000.0, 150000.0) ┤ 0
1170
+ [150000.0, 200000.0) ┤ 0
1171
+ [200000.0, 250000.0) ┤▇▇ 1
1172
+ └ ┘
1173
+ Frequency
1001
1174
 
1002
- #+END_EXAMPLE
1003
-
1004
- **** =String=
1175
+ #+END_EXAMPLE
1005
1176
 
1006
- ***** =Srting#p=
1007
-
1008
- =p= 方法的定义如下:
1009
-
1010
- #+begin_example
1011
- class String
1012
- def p
1013
- puts self
1014
- end
1015
- end
1016
- #+end_example
1177
+ *** Ransack
1017
1178
 
1018
- =​"hello".p= 等价于 =puts "hello"​= 。
1019
-
1020
- ***** =String#parse=
1021
-
1022
- 对于一个表示文件路径的字符串,可以调用 =parse= 方法通过文件路径中的后缀名来分别对 Excel、CSV、JSON 文件进行解析。
1023
-
1024
- #+BEGIN_EXAMPLE
1025
- excel = 'path/to/excel.xlsx'.parse
1026
- csv = 'path/to/csv.csv'.parse
1027
- json = 'path/to/json.json'.parse
1028
- #+END_EXAMPLE
1029
-
1030
- **** =ID=
1031
-
1032
- Arql 提供了一个 =ID= 类,用来生成雪花算法 ID 和 UUID。
1179
+ Arql 集成了 =Ransack=:
1033
1180
 
1034
1181
  #+BEGIN_EXAMPLE
1035
- id = ID.long # 生成一个雪花算法 ID
1036
- id = ID.uuid # 生成一个 UUID
1182
+ Student.ransack(name_cont: 'Tom').result # 模糊查询名字中包含 'Tom' 的学生
1183
+ Student.ransack(name_start: 'Tom').result # 模糊查询名字以 'Tom' 开头的学生
1037
1184
  #+END_EXAMPLE
1038
-
1039
- **** Ransack
1040
-
1041
- Arql 集成了 =Ransack=:
1042
-
1043
- #+BEGIN_EXAMPLE
1044
- Student.ransack(name_cont: 'Tom').result # 模糊查询名字中包含 'Tom' 的学生
1045
- Student.ransack(name_start: 'Tom').result # 模糊查询名字以 'Tom' 开头的学生
1046
- #+END_EXAMPLE
1047
1185
 
1048
- *** Emacs Org Babel 集成
1186
+ ** Emacs Org Babel 集成
1049
1187
 
1050
- 这里有一个 [[https://github.com/lululau/spacemacs-layers/blob/master/ob-arql/local/ob-arql/ob-arql.el][ob-arql]] 用于集成 Emacs org babel。
1188
+ 这里有一个 [[https://github.com/lululau/spacemacs-layers/blob/master/ob-arql/local/ob-arql/ob-arql.el][ob-arql]] 用于集成 Emacs org babel。
1051
1189
 
1052
1190
  ** Guides and Tips
1053
1191
  *** [[./define-associations-zh_CN.org][在 Initializer 文件中定义关联关系]]
@@ -1065,19 +1203,6 @@
1065
1203
  #+BEGIN_EXAMPLE
1066
1204
  arql -d db/development.sqlite3
1067
1205
  #+END_EXAMPLE
1068
-
1069
- *** 根据名称或注释查找字段
1070
-
1071
- 我们在熟悉一个项目的时候,经常会遇到这样的情况:我们知道某个字段的名称或注释,但是不知道它对应的表名和字段名。这时候我们可以使用如下方法来查找:
1072
-
1073
- #+BEGIN_SRC ruby
1074
- 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})"} }
1075
-
1076
- # 输出:
1077
- # Table: order, Column: entry_amount (订单金额)
1078
- # Table: sub_order, Column: entry_price (金额)
1079
- #+END_SRC
1080
-
1081
1206
  *** [[./ruby-guides-for-java-developer-zh_CN.org][给 Java 开发者的 Ruby 入门简明教程]]
1082
1207
  *** [[./simple-pry-guides-zh_CN.org][简明 Pry 使用指南]]
1083
1208
  *** [[./simple-active-record-guide-zh_CN.org][简明 ActiveRecord 使用指南]]