first functional commit of non-subclassed-style Schema::Loader
[dbsrgits/DBIx-Class-Schema-Loader.git] / lib / DBIx / Class / Schema / Loader / SQLite.pm
CommitLineData
18fca96a 1package DBIx::Class::Schema::Loader::SQLite;
a78e3fed 2
3use strict;
18fca96a 4use base 'DBIx::Class::Schema::Loader::Generic';
a78e3fed 5use Text::Balanced qw( extract_bracketed );
6use DBI;
7use Carp;
8
9=head1 NAME
10
18fca96a 11DBIx::Class::Schema::Loader::SQLite - DBIx::Class::Schema::Loader SQLite Implementation.
a78e3fed 12
13=head1 SYNOPSIS
14
18fca96a 15 use DBIx::Class::Schema::Loader;
a78e3fed 16
18fca96a 17 # $loader is a DBIx::Class::Schema::Loader::SQLite
18 my $loader = DBIx::Class::Schema::Loader->new(
a78e3fed 19 dsn => "dbi:SQLite:dbname=/path/to/dbfile",
20 namespace => "Data",
21 );
a78e3fed 22
23=head1 DESCRIPTION
24
18fca96a 25See L<DBIx::Class::Schema::Loader>.
a78e3fed 26
27=cut
28
29sub _db_classes {
30 return qw/DBIx::Class::PK::Auto::SQLite/;
31}
32
33sub _relationships {
34 my $self = shift;
35 foreach my $table ( $self->tables ) {
36
af6c2665 37 my $dbh = $self->{_storage}->dbh;
a78e3fed 38 my $sth = $dbh->prepare(<<"");
39SELECT sql FROM sqlite_master WHERE tbl_name = ?
40
41 $sth->execute($table);
42 my ($sql) = $sth->fetchrow_array;
43 $sth->finish;
44
45 # Cut "CREATE TABLE ( )" blabla...
46 $sql =~ /^[\w\s]+\((.*)\)$/si;
47 my $cols = $1;
48
49 # strip single-line comments
50 $cols =~ s/\-\-.*\n/\n/g;
51
52 # temporarily replace any commas inside parens,
53 # so we don't incorrectly split on them below
54 my $cols_no_bracketed_commas = $cols;
55 while ( my $extracted =
56 ( extract_bracketed( $cols, "()", "[^(]*" ) )[0] )
57 {
58 my $replacement = $extracted;
59 $replacement =~ s/,/--comma--/g;
60 $replacement =~ s/^\(//;
61 $replacement =~ s/\)$//;
62 $cols_no_bracketed_commas =~ s/$extracted/$replacement/m;
63 }
64
65 # Split column definitions
66 for my $col ( split /,/, $cols_no_bracketed_commas ) {
67
68 # put the paren-bracketed commas back, to help
69 # find multi-col fks below
70 $col =~ s/\-\-comma\-\-/,/g;
71
72 # CDBI doesn't have built-in support multi-col fks, so ignore them
73 next if $col =~ s/^\s*FOREIGN\s+KEY\s*//i && $col =~ /^\([^,)]+,/;
74
75 # Strip punctuations around key and table names
76 $col =~ s/[()\[\]'"]/ /g;
77 $col =~ s/^\s+//gs;
78
79 # Grab reference
80 if ( $col =~ /^(\w+).*REFERENCES\s+(\w+)\s*(\w+)?/i ) {
81 chomp $col;
82 warn qq/\# Found foreign key definition "$col"\n\n/
83 if $self->debug;
84 eval { $self->_belongs_to_many( $table, $1, $2, $3 ) };
85 warn qq/\# belongs_to_many failed "$@"\n\n/
86 if $@ && $self->debug;
87 }
88 }
89 }
90}
91
92sub _tables {
93 my $self = shift;
af6c2665 94 my $dbh = $self->{_storage}->dbh;
a78e3fed 95 my $sth = $dbh->prepare("SELECT * FROM sqlite_master");
96 $sth->execute;
97 my @tables;
98 while ( my $row = $sth->fetchrow_hashref ) {
99 next unless lc( $row->{type} ) eq 'table';
100 push @tables, $row->{tbl_name};
101 }
a78e3fed 102 return @tables;
103}
104
105sub _table_info {
106 my ( $self, $table ) = @_;
107
108 # find all columns.
af6c2665 109 my $dbh = $self->{_storage}->dbh;
a78e3fed 110 my $sth = $dbh->prepare("PRAGMA table_info('$table')");
111 $sth->execute();
112 my @columns;
113 while ( my $row = $sth->fetchrow_hashref ) {
114 push @columns, $row->{name};
115 }
116 $sth->finish;
117
118 # find primary key. so complex ;-(
119 $sth = $dbh->prepare(<<'SQL');
120SELECT sql FROM sqlite_master WHERE tbl_name = ?
121SQL
122 $sth->execute($table);
123 my ($sql) = $sth->fetchrow_array;
124 $sth->finish;
a78e3fed 125 my ($primary) = $sql =~ m/
126 (?:\(|\,) # either a ( to start the definition or a , for next
127 \s* # maybe some whitespace
128 (\w+) # the col name
129 [^,]* # anything but the end or a ',' for next column
130 PRIMARY\sKEY/sxi;
131 my @pks;
132
133 if ($primary) {
134 @pks = ($primary);
135 }
136 else {
137 my ($pks) = $sql =~ m/PRIMARY\s+KEY\s*\(\s*([^)]+)\s*\)/;
138 @pks = split( m/\s*\,\s*/, $pks ) if $pks;
139 }
140 return ( \@columns, \@pks );
141}
142
143=head1 SEE ALSO
144
18fca96a 145L<DBIx::Schema::Class::Loader>
a78e3fed 146
147=cut
148
1491;