arql 0.3.31 → 0.4.1
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 +616 -491
- data/README.org +803 -628
- data/auto-set-id-before-save-zh_CN.org +1 -1
- data/auto-set-id-before-save.org +1 -1
- data/custom-configurations-zh_CN.org +40 -3
- data/custom-configurations.org +71 -32
- data/define-associations-zh_CN.org +31 -17
- data/define-associations.org +52 -29
- data/initializer-structure-zh_CN.org +23 -5
- data/initializer-structure.org +46 -18
- data/lib/arql/app.rb +98 -71
- data/lib/arql/cli.rb +37 -15
- data/lib/arql/commands/info.rb +41 -28
- data/lib/arql/commands/models.rb +106 -61
- 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/repl.rb +1 -1
- data/lib/arql/ssh_proxy.rb +25 -22
- data/lib/arql/version.rb +1 -1
- data/lib/arql.rb +11 -7
- data/oss-files-zh_CN.org +2 -2
- data/oss-files.org +2 -2
- data/sql-log-zh_CN.org +8 -3
- data/sql-log.org +8 -3
- metadata +6 -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/auto-set-id-before-save.org
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
* 配置文件中的自定义配置项
|
2
2
|
|
3
|
-
你可以在配置文件 (如默认的 =~/.arql.yaml= / =~/.arql.d/init.yaml= ) 中定义自己的配置项,然后在代码中通过 =
|
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 =
|
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 =
|
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
|
+
|
data/custom-configurations.org
CHANGED
@@ -1,54 +1,93 @@
|
|
1
1
|
* Additional config items in Configuration File
|
2
2
|
|
3
|
-
You can define your own configuration items in
|
4
|
-
=~/.arql.d/init.yaml=), and then get the value of the configuration item in the code
|
5
|
-
=
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
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 =
|
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 =
|
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
|
-
#
|
43
|
+
|
44
|
+
|
45
|
+
# 从数据库查询出数据之后,自动解密 account_no 字段
|
45
46
|
after_find do
|
46
47
|
self.password = decrypt_account_no(self.password)
|
47
48
|
end
|
48
|
-
|
49
|
-
#
|
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
|
-
#+
|
93
|
+
#+end_src
|
@@ -5,26 +5,29 @@
|
|
5
5
|
Initializer 文件是一个 Ruby 文件,因此可以在其中定义关联关系,例如:
|
6
6
|
|
7
7
|
#+BEGIN_SRC ruby
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
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
|
+
|
data/define-associations.org
CHANGED
@@ -1,37 +1,60 @@
|
|
1
|
-
* Define
|
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
|
-
|
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
|
-
|
13
|
-
end
|
8
|
+
The initializer file is a Ruby file, so you can define associations within it, for example:
|
14
9
|
|
15
|
-
|
16
|
-
|
17
|
-
|
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
|
-
|
20
|
-
|
21
|
-
|
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
|
-
|
24
|
-
|
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
|
-
#+
|
27
|
-
|
28
|
-
1.
|
29
|
-
2. =belongs_to=
|
30
|
-
3. =has_and_belongs_to_many=
|
31
|
-
4. =class_name=
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
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
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
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
|
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
|
|
data/initializer-structure.org
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
9
|
+
- apollo.dev
|
10
|
+
- apollo.prod
|
11
|
+
- space.dev
|
12
|
+
- space.prod
|
13
13
|
|
14
|
-
+ apollo.rb
|
15
|
-
+ space.rb
|
16
14
|
|
17
|
-
|
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
|
-
#+
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
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
|
-
#+
|
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
|
-
|
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
|