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
@@ -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