|
| 1 | +package Convos::Core::Backend::SQLite; |
| 2 | +use Mojo::Base 'Convos::Core::Backend'; |
| 3 | + |
| 4 | +use Mojo::SQLite; |
| 5 | +use Convos::Date qw(dt); |
| 6 | +use Mojo::JSON qw(false true); |
| 7 | + |
| 8 | +has home => sub { Carp::confess('home() cannot be built') }; |
| 9 | +has sqlite => sub { Mojo::SQLite->new('sqlite:' . shift->home->child('convos.sqlite')) }; |
| 10 | + |
| 11 | +sub connections_p { |
| 12 | + my ($self, $user) = @_; |
| 13 | + |
| 14 | + return $self->sqlite->db->select_p('convos_connections')->then(sub { |
| 15 | + return shift->hashes->to_array; |
| 16 | + }); |
| 17 | +} |
| 18 | + |
| 19 | +sub delete_messages_p { |
| 20 | + my ($self, $obj) = @_; |
| 21 | + return Mojo::Promise->reject('Unknown target.') unless $obj and $obj->connection; |
| 22 | + return $self->sqlite->db->delete_p(convos_messages => {conversation_id => $obj->id}) |
| 23 | + ->then(sub {$obj}); |
| 24 | +} |
| 25 | + |
| 26 | +sub delete_object_p { |
| 27 | + my ($self, $obj) = @_; |
| 28 | + |
| 29 | + if ($obj->isa('Convos::Core::Connection')) { |
| 30 | + $obj->unsubscribe($_) for qw(conversation message state); |
| 31 | + } |
| 32 | + |
| 33 | + return $self->delete_p($self->_obj_to_table($obj), {id => $obj->id})->then(sub {$obj}); |
| 34 | +} |
| 35 | + |
| 36 | +sub load_object_p { |
| 37 | + my ($self, $obj) = @_; |
| 38 | + |
| 39 | + return $self->select_p($self->_obj_to_table($obj), {id => $obj->id})->then(sub { |
| 40 | + return shift->hash; |
| 41 | + }); |
| 42 | +} |
| 43 | + |
| 44 | +sub messages_p { |
| 45 | + my ($self, $obj, $query) = @_; |
| 46 | + |
| 47 | + if ($query->{around}) { |
| 48 | + my %query_before = (%$query, around => undef, before => $query->{around}); |
| 49 | + my %query_after = (%$query, around => undef, after => $query->{around}, include => 1); |
| 50 | + |
| 51 | + return Mojo::Promise->all( |
| 52 | + $self->messages_p($obj, \%query_before), |
| 53 | + $self->messages_p($obj, \%query_after), |
| 54 | + )->then(sub { |
| 55 | + my ($before, $after) = map { $_->[0] } @_; |
| 56 | + return {%$before, %$after, messages => [map { @{$_->{messages}} } ($before, $after)]}; |
| 57 | + }); |
| 58 | + } |
| 59 | + |
| 60 | + my %extra = (limit => $query->{limit} || 60); |
| 61 | + $extra{order_by} = {-desc => 'ts'}; |
| 62 | + |
| 63 | + my %where = (id => $obj->id); |
| 64 | + $where{from} = $query->{from} if $query->{from}; |
| 65 | + |
| 66 | + my $lt = $query->{include} ? '<=' : '<'; |
| 67 | + my $gt = $query->{include} ? '>=' : '>'; |
| 68 | + push @{$where{ts}}, {$gt => dt $query->{after}} if $query->{after}; |
| 69 | + push @{$where{ts}}, {$lt => dt $query->{before}} if $query->{before}; |
| 70 | + |
| 71 | + return $self->select_p(convos_messages => \%where, \%extra)->then(sub { |
| 72 | + return shift->hashes->to_array; |
| 73 | + }); |
| 74 | +} |
| 75 | + |
| 76 | +sub notifications_p { |
| 77 | + my ($self, $user, $query) = @_; |
| 78 | + |
| 79 | + my %extra = (limit => $query->{limit} || 60); |
| 80 | + $extra{order_by} = {-desc => 'ts'}; |
| 81 | + |
| 82 | + return $self->select_p(convos_notifications => {}, \%extra)->then(sub { |
| 83 | + return shift->hashes->to_array; |
| 84 | + }); |
| 85 | +} |
| 86 | + |
| 87 | +sub save_object_p { |
| 88 | + my ($self, $obj) = @_; |
| 89 | + |
| 90 | + return $self->insert_p($self->_obj_to_table($obj), $obj->TO_JSON('private'))->then(sub {$obj}); |
| 91 | +} |
| 92 | + |
| 93 | +sub users_p { |
| 94 | + my $self = shift; |
| 95 | + |
| 96 | + return $self->sqlite->db->select_p('convos_users')->then(sub { |
| 97 | + return shift->hashes->sort(sub { |
| 98 | + $a->{registered} cmp $b->{registered} || $a->{email} cmp $b->{email}; |
| 99 | + })->to_array; |
| 100 | + }); |
| 101 | +} |
| 102 | + |
| 103 | +sub _add_message_p { |
| 104 | + my ($self, $target, $msg) = @_; |
| 105 | + |
| 106 | + return $self->sqlite->db->insert_p( |
| 107 | + convos_notifications => { |
| 108 | + connection_id => $target->connection->id, |
| 109 | + conversation_id => $target->id, |
| 110 | + from => $msg->{from}, |
| 111 | + highlight => $msg->{highlight} ? 1 : 0, |
| 112 | + message => $msg->{message}, |
| 113 | + ts => dt($msg->{ts})->to_datetime, |
| 114 | + type => $msg->{type} || 'normal', |
| 115 | + } |
| 116 | + ); |
| 117 | +} |
| 118 | + |
| 119 | +sub _add_notification_p { |
| 120 | + my ($self, $target, $msg) = @_; |
| 121 | + |
| 122 | + return $self->sqlite->db->insert_p( |
| 123 | + convos_notifications => { |
| 124 | + connection_id => $target->connection->id, |
| 125 | + conversation_id => $target->id, |
| 126 | + from => $msg->{from}, |
| 127 | + message => $msg->{message}, |
| 128 | + ts => dt($msg->{ts})->to_datetime, |
| 129 | + type => $msg->{type} || 'normal', |
| 130 | + } |
| 131 | + ); |
| 132 | +} |
| 133 | + |
| 134 | +sub _obj_to_table { |
| 135 | + my ($self, $obj) = @_; |
| 136 | + return 'convos_connections' if $obj->isa('Convos::Core::Connection'); |
| 137 | + return 'convos_conversations' if $obj->isa('Convos::Core::Conversation'); |
| 138 | + return 'convos_settings' if $obj->isa('Convos::Core::Settings'); |
| 139 | + return 'convos_users' if $obj->isa('Convos::Core::User'); |
| 140 | + return 'convos_unknown_object'; |
| 141 | +} |
| 142 | + |
| 143 | +sub _setup { |
| 144 | + my $self = shift; |
| 145 | + |
| 146 | + Scalar::Util::weaken($self); |
| 147 | + my $catch = sub { $self->emit(error => shift) }; |
| 148 | + |
| 149 | + $self->on( |
| 150 | + connection => sub { |
| 151 | + my ($self, $connection) = @_; |
| 152 | + my $cid = $connection->id; |
| 153 | + my $uid = $connection->user->id; |
| 154 | + |
| 155 | + Scalar::Util::weaken($self); |
| 156 | + $connection->on( |
| 157 | + message => sub { |
| 158 | + my ($connection, $target, $msg) = @_; |
| 159 | + |
| 160 | + if ($msg->{highlight} and $target->id and !$target->is_private) { |
| 161 | + $self->_add_notification_p($target, $msg)->catch($catch); |
| 162 | + $connection->user->save_p->catch($catch); |
| 163 | + } |
| 164 | + |
| 165 | + $self->_add_message_p($target, $msg)->catch($catch); |
| 166 | + } |
| 167 | + ); |
| 168 | + } |
| 169 | + ); |
| 170 | + |
| 171 | + return $self->SUPER::_setup; |
| 172 | +} |
| 173 | + |
| 174 | +1; |
| 175 | + |
| 176 | +=encoding utf8 |
| 177 | +
|
| 178 | +=head1 NAME |
| 179 | +
|
| 180 | +Convos::Core::Backend::SQLite - Backend for storing objects to SQLite |
| 181 | +
|
| 182 | +=head1 DESCRIPTION |
| 183 | +
|
| 184 | +L<Convos::Core::Backend::SQLite> contains methods which is useful for objects |
| 185 | +that want to be persisted to an SQLite database. |
| 186 | +
|
| 187 | +=head2 Where is data stored |
| 188 | +
|
| 189 | +C<CONVOS_HOME> can be set to specify the root location for where to save store |
| 190 | +the SQLite database. The default directory on *nix systems is something like |
| 191 | +this: |
| 192 | +
|
| 193 | + $HOME/.local/share/convos/ |
| 194 | +
|
| 195 | +C<$HOME> is figured out from L<File::HomeDir/my_home>. |
| 196 | +
|
| 197 | +=head1 ATTRIBUTES |
| 198 | +
|
| 199 | +L<Convos::Core::Backend::File> inherits all attributes from |
| 200 | +L<Convos::Core::Backend> and implements the following new ones. |
| 201 | +
|
| 202 | +=head2 home |
| 203 | +
|
| 204 | +See L<Convos::Core/home>. |
| 205 | +
|
| 206 | +=head2 sqlite |
| 207 | +
|
| 208 | + $sqlite = $backend->sqlite; |
| 209 | +
|
| 210 | +Returns a L<Mojo::SQLite> object. |
| 211 | +
|
| 212 | +=head1 METHODS |
| 213 | +
|
| 214 | +L<Convos::Core::Backend::File> inherits all methods from |
| 215 | +L<Convos::Core::Backend> and implements the following new ones. |
| 216 | +
|
| 217 | +=head2 connections_p |
| 218 | +
|
| 219 | +See L<Convos::Core::Backend/connections_p>. |
| 220 | +
|
| 221 | +=head2 delete_messages_p |
| 222 | +
|
| 223 | +See L<Convos::Core::Backend/delete_messages_p>. |
| 224 | +
|
| 225 | +=head2 delete_object_p |
| 226 | +
|
| 227 | +See L<Convos::Core::Backend/delete_object_p>. |
| 228 | +
|
| 229 | +=head2 load_object_p |
| 230 | +
|
| 231 | +See L<Convos::Core::Backend/load_object_p>. |
| 232 | +
|
| 233 | +=head2 messages_p |
| 234 | +
|
| 235 | +See L<Convos::Core::Backend/messages_p>. |
| 236 | +
|
| 237 | +=head2 notifications_p |
| 238 | +
|
| 239 | +See L<Convos::Core::Backend/notifications_p>. |
| 240 | +
|
| 241 | +=head2 save_object_p |
| 242 | +
|
| 243 | +See L<Convos::Core::Backend/save_object_p>. |
| 244 | +
|
| 245 | +=head2 users_p |
| 246 | +
|
| 247 | +See L<Convos::Core::Backend/users_p>. |
| 248 | +
|
| 249 | +=head1 SEE ALSO |
| 250 | +
|
| 251 | +L<Convos::Core>. |
| 252 | +
|
| 253 | +=cut |
0 commit comments