1 package Gruta
::Source
::DBI
;
13 my $sth = $self->{dbh
}->prepare($sql) or
14 die $self->{dbh
}->errstr;
23 return $sth->execute( @_ ) or die $self->{dbh
}->errstr;
27 package Gruta
::Data
::DBI
::BASE
;
29 sub pk
{ return qw(id); }
35 $self->source( $driver );
39 if (not $sth = $self->source->{sth
}->{select}->{ref($self)}) {
40 my $sql = 'SELECT ' . join(', ', $self->fields()) .
41 ' FROM ' . $self->table() .
42 ' WHERE ' . join(' AND ', map { "$_ = ?" } $self->pk());
44 $sth = $self->source->{sth
}->{select}->{ref($self)} =
45 $self->source->_prepare($sql);
48 $self->source->_execute($sth, map { $self->get($_) } $self->pk());
50 my $r = $sth->fetchrow_hashref();
56 foreach my $k ($self->fields()) {
57 $self->set($k, $r->{$k});
68 $self->source( $driver ) if $driver;
72 if (not $sth = $self->source->{sth
}->{update
}->{ref($self)}) {
73 my $sql = 'UPDATE ' . $self->table() .
74 ' SET ' . join(', ', map { "$_ = ?" } $self->fields()) .
75 ' WHERE ' . join(' AND ', map { "$_ = ?" } $self->pk());
77 $sth = $self->source->{sth
}->{update
}->{ref($self)} =
78 $self->source->_prepare($sql);
81 $self->source->_execute($sth,
82 (map { $self->get($_) } $self->fields()),
83 (map { $self->get($_) } $self->pk())
94 $self->source( $driver ) if $driver;
98 if (not $sth = $self->source->{sth
}->{delete}->{ref($self)}) {
99 my $sql = 'DELETE FROM ' . $self->table() .
100 ' WHERE ' . join(' AND ', map { "$_ = ?" } $self->pk());
102 $sth = $self->source->{sth
}->{delete}->{ref($self)} =
103 $self->source->_prepare($sql);
106 $self->source->_execute($sth,
107 (map { $self->get($_) } $self->pk())
114 package Gruta
::Data
::DBI
::Story
;
116 use base
'Gruta::Data::Story';
117 use base
'Gruta::Data::DBI::BASE';
119 sub table
{ return 'stories'; }
120 sub pk
{ return qw(id topic_id); }
125 my $sth = $self->source->_prepare(
126 'UPDATE stories SET hits = hits + 1 WHERE topic_id = ? AND id = ?');
127 $self->source->_execute($sth, $self->get('topic_id'), $self->get('id'));
132 package Gruta
::Data
::DBI
::Topic
;
134 use base
'Gruta::Data::Topic';
135 use base
'Gruta::Data::DBI::BASE';
137 sub table
{ return 'topics'; }
139 package Gruta
::Data
::DBI
::User
;
141 use base
'Gruta::Data::User';
142 use base
'Gruta::Data::DBI::BASE';
144 sub table
{ return 'users'; }
146 package Gruta
::Data
::DBI
::Session
;
148 use base
'Gruta::Data::Session';
149 use base
'Gruta::Data::DBI::BASE';
151 sub table
{ return 'sids'; }
153 package Gruta
::Source
::DBI
;
155 sub _assert
{ return $_[0]; }
163 my $sth = $self->_prepare("SELECT id FROM $table");
164 $self->_execute($sth);
166 while(my @r = $sth->fetchrow_array()) {
178 my $o = ${class}->new( id
=> $id );
179 return $o->load( $self );
183 sub topic
{ return _one
( @_, 'Gruta::Data::DBI::Topic' ); }
184 sub topics
{ return $_[0]->_all('topics'); }
186 sub user
{ return _one
( @_, 'Gruta::Data::DBI::User' ); }
187 sub users
{ return $_[0]->_all('users'); }
191 my $topic_id = shift;
194 my $s = Gruta
::Data
::DBI
::Story
->new( topic_id
=> $topic_id, id
=> $id );
195 return $s->load( $self );
201 my $topic_id = shift;
205 my $sth = $self->_prepare("SELECT id FROM stories WHERE topic_id = ?");
206 $self->_execute($sth, $topic_id);
208 while(my @r = $sth->fetchrow_array()) {
216 sub stories_by_date
{
218 my $topic_id = shift;
222 $args{offset
} = 0 if $args{offset
} < 0;
224 my @args = ( $topic_id );
225 my $sql = 'SELECT id FROM stories WHERE topic_id = ?';
228 $sql .= ' AND date > ?';
229 push(@args, $args{from
});
233 $sql .= ' AND date < ?';
234 push(@args, $args{to
});
237 if (!$args{future
} && $args{today
}) {
238 $sql .= ' AND date < ?';
239 push(@args, $args{today
});
242 $sql .= ' ORDER BY date DESC';
244 if ($args{num
} || $args{offset
}) {
247 push(@args, $args{num
} || -1);
251 push(@args, $args{offset
});
255 my $sth = $self->_prepare($sql);
256 $self->_execute($sth, @args);
260 while(my $r = $sth->fetchrow_arrayref()) {
270 my $topic_id = shift;
273 my @q = map { '%' . $_ . '%' } split(/\s+/, $query);
274 my $like = 'AND content LIKE ? ' x
scalar(@q);
276 my $sth = $self->_prepare(
277 'SELECT id FROM stories WHERE topic_id = ? ' . $like .
278 'ORDER BY date DESC');
280 $self->_execute($sth, $topic_id, @q);
284 while(my $r = $sth->fetchrow_arrayref()) {
292 sub stories_top_ten
{
296 my $sql = 'SELECT topic_id, id FROM stories ' .
297 'ORDER BY hits DESC LIMIT ?';
299 my $sth = $self->_prepare($sql);
300 $self->_execute($sth, $num);
304 while (my @a = $sth->fetchrow_array()) {
312 sub session
{ return _one
( @_, 'Gruta::Data::DBI::Session' ); }
314 sub purge_old_sessions
{
317 my $sth = $self->_prepare('DELETE FROM sids WHERE time < ?');
318 $self->_execute($sth, time() - (60 * 60 * 24));
331 if (not $sth = $self->{sth
}->{insert
}->{ref($obj)}) {
332 my $sql = 'INSERT INTO ' . $table .
333 ' VALUES (' . join(', ', map { '?' } $obj->fields()) . ')';
335 $sth = $self->{sth
}->{insert
}->{ref($obj)} = $self->_prepare($sql);
338 $self->_execute($sth, map { $obj->get($_) } $obj->fields());
343 sub insert_topic
{ $_[0]->_insert($_[1], 'topics'); }
344 sub insert_user
{ $_[0]->_insert($_[1], 'users'); }
351 if (not $story->get('id')) {
352 # alloc an id for the story
355 my $sth = $self->_prepare(
356 'SELECT 1 FROM stories WHERE topic_id = ? AND id = ?');
360 $self->_execute($sth, $story->get('topic_id'), $id);
361 } while ($sth->fetchrow_arrayref());
363 $story->set('id', $id);
366 $self->_insert($story, 'stories');
371 sub insert_session
{ $_[0]->_insert($_[1], 'sids'); }
382 $self->{dbh
}->do($sql);
395 my $s = bless( { @_ }, $class);
397 $s->{dbh
} = DBI
->connect($s->{string
},
398 $s->{user
}, $s->{passwd
}, { RaiseError
=> 1 });
405 CREATE TABLE topics
(
406 id VARCHAR PRIMARY KEY
,
413 CREATE TABLE stories
(
415 topic_id VARCHAR NOT NULL
,
423 PRIMARY KEY
(id
, topic_id
)
427 id VARCHAR PRIMARY KEY
,
436 id VARCHAR PRIMARY KEY
,
442 CREATE INDEX stories_by_date ON stories
(date
)
444 CREATE INDEX stories_by_hits ON stories
(hits
)