Module: PgColumnBytePacker::PgDump
- Defined in:
- lib/pg_column_byte_packer/pg_dump.rb
Class Method Summary collapse
- ._sort_table_lines(connection:, qualified_table:, lines:) ⇒ Object
- .sort_columns_for_definition_file(path, connection:) ⇒ Object
Class Method Details
._sort_table_lines(connection:, qualified_table:, lines:) ⇒ Object
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/pg_column_byte_packer/pg_dump.rb', line 52 def self._sort_table_lines(connection:, qualified_table:, lines:) schema, table = qualified_table.match(/([^\.]+)\.([^\.]+)/)[1..-1] lines.sort_by do |line| line = line.chomp # To handle the vagaries of quoted keywords as column names # and spaces/special characters in column names, we resort # to using PostgreSQL's parsing code itself on a faked # CREATE TABLE call with a single column; we could parse # the entire CREATE TABLE statement we have in the file, # but then we'd have to figure out a way to recreate that # query from the parse tree, and therein lies madness. line_without_comma = line[-1] == "," ? line[0..-2] : line fake_query = "CREATE TABLE t(#{line_without_comma});" parsed = begin PgQuery.parse(fake_query) rescue PgQuery::ParseError nil end # Ignore CONSTRAINT definitions etc. if parsed && (column_def = parsed.tree[0]["RawStmt"]["stmt"]["CreateStmt"]["tableElts"][0]["ColumnDef"]) column = column_def["colname"] values = connection.select_rows(<<~SQL, "Column and Type Info").first SELECT pg_catalog.format_type(attr.atttypid, attr.atttypmod), typ_nsp.nspname, attr.attnotnull, attr.atthasdef, EXISTS ( SELECT 1 FROM pg_index idx WHERE idx.indisprimary AND attr.attnum = ANY(idx.indkey) AND idx.indrelid = attr.attrelid ) FROM pg_catalog.pg_attribute attr JOIN pg_catalog.pg_type typ ON typ.oid = attr.atttypid JOIN pg_catalog.pg_class cls ON cls.oid = attr.attrelid JOIN pg_catalog.pg_namespace attr_nsp ON attr_nsp.oid = cls.relnamespace JOIN pg_catalog.pg_namespace typ_nsp ON typ_nsp.oid = typ.typnamespace WHERE attr.attname = '#{connection.quote_string(column)}' AND attr_nsp.nspname = '#{connection.quote_string(schema)}' AND cls.relname = '#{connection.quote_string(table)}' AND NOT attr.attisdropped SQL sql_type, type_schema, not_null, has_default, primary_key = values PgColumnBytePacker.ordering_key_for_column( connection: connection, name: column, sql_type: sql_type, type_schema: type_schema, primary_key: primary_key, nullable: !not_null, has_default: has_default ) else # All non-column lines we want to sort at the end # of the table defintion statement. [2**32] end end end |
.sort_columns_for_definition_file(path, connection:) ⇒ Object
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/pg_column_byte_packer/pg_dump.rb', line 3 def self.sort_columns_for_definition_file(path, connection:) sorted_dump_output = [] current_block_start = nil current_block_body = [] current_table_name = nil block_begin_prefix_pattern = /\ACREATE TABLE ([^\(]+) \(/ block_end_line_pattern = /\A\);?\n\Z/ File.foreach(path) do |line| if current_block_start.nil? && (create_table_match = block_begin_prefix_pattern.match(line)) current_block_start = line current_block_body = [] current_table_name = create_table_match[1] elsif current_block_start if line =~ block_end_line_pattern sorted_dump_output << current_block_start table_lines = _sort_table_lines( connection: connection, qualified_table: current_table_name, lines: current_block_body ) table_lines = table_lines.map.with_index do |column_line, index| has_trailing_comma = column_line =~ /,\s*\Z/ last_line = index == table_lines.size - 1 if !last_line && !has_trailing_comma column_line.sub(/(.+)(\s*)\Z/, '\1,\2') elsif last_line && has_trailing_comma column_line.sub(/,(\s*)\Z/, '\1') else column_line end end sorted_dump_output.concat(table_lines) sorted_dump_output << line current_block_body = [] current_block_start = nil current_table_name = nil else current_block_body << line end else sorted_dump_output << line end end File.write(path, sorted_dump_output.join) end |