arql 0.3.31 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
@@ -5,7 +5,7 @@
5
5
  创建一个文件 =~/.arql.d/auto_gen_id.rb= ,内容如下:
6
6
 
7
7
  #+BEGIN_SRC ruby
8
- class ::ArqlModel
8
+ class ::Arql::BaseModel
9
9
  before_create do
10
10
  if id.blank?
11
11
  id_type = self.class.columns_hash['id'].sql_type.scan(/\w+/).first
@@ -5,7 +5,7 @@
5
5
  Create a file =~/.arql.d/auto_gen_id.rb= with the following content:
6
6
 
7
7
  #+BEGIN_SRC ruby
8
- class ::ArqlModel
8
+ class :Arql::BaseModel
9
9
  before_create do
10
10
  if id.blank?
11
11
  id_type = self.class.columns_hash['id'].sql_type.scan(/\w+/).first
@@ -1,6 +1,6 @@
1
1
  * 配置文件中的自定义配置项
2
2
 
3
- 你可以在配置文件 (如默认的 =~/.arql.yaml= / =~/.arql.d/init.yaml= ) 中定义自己的配置项,然后在代码中通过 =Arql::App.config["CONF_KEY"]-= 来获取配置项的值。
3
+ 你可以在配置文件 (如默认的 =~/.arql.yaml= / =~/.arql.d/init.yaml= ) 中定义自己的配置项,然后在代码中通过 =env_config(/my_env/)["CONF_KEY"]-= 来获取配置项的值。
4
4
 
5
5
  例如,假设系统对 BankAccount 表的 =account_no= 字段进行了加密,你可以在配置文件中定义加密的密钥:
6
6
 
@@ -23,7 +23,7 @@
23
23
  def self.encrypt_account_no(account_no)
24
24
  cipher = OpenSSL::Cipher.new('AES-128-ECB')
25
25
  cipher.encrypt
26
- cipher.key = Arql::App.config["encrypt_key"]
26
+ cipher.key = env_config(/my_env/)["encrypt_key"]
27
27
  encrypted = cipher.update(account_no) + cipher.final
28
28
  encrypted.unpack('H*').first
29
29
  end
@@ -31,7 +31,7 @@
31
31
  def self.decrypt_account_no(encrypted_account_no)
32
32
  cipher = OpenSSL::Cipher.new('AES-128-ECB')
33
33
  cipher.decrypt
34
- cipher.key = Arql::App.config["encrypt_key"]
34
+ cipher.key = env_config(/my_env/)["encrypt_key"]
35
35
  decrypted = cipher.update([encrypted_account_no].pack('H*')) + cipher.final
36
36
  decrypted
37
37
  end
@@ -48,3 +48,40 @@
48
48
  end
49
49
  end
50
50
  #+END_SRC
51
+
52
+ 也可以直接使用 Namespace Module 的 config 方法来获取配置项的值,例如:
53
+
54
+ 假设 Namespace Module 为 =NS=, 那么上述代码可以改写为:
55
+
56
+ #+BEGIN_SRC ruby
57
+ class BankAccount
58
+
59
+ def self.encrypt_account_no(account_no)
60
+ cipher = OpenSSL::Cipher.new('AES-128-ECB')
61
+ cipher.encrypt
62
+ cipher.key = NS::config["encrypt_key"]
63
+ encrypted = cipher.update(account_no) + cipher.final
64
+ encrypted.unpack('H*').first
65
+ end
66
+
67
+ def self.decrypt_account_no(encrypted_account_no)
68
+ cipher = OpenSSL::Cipher.new('AES-128-ECB')
69
+ cipher.decrypt
70
+ cipher.key = NS::config["encrypt_key"]
71
+ decrypted = cipher.update([encrypted_account_no].pack('H*')) + cipher.final
72
+ decrypted
73
+ end
74
+
75
+
76
+ # 从数据库查询出数据之后,自动解密 account_no 字段
77
+ after_find do
78
+ self.password = decrypt_account_no(self.password)
79
+ end
80
+
81
+ # 保存数据之前,自动加密 account_no 字段
82
+ before_save do
83
+ self.password = encrypt_account_no(self.password)
84
+ end
85
+ end
86
+ #+END_SRC
87
+
@@ -1,54 +1,93 @@
1
1
  * Additional config items in Configuration File
2
2
 
3
- You can define your own configuration items in the configuration file (such as the default =~/.arql.yaml= /
4
- =~/.arql.d/init.yaml=), and then get the value of the configuration item in the code through
5
- =Arql::App.config["CONF_KEY"]=.
6
-
7
- For example, suppose the system encrypts the =account_no= field of the BankAccount table, you can define the
8
- encryption key in the configuration file:
9
-
10
- #+BEGIN_SRC yaml
11
- dev:
12
- <<: *default
13
- host: 127.0.0.1
14
- port: 3306
15
- username: test
16
- password: test123456
17
- database: devel
18
- encrypt_key: "1234567890abcdef"
19
- #+END_SRC
20
-
21
- Then you can read the value of the configuration item in the Initialzier code (=~/.arql.rb= /
22
- =~/.arql.d/init.rb=):
23
-
24
- #+BEGIN_SRC ruby
3
+ You can define your own configuration items in a configuration file (such as the default =~/.arql.yaml= /
4
+ =~/.arql.d/init.yaml= ), and then get the value of the configuration item in the code with
5
+ =env_config(/my_env/)["CONF_KEY"]-= .
6
+
7
+
8
+ For example, let's say the system encrypts the field of the =account_no= BankAccount table, and you can define the key
9
+ for encryption in the configuration file:
10
+
11
+ #+begin_src yaml
12
+ dev:
13
+ <<: *default
14
+ host: 127.0.0.1
15
+ port: 3306
16
+ username: test
17
+ password: test123456
18
+ database: devel
19
+ encrypt_key: "1234567890abcdef"
20
+ #+end_src
21
+
22
+
23
+ You can then read the value of the config item in the Initialzier code ( =~/.arql.rb= / =~/.arql.d/init.rb= ):
24
+
25
+ #+begin_src ruby
25
26
  class BankAccount
26
-
27
+
27
28
  def self.encrypt_account_no(account_no)
28
29
  cipher = OpenSSL::Cipher.new('AES-128-ECB')
29
30
  cipher.encrypt
30
- cipher.key = Arql::App.config["encrypt_key"]
31
+ cipher.key = env_config(/my_env/)["encrypt_key"]
31
32
  encrypted = cipher.update(account_no) + cipher.final
32
33
  encrypted.unpack('H*').first
33
34
  end
34
-
35
+
35
36
  def self.decrypt_account_no(encrypted_account_no)
36
37
  cipher = OpenSSL::Cipher.new('AES-128-ECB')
37
38
  cipher.decrypt
38
- cipher.key = Arql::App.config["encrypt_key"]
39
+ cipher.key = env_config(/my_env/)["encrypt_key"]
39
40
  decrypted = cipher.update([encrypted_account_no].pack('H*')) + cipher.final
40
41
  decrypted
41
42
  end
42
-
43
-
44
- # After querying the data from the database, automatically decrypt the account_no field
43
+
44
+
45
+ # 从数据库查询出数据之后,自动解密 account_no 字段
45
46
  after_find do
46
47
  self.password = decrypt_account_no(self.password)
47
48
  end
48
-
49
- # Before saving the data, automatically encrypt the account_no field
49
+
50
+ # 保存数据之前,自动加密 account_no 字段
51
+ before_save do
52
+ self.password = encrypt_account_no(self.password)
53
+ end
54
+ end
55
+ #+end_src
56
+
57
+
58
+ You can also use the config method of the Namespace Module to obtain the value of the configuration item, for example:
59
+
60
+
61
+ Assuming the Namespace Module is , then =NS= the above code can be rewritten as:
62
+
63
+ #+begin_src ruby
64
+ class BankAccount
65
+
66
+ def self.encrypt_account_no(account_no)
67
+ cipher = OpenSSL::Cipher.new('AES-128-ECB')
68
+ cipher.encrypt
69
+ cipher.key = NS::config["encrypt_key"]
70
+ encrypted = cipher.update(account_no) + cipher.final
71
+ encrypted.unpack('H*').first
72
+ end
73
+
74
+ def self.decrypt_account_no(encrypted_account_no)
75
+ cipher = OpenSSL::Cipher.new('AES-128-ECB')
76
+ cipher.decrypt
77
+ cipher.key = NS::config["encrypt_key"]
78
+ decrypted = cipher.update([encrypted_account_no].pack('H*')) + cipher.final
79
+ decrypted
80
+ end
81
+
82
+
83
+ # 从数据库查询出数据之后,自动解密 account_no 字段
84
+ after_find do
85
+ self.password = decrypt_account_no(self.password)
86
+ end
87
+
88
+ # 保存数据之前,自动加密 account_no 字段
50
89
  before_save do
51
90
  self.password = encrypt_account_no(self.password)
52
91
  end
53
92
  end
54
- #+END_SRC
93
+ #+end_src
@@ -5,26 +5,29 @@
5
5
  Initializer 文件是一个 Ruby 文件,因此可以在其中定义关联关系,例如:
6
6
 
7
7
  #+BEGIN_SRC ruby
8
- class Student
9
- has_many :courses, foreign_key: :student_id, class_name: 'Course'
10
- belongs_to :school, foreign_key: :school_id, class_name: 'School'
11
-
12
- has_and_belongs_to_many :teachers, join_table: 'students_teachers', foreign_key: :student_id, association_foreign_key: :teacher_id, class_name: 'Teacher'
13
- end
14
-
15
- class Course
16
- belongs_to :student, foreign_key: :student_id, class_name: 'Student'
17
- end
18
-
19
- class School
20
- has_many :students, foreign_key: :school_id, class_name: 'Student'
21
- end
22
-
23
- class Teacher
24
- has_and_belongs_to_many :students, join_table: 'students_teachers', foreign_key: :teacher_id, association_foreign_key: :student_id, class_name: 'Student'
8
+ module Blog
9
+ class Student
10
+ has_many :courses, foreign_key: :student_id, class_name: 'Course'
11
+ belongs_to :school, foreign_key: :school_id, class_name: 'School'
12
+
13
+ has_and_belongs_to_many :teachers, join_table: 'students_teachers', foreign_key: :student_id, association_foreign_key: :teacher_id, class_name: 'Teacher'
14
+ end
15
+
16
+ class Course
17
+ belongs_to :student, foreign_key: :student_id, class_name: 'Student'
18
+ end
19
+
20
+ class School
21
+ has_many :students, foreign_key: :school_id, class_name: 'Student'
22
+ end
23
+
24
+ class Teacher
25
+ has_and_belongs_to_many :students, join_table: 'students_teachers', foreign_key: :teacher_id, association_foreign_key: :student_id, class_name: 'Student'
26
+ end
25
27
  end
26
28
  #+END_SRC
27
29
 
30
+
28
31
  1. =has_one= 表明此表是一对一关系的属主
29
32
  2. =belongs_to= 表明此表是一对多或一对一关系的从属方
30
33
  3. =has_and_belongs_to_many= 表明此表是多对多关系的其中一方
@@ -36,3 +39,14 @@
36
39
 
37
40
  可以参考: https://guides.rubyonrails.org/association_basics.html
38
41
 
42
+ 考虑到模型类都是定义在 Namespace module 下面的, 因此这里的 Blog 是必要的。
43
+
44
+ 当然,不管通过 =-e= 选项选择了哪个环境,Arql 默认都会加载 =~/.arql.rb= 或 =~/.arql.d/init.rb= 文件,
45
+ 因此像上述示例中把固定的 Namespace =Blog= 放在默认的初始化文件中, 不是一个好的选择。
46
+
47
+ 有两种方案解决这个问题:
48
+
49
+ 1. 使用 arql 时,对于不同的环境,用 =-i= 选项来指定不同的初始化文件,例如: =arql -e blog -i ~/.arql.d/blog.rb=
50
+ 2. 参考 [[./initializer-structure-zh_CN.org][将不同环境的初始化代码放在不同的文件中]]
51
+
52
+
@@ -1,37 +1,60 @@
1
- * Define associations in Initializers
1
+ * 1. Define the relationship in the initializer file
2
2
 
3
- You can define associations in Initializers. Arql will generate model classes based on the database schema when it starts, and then load the Initializer file.
4
3
 
5
- The Initializer file is a Ruby file, so you can define associations in it, for example:
4
+ Associations can be defined in the initializer file, and when Arql starts, it first generates the model class based on
5
+ the database schema and then loads the initializer file.
6
6
 
7
- #+BEGIN_SRC ruby
8
- class Student
9
- has_many :courses, foreign_key: :student_id, class_name: 'Course'
10
- belongs_to :school, foreign_key: :school_id, class_name: 'School'
11
7
 
12
- has_and_belongs_to_many :teachers, join_table: 'students_teachers', foreign_key: :student_id, association_foreign_key: :teacher_id, class_name: 'Teacher'
13
- end
8
+ The initializer file is a Ruby file, so you can define associations within it, for example:
14
9
 
15
- class Course
16
- belongs_to :student, foreign_key: :student_id, class_name: 'Student'
17
- end
10
+ #+begin_src ruby
11
+ module Blog
12
+ class Student
13
+ has_many :courses, foreign_key: :student_id, class_name: 'Course'
14
+ belongs_to :school, foreign_key: :school_id, class_name: 'School'
18
15
 
19
- class School
20
- has_many :students, foreign_key: :school_id, class_name: 'Student'
21
- end
16
+ has_and_belongs_to_many :teachers, join_table: 'students_teachers', foreign_key: :student_id, association_foreign_key: :teacher_id, class_name: 'Teacher'
17
+ end
18
+
19
+ class Course
20
+ belongs_to :student, foreign_key: :student_id, class_name: 'Student'
21
+ end
22
22
 
23
- class Teacher
24
- has_and_belongs_to_many :students, join_table: 'students_teachers', foreign_key: :teacher_id, association_foreign_key: :student_id, class_name: 'Student'
23
+ class School
24
+ has_many :students, foreign_key: :school_id, class_name: 'Student'
25
+ end
26
+
27
+ class Teacher
28
+ has_and_belongs_to_many :students, join_table: 'students_teachers', foreign_key: :teacher_id, association_foreign_key: :student_id, class_name: 'Student'
29
+ end
25
30
  end
26
- #+END_SRC
27
-
28
- 1. =has_one= indicates that this table is the owner of a one-to-one relationship
29
- 2. =belongs_to= indicates that this table is the dependent side of a one-to-many or one-to-one relationship
30
- 3. =has_and_belongs_to_many= indicates that this table is one of the many-to-many relationships
31
- 4. =class_name= indicates the Model class name of the corresponding relationship (the Model class name is actually the CamelCase form of the table name)
32
- 5. =foreign_key= indicates the name of the association field on the dependent side of the association
33
- 6. =primary_key= indicates the name of the association field on the owner side of the association
34
- 7. =join_table= in many-to-many relationships, indicates the name of the intermediate table that associates the two tables
35
- 8. =association_foreign_key= in many-to-many relationships, indicates the association field name of the other Model in the intermediate table
36
-
37
- You can refer to: https://guides.rubyonrails.org/association_basics.html
31
+ #+end_src
32
+
33
+ 1. =has_one= Indicates that this table is a one-to-one relationship with the owner
34
+ 2. =belongs_to= Indicates that this table is a subordinate of a one-to-many or one-to-one relationship
35
+ 3. =has_and_belongs_to_many= Indicates that this table is one of the parties to a many-to-many relationship
36
+ 4. =class_name= The model class name of the other party that indicates the relationship (the model class name is
37
+ actually the CamelCase form of the table name)
38
+ 5. =foreign_key= Indicates the name of the associated field on the side of the dependent table in the association
39
+ 6. =primary_key= Indicates the name of the association field on the side of the master table in the association
40
+ 7. =join_table= In a many-to-many relationship, the name of the intermediate table that is associated with two tables is
41
+ indicated
42
+ 8. =association_foreign_key= In a many-to-many relationship, indicates the name of the field associated with the other
43
+ model's model in the intermediate table
44
+
45
+ 可以参考: [[https://guides.rubyonrails.org/association_basics.html]]
46
+
47
+
48
+ Considering that the model classes are all defined under the Namespace module, a blog here is necessary.
49
+
50
+
51
+ Of course, Arql will load the =~/.arql.rb= OR =~/.arql.d/init.rb= file by default, regardless of which environment is
52
+ selected via the =-e= options, so putting a fixed namespace =Blog= in the default initialization file like in the
53
+ example above is not a good choice.
54
+
55
+ There are two ways to solve this problem:
56
+
57
+ 1.
58
+ When using arql, for different environments, use =-i= the option to specify different initialization files, such as:
59
+ =arql -e blog -i ~/.arql.d/blog.rb=
60
+ 2. Refer to Put the initialization code for different environments in different files
@@ -19,15 +19,33 @@
19
19
  然后在 =~/.arql.d/init.eb= 文件中写入以下代码:
20
20
 
21
21
  #+BEGIN_SRC ruby
22
- ["apollo", "space"].each do |project|
23
- if Arql::App.env.try { |e| e.include?(project + ".") }
24
- load(File.absolute_path(File.dirname(__FILE__) + "/#{project}.rb"))
25
- break
22
+ Dir.glob(File.dirname(__FILE__) + '/*.rb').each do |f|
23
+ Arql::App.instance.definitions.each do |env, definition|
24
+ if env.starts_with?(File.basename(f, '.rb'))
25
+ load(f, definition.namespace_module)
26
+ end
26
27
  end
27
28
  end
28
29
  #+END_SRC
29
30
 
30
- 这样,当执行 =arql -e apollo.dev= 或 =arql =e apollo.prod= 时,就会加载 =apollo.rb= 文件中的初始化代码;当执行 =arql
31
+ 这样,当执行 =arql -e apollo.dev= 或 =arql -e apollo.prod= 时,就会加载 =apollo.rb= 文件中的初始化代码;当执行 =arql
31
32
  -e space.dev= 或 =arql -e space.prod= 时,就会加载 =space.rb= 文件中的初始化代码。
32
33
 
34
+ =apollo.rb= 或 =space.rb= 文件中的代码将在对应的 Namespace Module 下执行:
35
+
36
+ #+BEGIN_SRC ruby
37
+ class Astronaut
38
+ has_many :missions
39
+ end
40
+ #+END_SRC
41
+
42
+ 等价于:
43
+
44
+ #+BEGIN_SRC ruby
45
+ module Apollo
46
+ class Astronaut
47
+ has_many :missions
48
+ end
49
+ end
50
+ #+END_SRC
33
51
 
@@ -1,31 +1,59 @@
1
1
  * Place your initialization code in a file named after the environment
2
2
 
3
- If you have multiple environments in your configuration file, you can place the initialization code for each environment in a separate file to avoid conflicts.
4
3
 
5
- Suppose you have 4 database environments in your configuration file:
4
+ There are often multiple environment configurations for multiple databases in the configuration file, so you can use the
5
+ method here to put the initialization code of different environments in different files to avoid conflicts.
6
6
 
7
- + apollo.dev
8
- + apollo.prod
9
- + space.dev
10
- + space.prod
7
+ Let's say you have 4 database environments configured in the configuration file:
11
8
 
12
- You can create the following files in the =~/.arql.d/= directory:
9
+ - apollo.dev
10
+ - apollo.prod
11
+ - space.dev
12
+ - space.prod
13
13
 
14
- + apollo.rb
15
- + space.rb
16
14
 
17
- Place the initialization code for the apollo project in the =apollo.rb= file; place the initialization code for the space project in the =space.rb= file.
15
+ Then you can create the following file in the =~/.arql.d/= directory:
16
+
17
+ - apollo.rb
18
+ - space.rb
19
+
20
+
21
+ Place the initialization code for the Apollo project =apollo.rb= in the file; Place the initialization code for the
22
+ space project =space.rb= in the file.
23
+
18
24
 
19
25
  Then write the following code in the =~/.arql.d/init.eb= file:
20
26
 
21
- #+BEGIN_SRC ruby
22
- ["apollo", "space"].each do |project|
23
- if Arql::App.env.try { |e| e.include?(project + ".") }
24
- load(File.absolute_path(File.dirname(__FILE__) + "/#{project}.rb"))
25
- break
27
+ #+begin_src ruby
28
+ Dir.glob(File.dirname(__FILE__) + '/*.rb').each do |f|
29
+ Arql::App.instance.definitions.each do |env, definition|
30
+ if env.starts_with?(File.basename(f, '.rb'))
31
+ load(f, definition.namespace_module)
32
+ end
26
33
  end
27
34
  end
28
- #+END_SRC
35
+ #+end_src
36
+
37
+
38
+ In this way, =arql -e apollo.prod= when or is executed, the initialization =apollo.rb= code in the file is loaded, and
39
+ =arql -e space.prod= when or is executed =arql -e apollo.dev= =arql -e space.dev= , the initialization code in the file
40
+ is loaded =space.rb= .
41
+
29
42
 
30
- Now, when you run =arql -e apollo.dev= or =arql =e apollo.prod=, the initialization code in the =apollo.rb= file will be loaded; when you run =arql -e space.dev= or =arql -e space.prod=, the initialization code in the =space.rb= file will be loaded.
31
-
43
+ =apollo.rb= The code in the =space.rb= or file will be executed under the corresponding Namespace Module:
44
+
45
+ #+begin_src ruby
46
+ class Astronaut
47
+ has_many :missions
48
+ end
49
+ #+end_src
50
+
51
+ Equivalent to:
52
+
53
+ #+begin_src ruby
54
+ module Apollo
55
+ class Astronaut
56
+ has_many :missions
57
+ end
58
+ end
59
+ #+end_src