Notes and updates based on riba's most recent comments
[dbsrgits/DBIx-Class-Manual-SQLHackers.git] / lib / DBIx / Class / Manual / SQLHackers / CREATE.pod
CommitLineData
6c2a4396 1=head1 NAME
2
3DBIx::Class::Manual::SQLHackers::CREATE - DBIx::Class for SQL Hackers - CREATE
4
5=head1 Table of Contents
6
7=over
8
9=item L<Introduction|DBIx::Class::Manual::SQLHackers::Introduction>
10
11=item CREATE
12
13=item L<INSERT|DBIx::Class::Manual::SQLHackers::INSERT>
14
15=item L<SELECT|DBIx::Class::Manual::SQLHackers::SELECT>
16
17=item L<UPDATE|DBIx::Class::Manual::SQLHackers::UPDATE>
18
19=item L<DELETE|DBIx::Class::Manual::SQLHackers::DELETE>
20
21=item L<BEGIN, COMMIT|DBIx::Class::Manual::SQLHackers::Transactions>
22
cd1e0628 23=back
24
6c2a4396 25=head1 Database structure
26
0e8be732 27To use DBIx::Class, we need to teach it about the layout of the
28underlying database. Several methods of doing this are available. If
29you have an existing database the most straightforward way is to use
30the module L<DBIx::Class::Schema::Loader>, which will introspect your
31database and generate individual classes representing every table and
32view in your database. For new projects one usually writes these
33classes by hand as described below. If you find the methods provided
34by L<DBIx::Class> core overly verbose, you can try to define your
35result classes via the more concise syntax of L<DBIx::Class::Candy>
36(the result is fully compatible with L<DBIx::Class>).
37
38Once a DBIx::Class schema (set of classes describing the database) has
39been created, built-in methods can be used to export it as SQL DDL
40using L<SQL::Translator>.
6c2a4396 41
42=head2 Using Loader
43
44Install L<DBIx::Class::Schema::Loader> and decide on a name for your schema classes.
45
46Run the included L<dbicdump> script.
47
cd1e0628 48 dbicdump -o dump_directory=./lib \
6c2a4396 49 -o components='["InflateColumn::DateTime"]' \
50 -o preserve_case=1 \
cd1e0628 51 MyApp::Schema dbi:mysql:database=foo user pass '{ quote_names => 1 }'
6c2a4396 52
53
54=head2 Manual Result class creation (and understanding Loader results)
55
2f41b1a9 56# note - CREATE INDEX is a bitch these days (requires a deploy hook) - perhaps not mentioning it at all is wise-ish?
0e8be732 57# Leaving in as it is possible, and anyway the only index I mentioned so far below was a unique one (really should add the deploy hook stuff, this is about describing the possible, not the simple)
cd1e0628 58This section covers the common and oft used CREATE DDL statements that DBIx::Class can replaces with Perl classes: B<CREATE TABLE>, B<CREATE VIEW> and B<CREATE INDEX>. The classes can be used to write the actual SQL DDL to the database or disc, if required.
59
6c2a4396 60=head3 CREATE TABLE
61
62=head4 Standard basic table creation in SQL:
63
64 CREATE TABLE users (
65 id INTEGER AUTO_INCREMENT,
66 username VARCHAR(255),
67 dob DATE,
68 realname VARCHAR(255),
69 password VARCHAR(255)
70 );
71
72We'll get to tables with references (foreign keys) later, here's the translation to DBIx::Class:
73
74The recommended version:
75
76 package MyDatabase::Schema::Result::User;
77 use strict;
78 use warnings;
79
80 use base 'DBIx::Class::Core';
81
82 __PACKAGE__->table('users');
83 __PACKAGE__->add_columns(
84 id => {
85 data_type => 'integer',
86 is_auto_increment => 1,
87 },
88 username => {
89 data_type => 'varchar',
90 size => 255,
91 },
92 dob => {
93 data_type => 'date',
94 },
95 realname => {
96 data_type => 'varchar',
97 size => 255,
98 },
99 password => {
100 data_type => 'varchar',
101 size => 255,
102 },
103 );
104 __PACKAGE__->set_primary_key('id');
105 __PACKAGE__->add_unique_constraint('uniq_username' => ['username']);
106 1;
107
108The fully descriptive version is required if you want to have DBIx::Class create your CREATE TABLE sql for you later. Many DBIC components also use settings in the column info hashrefs to decide how to treat the data for those columns.
109
2f41b1a9 110# perhaps "... with declared relations / Declaring relationships" ? "references" doesn't sound right in the context imho
0e8be732 111# in SQL land a relation == a table, since I'm talking to SQL heads I don't want to get that wrong.
6c2a4396 112=head4 Table creation with references:
113
114A relational database isn't worth much if we don't actually use references and constraints, so here is an example which constrains the B<user_id> column to only contain B<id> values from the *users* table.
115
116 CREATE TABLE posts (
117 id INTEGER AUTO_INCREMENT,
118 user_id INTEGER,
119 created_date DATETIME,
120 title VARCHAR(255),
121 post TEXT,
122 INDEX posts_idx_user_id (user_id),
123 PRIMARY KEY (id),
124 CONSTRAINT posts_fk_user_id FOREIGN KEY (user_id) REFERENCES users (id)
125 );
126
127In DBIx::Class this is achieved by adding L<relationship|DBIx::Class::Relationship> definitions to the class:
128
129 package MyDatabase::Schema::Result::Post;
130 use strict;
131 use warnings;
132 use base 'DBIx::Class::Core';
133
134 __PACKAGE__->table('posts');
135 __PACKAGE__->add_columns(
136 id => {
137 data_type => 'integer',
138 is_auto_increment => 1,
139 },
140 user_id => {
141 data_type => 'integer',
142 },
143 created_date => {
144 data_type => 'datetime',
145 },
146 title => {
147 data_type => 'varchar',
148 size => 255,
149 },
150 post => {
151 data_type => 'text',
152 },
153 );
154
155 __PACKAGE__->set_primary_key('id');
156 __PACKAGE__->belongs_to('user', 'MyDatabase::Schema::Result::User', 'user_id');
157 1;
158
2f41b1a9 159The B<belongs_to> relation creates a B<user> method which returns the user object, as well as storing JOIN information to be used when querying with JOINs. When not explicitly specified (as in this example), the columns for the JOIN clause default to the remote PRIMARY KEY column set.
cd1e0628 160
161Relationships may also be specified with completely custom JOIN conditions, using any columns, whether the database has them defined as constraints or not, or literal values.
6c2a4396 162
2f41b1a9 163Each relationship declaration in DBIC is one-way only.
6c2a4396 164To allow access from the B<user> object back to the posts they have written, we need to define another relationship in the User class:
165
166 __PACKAGE__->has_many('posts', 'MyDatabase::Schema::Result::Post', 'user_id');
167
168=head3 CREATE VIEW
169
170In SQL, a simple view that returns all users and their posts:
171
172 CREATE VIEW userposts
173 AS
174 SELECT posts.user_id, users.username, users.dob, users.realname, posts.createddate, posts.title, posts.post
175 FROM users
176 JOIN posts ON (users.id = posts.user_id)
177
178In DBIx::Class this can have a Result Class of its own:
179
180 package MyDatabase::Schema::Result::UserPosts;
181
182 use base qw/DBIx::Class::Core/;
183
cd1e0628 184 # Defaults to 'DBIx::Class::ResultSource::Table' unless specified like this
6c2a4396 185 __PACKAGE__->table_class('DBIx::Class::ResultSource::View');
186
187 __PACKAGE__->table('user_posts');
cd1e0628 188
189 # Do not emit SQL DDL for this particular resultsource
6c2a4396 190 __PACKAGE__->result_source_instance->is_virtual(1);
cd1e0628 191
6c2a4396 192 __PACKAGE__->result_source_instance->view_definition(
193 "SELECT posts.user_id, users.username, users.dob, users.realname, posts.createddate, posts.title, posts.post
194 FROM users
195 JOIN posts ON (users.id = posts.user_id)"
196 );
197 __PACKAGE__->add_columns(
198 user_id => {
199 data_type => 'integer',
200 },
201 username => {
202 data_type => 'varchar',
203 size => 255,
204 },
205 dob => {
206 data_type => 'date',
207 },
208 realname => {
209 data_type => 'varchar',
210 size => 255,
211 },
212 created_date => {
213 data_type => 'datetime',
214 },
215 title => {
216 data_type => 'varchar',
217 size => 255,
218 },
219 post => {
220 data_type => 'text',
221 },
222
223 );
224 __PACKAGE__->set_primary_key('user_id, post_id');
225
226=head3 CREATE INDEX
227
228=head4 UNIQUE indexes
229
230 CREATE UNIQUE INDEX username_idx ON user (username);
231
232To add extra unique indexes, add the B<add_unique_constraint> call to your Result Class.
233
234 __PACKAGE__->add_unique_constraint('username_idx' => ['username']);
235
0e8be732 236## Should add how to create a non-unique index via deploy hook here.
237
cd1e0628 238=head3 Outputting SQL DDL
6c2a4396 239
cd1e0628 240Once the DBIC schema has been defined, you can outout the SQL DDL needed to create the schema in your database (using the RDBMS-specific flavor of SQL DDL) in one of several ways.
6c2a4396 241
242=head4 Deploy directly to the database
243
244Create a schema object with the correct database connection, then call B<deploy> on it.
245
246 my $schema = MyDatabase::Schema->connect('dbi:SQLite:my.db');
247 $schema->deploy({add_drop_table => 1});
248
249L<DBIx::Class::Schema/deploy> has the documentation for the deploy method.
250
251=head4 Write out SQL files
252
cd1e0628 253Create a schema object with the a database connection (any will do), and call the B<create_ddl_dir> method on it.
6c2a4396 254
255 my $schema = MyDatabase::Schema->connect('dbi:SQLite:my.db');
256 $schema->create_ddl_dir(['SQLite', 'MySQL']);
257
cd1e0628 258If called with no arguments, this method will create an SQL file each for MySQL, PostgreSQL and SQLite. More databases are supported by L<SQL::Translator> if necessary.
6c2a4396 259
2f41b1a9 260### IIRC this is not true - one can not do diffs without Schema::Versioned
261### which is not loaded by default (and will soon be deprecated anyway, given how far frew and jnap have gone)
0e8be732 262## No thats rubbish, my usual use-case is to not use versioned at all, but have create_ddl_dir output me the diff files, thats where they come from. (unless someone has stuffed that up and I havent noticed..)
2f41b1a9 263
6c2a4396 264=head4 SQL files for upgrades (ALTER TABLE)
265
cd1e0628 266DBIC can also make use of L<SQL::Translator::Diff> to write out ALTER TABLE statements when the schema classes are changed.
6c2a4396 267
268To do this, make sure that you set a B<$VERSION> in your main Schema class, and run B<create_ddl_dir> on the initial version to provide a baseline.
269
270After the schema has changed, change the B<$VERSION> value and re-run B<create_ddl_dir>.
271
272 my $schema = MyDatabase::Schema->connect('dbi:SQLite:my.db');
273 $schema->create_ddl_dir(\@databases, undef, '.', '0.1');