crudboy 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,10 @@
1
+ module Crudboy
2
+ class Connection
3
+ class << self
4
+ def open(options)
5
+ ActiveRecord::Base.establish_connection(options)
6
+ $C = ActiveRecord::Base.connection
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,123 @@
1
+ require 'crudboy/concerns'
2
+ module Crudboy
3
+ module Extension
4
+ extend ActiveSupport::Concern
5
+
6
+ def t
7
+ puts Terminal::Table.new { |t|
8
+ v.each { |row| t << (row || :separator) }
9
+ }
10
+ end
11
+
12
+ def v
13
+ t = []
14
+ t << ['Attribute Name', 'Attribute Value', 'SQL Type', 'Comment']
15
+ t << nil
16
+ self.class.connection.columns(self.class.table_name).each do |column|
17
+ t << [column.name, read_attribute(column.name), column.sql_type, column.comment || '']
18
+ end
19
+ t
20
+ end
21
+
22
+ def to_insert_sql
23
+ self.class.to_insert_sql([self])
24
+ end
25
+
26
+ def to_upsert_sql
27
+ self.class.to_upsert_sql([self])
28
+ end
29
+
30
+ def write_csv(filename, *fields, **options)
31
+ [self].write_csv(filename, *fields, **options)
32
+ end
33
+
34
+ def write_excel(filename, *fields, **options)
35
+ [self].write_excel(filename, *fields, **options)
36
+ end
37
+
38
+ class_methods do
39
+ def t
40
+ table_name = Commands::Table::get_table_name(name)
41
+ puts "\nTable: #{table_name}"
42
+ puts Commands::Table::table_info_table(table_name)
43
+ end
44
+
45
+ def v
46
+ table_name = Commands::Table::get_table_name(name)
47
+ Commands::Table::table_info(table_name)
48
+ end
49
+
50
+ def to_insert_sql(records, batch_size = 1)
51
+ to_sql(records, :skip, batch_size)
52
+ end
53
+
54
+ def to_upsert_sql(records, batch_size = 1)
55
+ to_sql(records, :update, batch_size)
56
+ end
57
+ end
58
+ end
59
+
60
+ class Definition
61
+
62
+ attr_accessor :table_name, :model, :model_name
63
+
64
+ def initialize(options)
65
+ @@options = options
66
+ @table_name = @@options[:table_name]
67
+ @model_name = @@options[:model_name]
68
+ ActiveRecord::Base.connection.tap do |conn|
69
+ Object.const_set('CrudboyModel', Class.new(ActiveRecord::Base) do
70
+ include ::Crudboy::Concerns::TableDataDefinition
71
+ self.abstract_class = true
72
+ end)
73
+
74
+ raise "Table not exist: #{@table_name}" unless conn.tables.include?(@table_name)
75
+
76
+ table_comment = conn.table_comment(@table_name)
77
+ conn.primary_key(@table_name).tap do |pkey|
78
+ Class.new(::CrudboyModel) do
79
+ include Crudboy::Extension
80
+ self.table_name = options[:table_name]
81
+ if pkey.is_a?(Array)
82
+ self.primary_keys = pkey
83
+ else
84
+ self.primary_key = pkey
85
+ end
86
+ self.inheritance_column = nil
87
+ self.default_timezone = :local
88
+ if options[:created_at].present?
89
+ define_singleton_method :timestamp_attributes_for_create do
90
+ options[:created_at]
91
+ end
92
+ end
93
+
94
+ if options[:updated_at].present?
95
+ define_singleton_method :timestamp_attributes_for_update do
96
+ options[:updated_at]
97
+ end
98
+ end
99
+ end.tap do |clazz|
100
+ Object.const_set(@model_name, clazz).tap do |const|
101
+ @model = Model.new(const, @table_name, table_comment)
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
107
+
108
+ ::ActiveRecord::Relation.class_eval do
109
+ def t(*attrs, **options)
110
+ records.t(*attrs, **options)
111
+ end
112
+
113
+ def v
114
+ records.v
115
+ end
116
+
117
+ def a
118
+ to_a
119
+ end
120
+
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,5 @@
1
+ require 'crudboy/ext/object'
2
+ require 'crudboy/ext/array'
3
+ require 'crudboy/ext/time'
4
+ require 'crudboy/ext/string'
5
+ require 'crudboy/ext/kernel'
@@ -0,0 +1,139 @@
1
+ class Array
2
+ def to_insert_sql(batch_size=500)
3
+ raise 'All element should be an ActiveRecord instance object' unless all? { |e| e.is_a?(ActiveRecord::Base) }
4
+ group_by(&:class).map do |(klass, records)|
5
+ klass.to_insert_sql(records, batch_size)
6
+ end.join("\n")
7
+ end
8
+
9
+ def to_upsert_sql(batch_size=500)
10
+ raise 'All element should be an ActiveRecord instance object' unless all? { |e| e.is_a?(ActiveRecord::Base) }
11
+ group_by(&:class).map do |(klass, records)|
12
+ klass.to_upsert_sql(records, batch_size)
13
+ end.join("\n")
14
+ end
15
+
16
+ def t(*attrs, **options)
17
+ if (attrs.present? || options.present? && options[:except]) && present? && first.is_a?(ActiveRecord::Base)
18
+ column_names = first.attribute_names.map(&:to_sym)
19
+ attrs = attrs.flat_map { |e| e.is_a?(Regexp) ? column_names.grep(e) : e }.uniq
20
+ if options.present? && options[:except]
21
+ attrs = column_names if attrs.empty?
22
+ if options[:except].is_a?(Regexp)
23
+ attrs.reject! { |e| e =~ options[:except] }
24
+ else
25
+ attrs -= [options[:except]].flatten
26
+ end
27
+ end
28
+ puts Terminal::Table.new { |t|
29
+ t << attrs
30
+ t << :separator
31
+ each do |e|
32
+ t << e.attributes.values_at(*attrs.map(&:to_s))
33
+ end
34
+ }
35
+ else
36
+ table = Terminal::Table.new { |t|
37
+ v.each { |row| t << (row || :separator)}
38
+ }.to_s
39
+
40
+ terminal_width = `tput cols`.to_i
41
+ if table.lines.first.size > terminal_width
42
+ table = table.lines.map(&:chomp)
43
+ puts table[0..2].join("\n")
44
+ puts table[3..-1].join("\n#{'-' * terminal_width}\n")
45
+ else
46
+ puts table
47
+ end
48
+ end
49
+ end
50
+
51
+ def v
52
+ return self unless present?
53
+ t = []
54
+ if map(&:class).uniq.size == 1
55
+ if first.is_a?(ActiveRecord::Base)
56
+ t << first.attribute_names
57
+ t << nil
58
+ each do |e|
59
+ t << e.attributes.values_at(*first.attribute_names).map(&:as_json)
60
+ end
61
+ elsif first.is_a?(Array)
62
+ t = map { |a| a.map(&:as_json) }
63
+ elsif first.is_a?(Hash) || first.is_a?(ActiveSupport::HashWithIndifferentAccess)
64
+ t << first.keys
65
+ t << nil
66
+ each do |e|
67
+ t << e.values_at(*first.keys).map(&:as_json)
68
+ end
69
+ else
70
+ return self
71
+ end
72
+ end
73
+ t
74
+ end
75
+
76
+ def write_csv(filename, *fields, **options)
77
+ generate_csv(filename, **options) do |csv|
78
+ if size > 0 && first.is_a?(ActiveRecord::Base)
79
+ if fields.empty?
80
+ fields = first.attributes.keys
81
+ else
82
+ fields = fields.map(&:to_s)
83
+ end
84
+ csv << fields
85
+ end
86
+ if size > 0 && first.is_a?(Hash)
87
+ if fields.empty?
88
+ fields = first.keys
89
+ end
90
+ csv << fields
91
+ end
92
+ each do |row|
93
+ if row.is_a?(Array)
94
+ csv << row.map(&:to_s)
95
+ else
96
+ csv << row.slice(*fields).values.map(&:to_s)
97
+ end
98
+ end
99
+ end
100
+ end
101
+
102
+ def write_excel(filename, *fields, **options)
103
+ sheet_name = options[:sheet_name] || 'Sheet1'
104
+ generate_excel(filename) do |workbook|
105
+ workbook.add_worksheet(name: sheet_name) do |sheet|
106
+ if size > 0 && first.is_a?(ActiveRecord::Base)
107
+ if fields.empty?
108
+ fields = first.attributes.keys
109
+ else
110
+ fields = fields.map(&:to_s)
111
+ end
112
+ sheet.add_row(fields, types: [:string] * fields.size)
113
+ end
114
+ if size > 0 && first.is_a?(Hash)
115
+ if fields.empty?
116
+ fields = first.keys
117
+ end
118
+ sheet.add_row(fields, types: [:string] * fields.size)
119
+ end
120
+ each do |row|
121
+ if row.is_a?(Array)
122
+ sheet.add_row(row.map(&:to_s), types: [:string] * row.size)
123
+ else
124
+ sheet.add_row(row.slice(*fields).values.map(&:to_s), types: [:string] * fields.size)
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
130
+
131
+ def dump(filename, batch_size=500)
132
+ File.open(File.expand_path(filename), 'w') do |file|
133
+ group_by(&:class).each do |(klass, records)|
134
+ file.puts(klass.to_upsert_sql(records, batch_size))
135
+ end
136
+ end
137
+ {size: size, file: File.expand_path(filename)}
138
+ end
139
+ end
@@ -0,0 +1,41 @@
1
+ class Hash
2
+ def write_excel(filename)
3
+ generate_excel(filename) do |workbook|
4
+ each do |sheet_name, sheet_data|
5
+ workbook.add_worksheet(name: sheet_name) do |sheet|
6
+ if sheet_data.is_a?(Hash)
7
+ fields = sheet_data[:fields].map(&:to_s)
8
+ sheet.add_row(fields, types: [:string] * fields.size)
9
+ sheet_data[:data].each do |row|
10
+ sheet.add_row(row.slice(*fields).values.map(&:to_s), types: [:string] * fields.size)
11
+ end
12
+ end
13
+
14
+ if sheet_data.is_a?(Array)
15
+ if sheet_data.size > 0 && sheet_data.first.is_a?(ActiveModel::Base)
16
+ fields = sheet_data.first.attributes.keys
17
+ sheet.add_row(fields, types: [:string] * fields.size)
18
+ sheet_data.each do |row|
19
+ sheet.add_row(row.slice(*fields).values.map(&:to_s), types: [:string] * fields.size)
20
+ end
21
+ end
22
+
23
+ if sheet_data.size > 0 && sheet_data.first.is_a?(Hash)
24
+ fields = sheet_data.first.keys
25
+ sheet.add_row(fields, types: [:string] * fields.size)
26
+ sheet_data.each do |row|
27
+ sheet.add_row(row.slice(*fields).values.map(&:to_s), types: [:string] * fields.size)
28
+ end
29
+ end
30
+
31
+ if sheet_data.size > 0 && sheet_data.first.is_a?(Array)
32
+ sheet_data.each do |row|
33
+ sheet.add_row(row.map(&:to_s), types: [:string] * fields.size)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,112 @@
1
+ require 'crudboy/concerns'
2
+ module Kernel
3
+ CSV_BOM = "\xef\xbb\xbf"
4
+
5
+ include ::Crudboy::Concerns::GlobalDataDefinition
6
+
7
+ def sql(sql)
8
+ ActiveRecord::Base.connection.exec_query(sql)
9
+ end
10
+
11
+ def print_tables(format = :md)
12
+ require 'terminal-table'
13
+
14
+ tables = ActiveRecord::Base.connection.tables.map do |table_name|
15
+ {
16
+ table: table_name,
17
+ table_comment: ActiveRecord::Base.connection.table_comment(table_name) || '',
18
+ columns: ::ActiveRecord::Base.connection.columns(table_name)
19
+ }
20
+ end
21
+
22
+ outputs = tables.map do |table|
23
+ table_name = table[:table]
24
+ table_comment = table[:table_comment]
25
+ case format
26
+ when :md
27
+ "# #{table_name} #{table_comment}\n\n" +
28
+ Terminal::Table.new { |t|
29
+ t.headings = ['PK', 'Name', 'SQL Type', 'Limit', 'Precision', 'Scale', 'Default', 'Nullable', 'Comment']
30
+ t.rows = table[:columns].map { |column|
31
+ pk = if [::ActiveRecord::Base.connection.primary_key(table_name)].flatten.include?(column)
32
+ 'Y'
33
+ else
34
+ ''
35
+ end
36
+ [pk, "`#{column.name}`", column.sql_type, column.sql_type_metadata.limit || '', column.sql_type_metadata.precision || '',
37
+ column.sql_type_metadata.scale || '', column.default || '', column.null, column.comment || '']
38
+ }
39
+ t.style = {
40
+ border_top: false,
41
+ border_bottom: false,
42
+ border_i: '|'
43
+ }
44
+ }.to_s.lines.map { |l| ' ' + l }.join
45
+ when :org
46
+ "* #{table_name} #{table_comment}\n\n" +
47
+ Terminal::Table.new { |t|
48
+ t.headings = ['PK', 'Name', 'SQL Type', 'Limit', 'Precision', 'Scale', 'Default', 'Nullable', 'Comment']
49
+ t.rows = table[:columns].map { |column|
50
+ pk = if [::ActiveRecord::Base.connection.primary_key(table_name)].flatten.include?(column)
51
+ 'Y'
52
+ else
53
+ ''
54
+ end
55
+ [pk, "=#{column.name}=", column.sql_type, column.sql_type_metadata.limit || '', column.sql_type_metadata.precision || '',
56
+ column.sql_type_metadata.scale || '', column.default || '', column.null, column.comment || '']
57
+ }
58
+ t.style = {
59
+ border_top: false,
60
+ border_bottom: false,
61
+ }
62
+ }.to_s.lines.map { |l| ' ' + l.gsub(/^\+|\+$/, '|') }.join
63
+ when :sql
64
+ "-- Table: #{table_name}\n\n" + ActiveRecord::Base.connection.exec_query("show create table `#{table_name}`").rows.last.last + ';'
65
+ end
66
+ end
67
+
68
+ outputs.each { |out| puts out; puts }
69
+ end
70
+
71
+ def generate_csv(filename, **options, &block)
72
+ opts = {
73
+ col_sep: "\t",
74
+ row_sep: "\r\n"
75
+ }
76
+ opts.merge!(options.except(:encoding))
77
+ encoding = options[:encoding] || 'UTF-16LE'
78
+ File.open(File.expand_path(filename), "w:#{encoding}") do |file|
79
+ file.write(CSV_BOM)
80
+ file.write CSV.generate(**opts, &block)
81
+ end
82
+ end
83
+
84
+ def parse_csv(filename, **options)
85
+ encoding = options[:encoding] || 'UTF-16'
86
+ opts = {
87
+ headers: false,
88
+ col_sep: "\t",
89
+ row_sep: "\r\n"
90
+ }
91
+ opts.merge!(options.except(:encoding))
92
+ CSV.parse(IO.read(File.expand_path(filename), encoding: encoding, binmode: true).encode('UTF-8'), **opts).to_a
93
+ end
94
+
95
+ def generate_excel(filename)
96
+ Axlsx::Package.new do |package|
97
+ yield(package.workbook)
98
+ package.serialize(File.expand_path(filename))
99
+ end
100
+ end
101
+
102
+ def parse_excel(filename)
103
+ xlsx = Roo::Excelx.new(File.expand_path(filename))
104
+ xlsx.sheets.each_with_object({}) do |sheet_name, result|
105
+ begin
106
+ result[sheet_name] = xlsx.sheet(sheet_name).to_a
107
+ rescue
108
+ end
109
+ end
110
+ end
111
+
112
+ end
@@ -0,0 +1,22 @@
1
+ class Object
2
+
3
+ def j
4
+ to_json
5
+ end
6
+
7
+ def jj
8
+ JSON.pretty_generate(JSON.parse(to_json))
9
+ end
10
+
11
+ def jp
12
+ puts j
13
+ end
14
+
15
+ def jjp
16
+ puts jj
17
+ end
18
+
19
+ def a
20
+ [self]
21
+ end
22
+ end