Red.git | lib/Red/Driver/SQLite/ | SchemaReader.rakumod
use Red::SchemaReader;
use Red::Driver::SQLite::SQLiteMaster;
#| An internal class to read SQLite schemes.
unit class Red::Driver::SQLite::SchemaReader;
also does Red::SchemaReader;
method sqlite-master { Red::Driver::SQLite::SQLiteMaster }
#use Grammar::Tracer::Compact;
grammar SQL::CreateTable {
rule TOP { :i <create-table>+ %% ";" }
rule create-table { :i CREATE TABLE <table-name=.name> '(' ~ ')' <column>+ %% [ "," ] }
token name { :i \w+ }
rule type { :i <name>["(" ~ ")" \d+]? }
rule column { :i <column-name=.name> <type> <modifier>? <index-mod>? <auto-increment>? }
rule auto-increment { :i "AUTOINCREMENT" }
proto rule modifier {*}
multi rule modifier:<null> { :i NULL }
multi rule modifier:<not-null> { :i NOT NULL }
proto rule index-mod {*}
multi rule index-mod:<pk> { :i PRIMARY KEY }
multi rule index-mod:<fk> { :i REFERENCES <table-name=.name> '(' ~ ')' <column-name=.name> }
multi rule index-mod:<unique> { :i UNIQUE }
proto rule index {*}
multi rule index:<pk> { :i PRIMARY KEY '(' ~ ')' <column-name=.name>+ % "," }
multi rule index:<fk> { :i FOREIGN KEY <local-column-name=.name> REFERENCES '(' ~ ')' <column-name=.name>+ % "," }
multi rule index:<unique> { :i UNIQUE '(' ~ ')' <column-name=.name>+ % "," }
}
class SQL::CreateTable::Action {
use Red::Cli::Table;
use Red::Cli::Column;
method TOP($/) { make $<create-table>».made }
method create-table($/) { make Red::Cli::Table.new: name => $<table-name>.made, columns => $<column>».made }
method name($/) { make ~$/ }
method type($/) { make $/.Str.trim}
method column($/) {
make Red::Cli::Column.new(
$<column-name>.made,
$<type>.made,
($<modifier>.made // True),
|$<index-mod>.made<pk unique references>
)
}
method auto-increment { make ( :auto-increment ) }
method modifier:<null>($/) { make ( :nullable ) }
method modifier:<not-null>($/) { make ( :!nullable ) }
method index-mod:<pk>($/) { make ( :pk ) }
method index-mod:<fk>($/) { make ( :references( %( table => $<table-name>.made, column => $<column-name>.made ) ) ) }
method index-mod:<unique>($/) { make ( :unique ) }
method index:<pk>($/) { ... }
method index:<fk>($/) { ... }
method index:<unique>($/) { ... }
}
method tables-names { self.sqlite-master.tables.map: *.name }
method indexes-of($table) { self.sqlite-master.find-table($table).indexes }
method table-definition($table) {
my $sql = self.sqlite-master.find-table($table).sql;
my $list = self.table-definition-from-create-table($sql);
return unless $list;
$list.head
}
multi method table-definition-from-create-table(Str:D $sql) {
SQL::CreateTable.parse($sql, :actions(SQL::CreateTable::Action)).made;
}
multi method table-definition-from-create-table(Any:U) {
Red::Cli::Table.new
}