Class: RailsAiBridge::Introspectors::Schema::StaticStructureSqlParser
- Inherits:
-
Object
- Object
- RailsAiBridge::Introspectors::Schema::StaticStructureSqlParser
- Defined in:
- lib/rails_ai_bridge/introspectors/schema/static_structure_sql_parser.rb
Overview
Parses a db/structure.sql file as plain text, without a live database
connection. This is the schema_format = :sql counterpart to
StaticSchemaParser: apps that keep their schema as SQL (common on
Postgres, where schema.rb cannot represent partitions, views,
extensions, or custom SQL) have no db/schema.rb to fall back to in
offline environments (CI, Claude Code, agent contexts).
Each instance is single-use: construct it with the file content and a configuration object, call #call, and discard. No mutable state escapes the instance.
Supported DDL (pg_dump / structure.sql form)
CREATE TABLE [IF NOT EXISTS] [schema.]name (— opens a table context<name> <type> ...— a column line inside the table body; the leading identifier is the column and the remainder (minus +NOT NULL+/+DEFAULT+) is the SQL type. Table-level constraint lines (+CONSTRAINT+,PRIMARY KEY,FOREIGN KEY, …) are skipped.);— closes the current table contextCREATE [UNIQUE] INDEX name ON [schema.]table USING method (cols)— adds an index entry (first simple column) to the named table. Functional/expression indexes (e.g.lower(email)) are skipped.- +ALTER TABLE [ONLY] table ADD CONSTRAINT ... FOREIGN KEY (col)
REFERENCES ref_table (pk)+ — adds a foreign-key entry to
table(pg_dump emits these in a separate constraints section).
Unlike StaticSchemaParser (whose schema.rb static form leaves foreign
keys empty), structure.sql spells foreign keys out as parseable DDL, so
this parser populates them offline — matching what the live
RailsAiBridge::Introspectors::SchemaIntrospector path reports.
Internal Rails tables (+ar_internal_metadata+, schema_migrations) and
any table matching Config::Introspection#excluded_tables are silently
skipped.
Constant Summary collapse
- TABLE_LINE =
Regex matching a
CREATE TABLEdeclaration, toleratingIF NOT EXISTS, a schema qualifier (+public.+), and optional quoting of either part. /\ACREATE TABLE (?:IF NOT EXISTS\s+)?(?:[\w"]+\.)?"?([A-Za-z_]\w*)"?\s*\(/- TABLE_END_LINE =
Regex matching the end of a table body (+);+ at column zero).
/\A\)/- COLUMN_LINE =
Regex matching a column definition inside a table body: leading whitespace, an identifier (optionally quoted), then the type/modifiers.
/\A\s+"?([A-Za-z_]\w*)"?\s+(.+)/- INDEX_LINE =
Regex matching a
CREATE INDEXstatement. Captures the target table and the raw parenthesised column list; only the first column is kept (parity with RailsAiBridge::Introspectors::Schema::StaticSchemaParser). /\ACREATE\s+(?:UNIQUE\s+)?INDEX\s+.+?\s+ON\s+(?:[\w"]+\.)?"?([A-Za-z_]\w*)"?\s+(?:USING\s+\w+\s+)?\(([^)]+)\)/- ALTER_TABLE_LINE =
Regex matching an
ALTER TABLE [ONLY] [schema.]tablestatement, which in pg_dump precedes anADD CONSTRAINTline. Captures the target table. /\AALTER TABLE (?:ONLY\s+)?(?:[\w"]+\.)?"?([A-Za-z_]\w*)"?/- FOREIGN_KEY_LINE =
Regex matching an +ADD CONSTRAINT ... FOREIGN KEY (cols) REFERENCES [schema.]ref_table (pk)+ clause. Captures local columns, referenced table, and referenced columns.
/FOREIGN KEY\s*\(([^)]+)\)\s*REFERENCES\s+(?:[\w"]+\.)?"?([A-Za-z_]\w*)"?\s*\(([^)]+)\)/- ON_DELETE =
Regex matching an
ON DELETE <action>clause on a foreign-key line. /ON DELETE ([A-Z ]+?)(?=\s+ON UPDATE|\s+(?:NOT\s+)?(?:DEFERRABLE|VALID)|[,;)]|\z)/i- ON_UPDATE =
Regex matching an
ON UPDATE <action>clause on a foreign-key line. /ON UPDATE ([A-Z ]+?)(?=\s+(?:NOT\s+)?(?:DEFERRABLE|VALID)|[,;)]|\z)/i- INTERNAL_TABLES =
Rails-managed tables that must never appear in introspection output.
%w[ar_internal_metadata schema_migrations].freeze
- CONSTRAINT_KEYWORDS =
Table-level constraint keywords that share a column line's shape but are not columns.
%w[CONSTRAINT PRIMARY FOREIGN UNIQUE CHECK EXCLUDE LIKE DEFERRABLE].freeze
Instance Method Summary collapse
-
#call ⇒ Hash{Symbol => Object}
Parse the structure.sql content and return the tables hash.
-
#initialize(content:, config:) ⇒ StaticStructureSqlParser
constructor
A new instance of StaticStructureSqlParser.
Constructor Details
#initialize(content:, config:) ⇒ StaticStructureSqlParser
Returns a new instance of StaticStructureSqlParser.
90 91 92 93 94 95 96 97 |
# File 'lib/rails_ai_bridge/introspectors/schema/static_structure_sql_parser.rb', line 90 def initialize(content:, config:) @content = content @config = config @tables = {} @current_table = nil @in_table = false @alter_target = nil end |
Instance Method Details
#call ⇒ Hash{Symbol => Object}
Parse the structure.sql content and return the tables hash. Never raises — malformed or non-UTF-8 input is caught and reported as an error hash, per the introspector contract.
105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/rails_ai_bridge/introspectors/schema/static_structure_sql_parser.rb', line 105 def call @content.each_line { |line| parse_line(line) } { adapter: 'static_parse', tables: @tables, total_tables: @tables.size, note: 'Parsed from db/structure.sql (no DB connection)' } rescue StandardError => error { error: "Failed to parse db/structure.sql: #{error.}" } end |