# File: SQLite.pm # # Purpose: SQLite backend for storing and retreiving quotegrabs. # SPDX-FileCopyrightText: 2021 Pragmatic Software # SPDX-License-Identifier: MIT package PBot::Plugin::Quotegrabs::Storage::SQLite; use PBot::Imports; use DBI; use Carp qw(shortmess); sub new { if (ref($_[1]) eq 'HASH') { Carp::croak("Options to " . __FILE__ . " should be key/value pairs, not hash reference"); } my ($class, %conf) = @_; my $self = bless {}, $class; $self->initialize(%conf); return $self; } sub initialize { my ($self, %conf) = @_; $self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference in " . __FILE__); $self->{filename} = delete $conf{filename}; } sub begin { my $self = shift; $self->{pbot}->{logger}->log("Opening quotegrabs SQLite database: $self->{filename}\n"); $self->{dbh} = DBI->connect("dbi:SQLite:dbname=$self->{filename}", "", "", {RaiseError => 1, PrintError => 0, sqlite_unicode => 1}) or die $DBI::errstr; eval { $self->{dbh}->do(<< 'SQL'); CREATE TABLE IF NOT EXISTS Quotegrabs ( id INTEGER PRIMARY KEY, nick TEXT, channel TEXT, grabbed_by TEXT, text TEXT, timestamp NUMERIC ) SQL }; $self->{pbot}->{logger}->log($@) if $@; } sub end { my $self = shift; $self->{pbot}->{logger}->log("Closing quotegrabs SQLite database\n"); if (exists $self->{dbh} and defined $self->{dbh}) { $self->{dbh}->disconnect(); delete $self->{dbh}; } } sub add_quotegrab { my ($self, $quotegrab) = @_; my $id = eval { my $sth = $self->{dbh}->prepare('INSERT INTO Quotegrabs VALUES (?, ?, ?, ?, ?, ?)'); $sth->bind_param(1, undef); $sth->bind_param(2, $quotegrab->{nick}); $sth->bind_param(3, $quotegrab->{channel}); $sth->bind_param(4, $quotegrab->{grabbed_by}); $sth->bind_param(5, $quotegrab->{text}); $sth->bind_param(6, $quotegrab->{timestamp}); $sth->execute(); return $self->{dbh}->sqlite_last_insert_rowid(); }; $self->{pbot}->{logger}->log($@) if $@; return $id; } sub get_quotegrab { my ($self, $id) = @_; my $quotegrab = eval { my $sth = $self->{dbh}->prepare('SELECT * FROM Quotegrabs WHERE id == ?'); $sth->bind_param(1, $id); $sth->execute(); return $sth->fetchrow_hashref(); }; $self->{pbot}->{logger}->log($@) if $@; return $quotegrab; } sub get_random_quotegrab { my ($self, $nick, $channel, $text) = @_; $nick =~ s/\.?\*\??/%/g if defined $nick; $channel =~ s/\.?\*\??/%/g if defined $channel; $text =~ s/\.?\*\??/%/g if defined $text; $nick =~ s/\./_/g if defined $nick; $channel =~ s/\./_/g if defined $channel; $text =~ s/\./_/g if defined $text; my $quotegrab = eval { my $sql = 'SELECT * FROM Quotegrabs '; my @params; my $where = 'WHERE '; my $and = ''; # multi-grabs have the nick separated by +'s so we must test for # nick, nick+*, *+nick, and *+nick+* to match each of these cases if (defined $nick) { $sql .= $where . 'nick LIKE ? OR nick LIKE ? OR nick LIKE ? OR nick LIKE ?'; push @params, "$nick"; push @params, "$nick+%"; push @params, "%+$nick"; push @params, "%+$nick+%"; $where = ''; $and = 'AND '; } if (defined $channel) { $sql .= $where . $and . 'channel LIKE ? '; push @params, $channel; $where = ''; $and = 'AND '; } if (defined $text) { $sql .= $where . $and . 'text LIKE ? '; push @params, "%$text%"; } $sql .= 'ORDER BY RANDOM() LIMIT 1'; my $sth = $self->{dbh}->prepare($sql); $sth->execute(@params); return $sth->fetchrow_hashref(); }; $self->{pbot}->{logger}->log($@) if $@; return $quotegrab; } sub get_all_quotegrabs { my $self = shift; my $quotegrabs = eval { my $sth = $self->{dbh}->prepare('SELECT * from Quotegrabs'); $sth->execute(); return $sth->fetchall_arrayref({}); }; $self->{pbot}->{logger}->log($@) if $@; return $quotegrabs; } sub delete_quotegrab { my ($self, $id) = @_; eval { my $sth = $self->{dbh}->prepare('DELETE FROM Quotegrabs WHERE id == ?'); $sth->bind_param(1, $id); $sth->execute(); }; $self->{pbot}->{logger}->log($@) if $@; } 1;