database-core 0.1.0

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.
@@ -0,0 +1,121 @@
1
+ module Database::V2
2
+
3
+ class Query
4
+
5
+ def self.build table, query
6
+
7
+ output = []
8
+
9
+ build_select output, query
10
+
11
+ output << "FROM `#{table}`"
12
+
13
+ build_where output, query
14
+ build_order output, query
15
+ build_limit output, query
16
+ build_offset output, query
17
+
18
+ output.join " "
19
+ end
20
+
21
+ def self.build_select output, query
22
+
23
+ columns = []
24
+
25
+ build_keys columns, query
26
+
27
+ unless query["columns"].nil?
28
+ columns.concat query["columns"]
29
+ end
30
+
31
+ if columns.empty?
32
+ output << "SELECT *"
33
+ end
34
+
35
+ unless columns.empty?
36
+ columns.map!{ |column| "`#{column}`" }
37
+ output << "SELECT #{columns.join ","}"
38
+ end
39
+ end
40
+
41
+ def self.build_where output, query
42
+
43
+ where_rules = []
44
+
45
+ unless query["where_and"].nil?
46
+ where_rules << Wherer.build(query["where_and"]).join(" AND ")
47
+ end
48
+
49
+ unless query["where_or"].nil?
50
+ where_rules << Wherer.build(query["where_and"]).join(" OR ")
51
+ end
52
+
53
+ unless where_rules.empty?
54
+ output << "WHERE #{where_rules.join(" AND ")}"
55
+ end
56
+ end
57
+
58
+ def self.build_order output, query
59
+
60
+ order = []
61
+
62
+ unless query["order"].nil?
63
+ query["order"].each do |key, value|
64
+ order << "`#{key}` #{value}"
65
+ end
66
+ end
67
+
68
+ unless order.empty?
69
+ order = order.join ","
70
+ output << "ORDER BY #{order}"
71
+ end
72
+ end
73
+
74
+ def self.build_limit output, query
75
+
76
+ unless query["limit"].nil?
77
+ output << "LIMIT #{query["limit"]}"
78
+ end
79
+ end
80
+
81
+ def self.build_offset output, query
82
+
83
+ unless query["offset"].nil?
84
+ output << "OFFSET #{query["offset"]}"
85
+ end
86
+ end
87
+
88
+ def self.build_keys output, query
89
+
90
+ unless query["has_one_key"].nil?
91
+ unless output.include? "id"
92
+ output << "id"
93
+ end
94
+ end
95
+
96
+ unless query["has_many"].nil?
97
+ unless output.include? "id"
98
+ output << "id"
99
+ end
100
+ end
101
+
102
+ unless query["has_many_key"].nil?
103
+ unless output.include? query["has_many_key"]
104
+ output << query["has_many_key"]
105
+ end
106
+ end
107
+
108
+ unless query["has_one"].nil?
109
+ query["has_one"].each do |table, query|
110
+ unless query["has_one_key"].nil?
111
+ unless output.include? query["has_one_key"]
112
+ output << query["has_one_key"]
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
118
+
119
+ end
120
+
121
+ end
@@ -0,0 +1,100 @@
1
+ module Database::V2
2
+
3
+ class QueryRunner
4
+
5
+ def self.query models_query
6
+
7
+ models_values = {}
8
+
9
+ models_query.each do |model, query|
10
+
11
+ sql = Query.build(model, query)
12
+
13
+ values = ActiveRecord::Base.connection.exec_query(sql).map(&:as_json)
14
+
15
+ if values.present?
16
+
17
+ setup_relation values, query["has_one"], true
18
+ setup_relation values, query["has_many"], false
19
+ end
20
+
21
+ models_values[model] = values
22
+ end
23
+
24
+ serialize(models_values)
25
+ end
26
+
27
+ def self.setup_relation parents, models_query, relation
28
+
29
+ return unless models_query.present?
30
+
31
+ setup_relation_query(parents, models_query, relation)
32
+ setup_relation_value(parents, models_query, relation)
33
+ end
34
+
35
+ def self.setup_relation_query parents, models_query, relation
36
+
37
+ models_query.each do |model, query|
38
+
39
+ next if query["has_one_key"].nil? && relation == true
40
+ next if query["has_many_key"].nil? && relation == false
41
+
42
+ foreign_key = relation ? "id" : query["has_many_key"]
43
+ primary_key = relation ? query["has_one_key"] : "id"
44
+
45
+ keys = parents.map{ |parent| parent[primary_key] }.uniq.compact
46
+
47
+ next if keys.empty?
48
+
49
+ query["in_value"] = {} if query["in_value"].nil?
50
+
51
+ if query["in_value"][foreign_key]
52
+ query["in_value"][foreign_key] << keys
53
+ query["in_value"][foreign_key].flatten
54
+ else
55
+ query["in_value"][foreign_key] = keys
56
+ end
57
+ end
58
+ end
59
+
60
+ def self.setup_relation_value parents, models_query, relation
61
+
62
+ models_values = query(models_query)
63
+
64
+ parents.each do |parent|
65
+
66
+ models_query.each do |model, query|
67
+
68
+ next if query["has_one_key"].nil? && relation == true
69
+ next if query["has_many_key"].nil? && relation == false
70
+
71
+ foreign_key = relation ? "id" : query["has_many_key"]
72
+ primary_key = relation ? query["has_one_key"] : "id"
73
+
74
+ values = models_values[model].select{ |value| value[foreign_key] == parent[primary_key] }
75
+
76
+ parent[model] = relation ? values.first : values
77
+ end
78
+ end
79
+ end
80
+
81
+ def self.serialize(target)
82
+
83
+ case target
84
+ when Integer
85
+ target > 2**32 ? target.to_s : target
86
+ when String
87
+ encodings = [Encoding::US_ASCII, Encoding::UTF_8]
88
+ encodings.include?(target.encoding) ? target : target.bytes.to_a
89
+ when Array
90
+ target.map { |value| serialize(value) }
91
+ when Hash
92
+ target.transform_values { |value| serialize(value) }
93
+ else
94
+ target
95
+ end
96
+ end
97
+
98
+ end
99
+
100
+ end
@@ -0,0 +1,62 @@
1
+ module Database::V2
2
+
3
+ class Wherer
4
+
5
+ def self.build query
6
+
7
+ where_rules = []
8
+
9
+ unless query["bigger"].nil?
10
+ query["bigger"].each do |key, value|
11
+ where_rules << "`#{key}` = #{value}"
12
+ end
13
+ end
14
+
15
+ unless query["smaller"].nil?
16
+ query["smaller"].each do |key, value|
17
+ where_rules << "`#{key}` = #{value}"
18
+ end
19
+ end
20
+
21
+ unless query["different"].nil?
22
+ query["different"].each do |key, value|
23
+ where_rules << "`#{key}` = #{value}"
24
+ end
25
+ end
26
+
27
+ unless query["equal"].nil?
28
+ query["equal"].each do |key, value|
29
+ where_rules << "`#{key}` = #{value}"
30
+ end
31
+ end
32
+
33
+ unless query["in_query"].nil?
34
+ query["in_query"].each do |key, value|
35
+ value.each do |table, query|
36
+ query = Query.build table, query
37
+ where_rules << "`#{key}` IN (#{query})"
38
+ end
39
+ end
40
+ end
41
+
42
+ unless query["in_value"].nil?
43
+ query["in_value"].each do |key, value|
44
+ unless value.empty?
45
+ value = value.join ","
46
+ where_rules << "`#{key}` IN (#{value})"
47
+ end
48
+ end
49
+ end
50
+
51
+ unless query["like"].nil?
52
+ query["like"].each do |key, value|
53
+ where_rules << "`#{key}` LIKE '#{value}'"
54
+ end
55
+ end
56
+
57
+ where_rules
58
+ end
59
+
60
+ end
61
+
62
+ end
@@ -0,0 +1,18 @@
1
+ module Database::V3
2
+
3
+ class DeleteModel
4
+
5
+ def self.build model, params
6
+
7
+ model = Sanitize.target(model)
8
+
9
+ output = ["DELETE FROM `#{model}`"]
10
+
11
+ WhereModel.build(output, params)
12
+
13
+ output.join(" ")
14
+ end
15
+
16
+ end
17
+
18
+ end
@@ -0,0 +1,20 @@
1
+ module Database::V3
2
+
3
+ class DeleteRunner
4
+
5
+ def self.delete input
6
+
7
+ input.each do |model, payload|
8
+
9
+ Array.wrap(payload).each do |item|
10
+
11
+ sql = DeleteModel.build(model, item)
12
+
13
+ ActiveRecord::Base.connection.execute(sql)
14
+ end
15
+ end
16
+ end
17
+
18
+ end
19
+
20
+ end
@@ -0,0 +1,33 @@
1
+ module Database::V3
2
+
3
+ class InsertModel
4
+
5
+ def self.build model, params
6
+
7
+ model = Sanitize.target(model)
8
+
9
+ datetime = Time.current.utc.strftime("%Y-%m-%d %H:%M:%S")
10
+
11
+ params["columns"]["created_at"] = datetime
12
+ params["columns"]["updated_at"] = datetime
13
+
14
+ columns = build_columns(params).join(", ")
15
+
16
+ values = build_values(params).join(", ")
17
+
18
+ "INSERT INTO `#{model}` (#{columns}) VALUES (#{values})"
19
+ end
20
+
21
+ def self.build_columns params
22
+
23
+ params["columns"].keys.map{ |column| "`#{Sanitize.target(column)}`" }
24
+ end
25
+
26
+ def self.build_values params
27
+
28
+ params["columns"].values.map{ |value| Sanitize.array(["?", value]) }
29
+ end
30
+
31
+ end
32
+
33
+ end
@@ -0,0 +1,20 @@
1
+ module Database::V3
2
+
3
+ class InsertRunner
4
+
5
+ def self.insert input
6
+
7
+ input.each do |model, payload|
8
+
9
+ Array.wrap(payload).each do |item|
10
+
11
+ sql = InsertModel.build(model, item)
12
+
13
+ ActiveRecord::Base.connection.execute(sql)
14
+ end
15
+ end
16
+ end
17
+
18
+ end
19
+
20
+ end
@@ -0,0 +1,29 @@
1
+ module Database::V3
2
+
3
+ class PolicyModel
4
+
5
+ def initialize permissions, overrides
6
+
7
+ @permissions = permissions
8
+
9
+ @overrides = overrides
10
+ end
11
+
12
+ def permit? model, params, permission
13
+
14
+ override = @overrides.dig(model)
15
+
16
+ return @permissions.dig(permission) unless override
17
+
18
+ params_columns = params.dig("columns").to_a
19
+
20
+ override_columns = override.dig("columns").to_a
21
+
22
+ return @permissions.dig(permission) unless (params_columns - override_columns).empty?
23
+
24
+ override.dig("permissions", permission)
25
+ end
26
+
27
+ end
28
+
29
+ end
@@ -0,0 +1,23 @@
1
+ module Database::V3
2
+
3
+ class PolicyRunner
4
+
5
+ def initialize permissions, overrides
6
+
7
+ @policy_model = PolicyModel.new(permissions, overrides)
8
+ end
9
+
10
+ def permit? input, permission
11
+
12
+ input.all? do |model, payload|
13
+
14
+ Array.wrap(payload).all? do |item|
15
+
16
+ @policy_model.permit?(model, item, permission)
17
+ end
18
+ end
19
+ end
20
+
21
+ end
22
+
23
+ end
@@ -0,0 +1,126 @@
1
+ module Database::V3
2
+
3
+ class QueryModel
4
+
5
+ def self.build model, query
6
+
7
+ model = Sanitize.target(model)
8
+
9
+ columns = build_columns(query)
10
+
11
+ output = ["SELECT #{columns} FROM `#{model}`"]
12
+
13
+ WhereModel.build(output, query)
14
+
15
+ build_order(output, query)
16
+ build_limit(output, query)
17
+ build_offset(output, query)
18
+
19
+ output.join(" ")
20
+ end
21
+
22
+ def self.build_count model, query
23
+
24
+ model = Sanitize.target(model)
25
+
26
+ output = ["SELECT COUNT(id) AS `#{model}` FROM `#{model}`"]
27
+
28
+ WhereModel.build(output, query)
29
+
30
+ output.join(" ")
31
+ end
32
+
33
+ def self.build_children model, query
34
+
35
+ children = query["children"]
36
+
37
+ return unless children.present?
38
+
39
+ children.each do |_model, value|
40
+
41
+ value["key"] = "#{model.singularize}_id" if value["key"].nil?
42
+
43
+ value["keys"] = [] if value["keys"].nil?
44
+
45
+ value["keys"] << value["key"] unless value["keys"].include? value["key"]
46
+ end
47
+
48
+ query["keys"] = [] if query["keys"].nil?
49
+
50
+ query["keys"] << "id" unless query["keys"].include? "id"
51
+ end
52
+
53
+ def self.build_parents _model, query
54
+
55
+ parents = query["parents"]
56
+
57
+ return unless parents.present?
58
+
59
+ parents.each do |model, value|
60
+
61
+ value["key"] = "#{model.singularize}_id" if value["key"].nil?
62
+
63
+ query["keys"] = [] if query["keys"].nil?
64
+
65
+ query["keys"] << value["key"] unless query["keys"].include? value["key"]
66
+
67
+ value["keys"] = [] if value["keys"].nil?
68
+
69
+ value["keys"] << "id" unless value["keys"].include? "id"
70
+ end
71
+ end
72
+
73
+ def self.build_columns query
74
+
75
+ columns = query["columns"].to_a + query["keys"].to_a
76
+
77
+ columns = columns.uniq.map{ |column| column.is_a?(Hash) ? build_function(column) : "`#{column}`" }.join(",")
78
+
79
+ columns.present? ? columns : "*"
80
+ end
81
+
82
+ def self.build_function function
83
+
84
+ function_name = function["function"].upcase
85
+
86
+ params = function["params"].map{ |param| param.is_a?(Hash) ? build_function(param) : "`#{param}`" }.join(", ")
87
+
88
+ function_call = "#{function_name}(#{params})"
89
+
90
+ function["alias"] ? "#{function_call} AS `#{function['alias']}`" : function_call
91
+ end
92
+
93
+ def self.build_order output, query
94
+
95
+ order = query["order"]
96
+
97
+ return unless order.present?
98
+
99
+ order = order.map{ |key, value| "`#{key}` #{value}" }.join(",")
100
+
101
+ return unless order.present?
102
+
103
+ output << "ORDER BY #{order}"
104
+ end
105
+
106
+ def self.build_limit output, query
107
+
108
+ limit = query["limit"].to_i
109
+
110
+ return if limit.zero?
111
+
112
+ output << "LIMIT #{limit}"
113
+ end
114
+
115
+ def self.build_offset output, query
116
+
117
+ offset = query["offset"].to_i
118
+
119
+ return if offset.zero?
120
+
121
+ output << "OFFSET #{offset}"
122
+ end
123
+
124
+ end
125
+
126
+ end