recursifier 0.1.0 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9377da0704e74c9cff7c6f8b170c2f95601af14e6fc707b1a377137862bb7c12
4
- data.tar.gz: 47da562f93257c3e83c4db12c57ae474954aaebf0f3a12c5e082859617478764
3
+ metadata.gz: 70abf15924be32d252f28bd29f78b0e0b4c6308b28f3372ff9fd9b737bf0850c
4
+ data.tar.gz: ee1fdea7fe022b9b4846a02c02b7abfc33bdaaa6c087f7f1dd7093121acde3b5
5
5
  SHA512:
6
- metadata.gz: 449d00f6335ca6c1f4c8c527eaddc7c60932e95225253dfe25e44f4d88fe150e9c92953537bf88c0789a39712571b5f6438215bac0d31ef02c1dfedaea2734cd
7
- data.tar.gz: f508864e8bee585a63f6f96e4cd2664ccc45f231d5e453f84fb7ffd4d5b02f3aabde5ce356ff07d70f1d91e00cb7665d6ae4088c503536059eebfb95a57096f9
6
+ metadata.gz: 14556fc8c7937797eb709a2bd7185aa8a9d1d3249c87dceb4064c33336f524864f855b78e28918babe9bad2b59e11cc198972fe507df92937223817ca74253f4
7
+ data.tar.gz: 8f5ef9e9065266e2257058584aec8bf80b1d9efe747070ac925415d8a4ccaf9daf675fda1203cc1989111539cdb095dd4fdec204693f050e77d533876cbe1ee6
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Recursifier
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.2"
5
5
  end
data/lib/recursifier.rb CHANGED
@@ -1,28 +1,29 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "recursifier/version"
3
+ require_relative 'recursifier/version'
4
4
 
5
5
  module Recursifier
6
6
  module RecursiveQuery
7
-
8
7
  class InvalidQueryError < StandardError; end
9
8
 
10
9
  def self.fetch_hierarchy(table_name, parent_matching_column, sub_matching_column, start_id, filters = {}, selected_columns = [], max_depth = 10, current_depth = 0)
11
-
12
- # Validate inputs
13
- raise InvalidQueryError, "Table name must be a string" unless table_name.is_a?(String)
14
- raise InvalidQueryError, "Selected columns must be an array of strings" unless selected_columns.is_a?(Array) && selected_columns.all? { |col| col.is_a?(String) }
15
-
10
+
11
+ # Validate inputs
12
+ raise InvalidQueryError, 'Table name must be a string' unless table_name.is_a?(String)
13
+ unless selected_columns.is_a?(Array) && selected_columns.all? { |col| col.is_a?(String) }
14
+ raise InvalidQueryError, 'Selected columns must be an array of strings'
15
+ end
16
+
16
17
  begin
17
18
  # Check if the current depth exceeds the maximum depth limit
18
- if current_depth > max_depth
19
- return { error: "Maximum recursion depth exceeded" }
20
- end
19
+ return { error: 'Maximum recursion depth exceeded' } if current_depth > max_depth
21
20
 
22
21
  # Convert filters hash into SQL conditions
23
22
  filter_conditions = filters.map { |key, value| "#{key} = '#{value}'" }.join(' AND ')
24
23
 
25
24
  # Convert selected_columns array into comma-separated column names
25
+ selected_columns_sub_str = selected_columns.empty? ? 't.*' : selected_columns.map { |col| "t.#{col}" }.join(', ')
26
+
26
27
  selected_columns_str = selected_columns.empty? ? '*' : selected_columns.join(', ')
27
28
 
28
29
  # Constructing the recursive query with additional filters and selected columns
@@ -30,27 +31,101 @@ module Recursifier
30
31
  WITH RECURSIVE hierarchy AS (
31
32
  SELECT #{selected_columns_str}, 1 AS depth FROM #{table_name} WHERE #{parent_matching_column} = #{start_id} #{filter_conditions}
32
33
  UNION ALL
33
- SELECT #{selected_columns_str}, h.depth + 1 FROM #{table_name} t
34
+ SELECT #{selected_columns_sub_str}, h.depth + 1 FROM #{table_name} t
34
35
  JOIN hierarchy h ON t.#{sub_matching_column} = h.#{parent_matching_column} WHERE h.depth < #{max_depth}
35
36
  )
36
37
  SELECT #{selected_columns_str} FROM hierarchy;
37
38
  SQL
38
39
 
39
40
  # Executing the query and return the result
40
- ActiveRecord::Base.connection.execute(query)
41
+ data = ActiveRecord::Base.connection.execute(query)
42
+ HierarchicalData.new(data, parent_matching_column, sub_matching_column)
41
43
 
42
44
  rescue ActiveRecord::StatementInvalid => e
43
- if e.message.include?("statement timeout")
44
- # Handle statement timeout error
45
- error_message = "Statement Timeout: #{e.message}"
46
- else
47
- # Handle other errors
48
- error_message = "Error: #{e.message}"
49
- end
45
+ error_message = if e.message.include?('statement timeout')
46
+ # Handle statement timeout error
47
+ "Statement Timeout: #{e.message}"
48
+ else
49
+ # Handle other errors
50
+ "Error: #{e.message}"
51
+ end
50
52
 
51
53
  # Return the error message as part of the response
52
54
  { error: error_message }
53
55
  end
54
56
  end
57
+
58
+ class HierarchicalData
59
+ attr_reader :data, :parent_matching_column, :sub_matching_column
60
+
61
+ def initialize(data, parent_match, sub_match)
62
+ @data = data
63
+ @parent_match = parent_match
64
+ @sub_match = sub_match
65
+ end
66
+
67
+ def to_visualize
68
+ parsed_data = JSON.parse(@data.to_json)
69
+
70
+ html = <<~HTML
71
+ <!DOCTYPE html>
72
+ <html lang="en">
73
+ <head>
74
+ <meta charset="UTF-8">
75
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
76
+ <title>Hierarchical Data Visualization</title>
77
+ <style>
78
+ .google-visualization-orgchart-node {
79
+ animation: fade-in 0.5s ease-out;
80
+ }
81
+ @keyframes fade-in {
82
+ 0% { opacity: 0; }
83
+ 100% { opacity: 1; }
84
+ }
85
+ .google-visualization-orgchart-node:hover {
86
+ transform: scale(1.1); /* Scale up the node on hover */
87
+ transition: transform 0.3s ease; /* Add smooth transition */
88
+ }
89
+ </style>
90
+
91
+ <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
92
+ <script type="text/javascript">
93
+ google.charts.load('current', {packages: ['orgchart']});
94
+ google.charts.setOnLoadCallback(drawChart);
95
+ function drawChart() {
96
+ var data = new google.visualization.DataTable();
97
+ data.addColumn('string', 'Node');
98
+ data.addColumn('string', 'Parent');
99
+ data.addRows([
100
+ #{generate_rows(parsed_data)}
101
+ ]);
102
+ var chart = new google.visualization.OrgChart(document.getElementById('visualization'));
103
+ chart.draw(data, {allowHtml: true});
104
+ }
105
+ </script>
106
+ </head>
107
+ <body>
108
+ <div id="visualization" style="width: 100%; height: 100%;"></div>
109
+ </body>
110
+ </html>
111
+ HTML
112
+
113
+ html
114
+ end
115
+
116
+ def get_data
117
+ @data
118
+ end
119
+
120
+ private
121
+
122
+ def generate_rows(data)
123
+ rows = ''
124
+ data.each do |row|
125
+ rows += "['ID: #{row[@parent_match.to_s]}', 'ID: #{row[@sub_match.to_s]}'],"
126
+ end
127
+ rows
128
+ end
129
+ end
55
130
  end
56
131
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: recursifier
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jana
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-03-09 00:00:00.000000000 Z
11
+ date: 2024-03-10 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Recursifier is a Ruby gem designed to simplify and optimize recursive
14
14
  querying of hierarchical data in PostgreSQL databases, particularly within Ruby