Skip to content

Commit 2d0d113

Browse files
author
Jan Henning Thorsen
committed
Drafted SQLite backend
1 parent 3771da3 commit 2d0d113

File tree

1 file changed

+253
-0
lines changed

1 file changed

+253
-0
lines changed

lib/Convos/Core/Backend/SQLite.pm

Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
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

Comments
 (0)