File Coverage

blib/lib/Search/Typesense.pm
Criterion Covered Total %
statement 46 53 86.7
branch 1 4 25.0
condition n/a
subroutine 15 18 83.3
pod 2 3 66.6
total 64 78 82.0


line stmt bran cond sub pod time code
1             package Search::Typesense;
2              
3 4     4   487429 use v5.16.0;
  4         52  
4              
5 4     4   662 use Moo;
  4         7499  
  4         21  
6             with 'Search::Typesense::Role::Request';
7              
8 4     4   4839 use Mojo::JSON qw(decode_json encode_json);
  4         845227  
  4         348  
9 4     4   2314 use Mojo::UserAgent;
  4         1010086  
  4         40  
10 4     4   254 use Mojo::URL;
  4         9  
  4         19  
11 4     4   171 use Carp qw(croak);
  4         9  
  4         215  
12              
13 4     4   2395 use Search::Typesense::Document ();
  4         15  
  4         149  
14 4     4   2306 use Search::Typesense::Collection;
  4         14  
  4         186  
15 4     4   2160 use Search::Typesense::Version;
  4         16  
  4         170  
16 4         25 use Search::Typesense::Types qw(
17             ArrayRef
18             Bool
19             Enum
20             HashRef
21             InstanceOf
22             NonEmptyStr
23             PositiveInt
24             compile
25 4     4   34 );
  4         11  
26              
27             =head1 NAME
28              
29             Search::Typesense - Perl interface to Typesense search engine.
30              
31             =head1 SYNOPSIS
32              
33             my $typesense = Search::Typesense->new(
34             host => $host, # required
35             api_key => $key, # required
36             port => $port, # defaults to 8108
37             use_https => $bool, # defaults to true
38             );
39            
40             my $results = $typesense->search(
41             $collection_name,
42             { q => 'Search String' },
43             );
44             if ( $results->{found} ) {
45             foreach my $hit ( @{ $results->{hits} } ) {
46             ...;
47             }
48             }
49              
50             =head1 DESCRIPTION
51              
52             B<ALPHA CODE>. The interface can and will change without warning.
53              
54             This is an interface to the L<Typesense|https://typesense.org/> search
55             engine. Most methods will do one of three things:
56              
57             =over 4
58              
59             =item * Return results as defined in the Typesense documentation (listed per section)
60              
61             =item * Return nothing if Typesense returns a 404.
62              
63             =item * C<croak> if Typesense returns an error.
64              
65             =back
66              
67             =cut
68              
69             our $VERSION = '0.06';
70              
71             has collections => (
72             is => 'lazy',
73             isa => InstanceOf ['Search::Typesense::Collection'],
74             init_arg => undef,
75             handles => [qw/search/],
76             builder => sub {
77 0     0   0 my $self = shift;
78 0         0 return Search::Typesense::Collection->new(
79             user_agent => $self->_ua,
80             url => $self->_url_base,
81             );
82             },
83             );
84              
85             has documents => (
86             is => 'lazy',
87             isa => InstanceOf ['Search::Typesense::Document'],
88             init_arg => undef,
89             builder => sub {
90 0     0   0 my $self = shift;
91 0         0 return Search::Typesense::Document->new(
92             user_agent => $self->_ua,
93             url => $self->_url_base,
94             );
95             },
96             );
97              
98             # this sub without a body is called a "forward declaration" and it allows the
99             # requires() in Search::Typesense::Role::Request to realize that we really do
100             # provide these methods.
101              
102             sub _ua;
103             has _ua => (
104             is => 'lazy',
105             isa => InstanceOf ['Mojo::UserAgent'],
106             builder => sub {
107 3     3   57 my $self = shift;
108 3         48 my $ua = Mojo::UserAgent->new;
109 3         29 my $key = $self->api_key;
110             $ua->on(
111             start => sub {
112 3     3   1589 my ( $ua, $tx ) = @_;
113 3         14 $tx->req->headers->header(
114             'Content-Type' => 'application/json' )
115             ->header( 'X-TYPESENSE-API-KEY' => $key );
116             }
117 3         46 );
118 3         91 return $ua;
119             },
120             );
121              
122             sub _url_base;
123             has _url_base => (
124             is => 'lazy',
125             isa => InstanceOf ['Mojo::URL'],
126             builder => sub {
127 3     3   46 my $self = shift;
128 3         42 my $url = Mojo::URL->new;
129 3 50       96 $url->scheme( $self->use_https ? 'https' : 'http' );
130 3         158 $url->host( $self->host );
131 3         34 $url->port( $self->port );
132 3         69 return $url;
133             },
134             );
135              
136             has use_https => (
137             is => 'ro',
138             isa => Bool,
139             required => 1,
140             default => 1,
141             );
142              
143             has api_key => (
144             is => 'ro',
145             isa => NonEmptyStr,
146             required => 1,
147             );
148              
149             has host => (
150             is => 'ro',
151             isa => NonEmptyStr,
152             required => 1,
153             );
154              
155             has port => (
156             is => 'ro',
157             isa => PositiveInt,
158             default => 8108,
159             );
160              
161             sub BUILD {
162 3     3 0 27014 my $self = shift;
163 3         17 $self->assert_is_running;
164             }
165              
166             =head1 CONSTRUCTOR
167              
168             The constructor takes a list (or hashref) of key/value pairs.
169              
170             my $typesense = Search::Typesense->new(
171             host => $host, # required
172             api_key => $key, # required
173             port => $port, # defaults to 8108
174             use_https => $bool, # defaults to true
175             );
176              
177             =head2 C<api_key>
178              
179             The api key to which will be sent as the C<X-TYPESENSE-API-KEY> header.
180              
181             =head2 C<host>
182              
183             The hostname to connect to.
184              
185             =head2 C<port>
186              
187             Optional port number to connect to. Defaults to 8108 if not supplied.
188              
189             =head2 C<use_https>
190              
191             Optional boolean. Whether or not to connect to Typesense over https. Default true.
192              
193             =head1 METHODS
194              
195             =head2 C<collections>
196              
197             my $collections = $typesense->collections;
198             my $collection = $collections->get($collection_name);
199             my $results = $collections->search($collection_name, {q => 'London'});
200              
201             Returns an instance of L<Search::Typesense::Collection> for managing Typesense collections.
202              
203             =head2 C<search>
204              
205             my $results = $typesense->search($collection_name, {q => 'London'});
206              
207             Shorthand that delegated to C<< $typesense->collections->search(...) >>.
208              
209             We do this hear mainly because this is the common case.
210              
211             =head2 C<documents>
212              
213             my $documents = $typesense->documents;
214             my $document = $documents->delete($collection_name, $document_id);
215              
216             Returns an instance of L<Search::Typesense::Document> for managing Typesense documents.
217              
218             =head2 C<assert_is_running>
219              
220             $typesense->assert_is_running;
221              
222             This does nothing if we can connect to Typesense. Otherwise, this method will
223             C<croak> with a message explaining the error.
224              
225             =cut
226              
227             sub assert_is_running {
228 3     3 1 7 my $self = shift;
229 3         24 $self->_GET( path => ['health'] );
230             }
231              
232             =head2 C<typesense_version>
233              
234             my $version = $typesense->typesense_version;
235              
236             Returns an instance of L<Search::Typesense::Version>.
237              
238             If your version of Typesense is older than C<0.8.0>, this method will return
239             nothing.
240              
241             =cut
242              
243             sub typesense_version {
244 0     0 1   my $self = shift;
245 0 0         my $result = $self->_GET( path => ['debug'] ) or return;
246 0           return Search::Typesense::Version->new( version_string => $result->{version} );
247             }
248              
249             =head1 AUTHOR
250              
251             Curtis "Ovid" Poe, C<< <ovid at allaroundtheworld.fr> >>
252              
253             =head1 BUGS
254              
255             Please report any bugs or feature requests to
256             C<https://github.com/Ovid/Search-Typesense/issues>. I will be notified, and
257             then you'll automatically be notified of progress on your bug as I make
258             changes.
259              
260             =head1 SUPPORT
261              
262             You can find documentation for this module with the perldoc command.
263              
264             perldoc Search::Typesense
265              
266             You can also look for information at:
267              
268             =over 4
269              
270             =item * Github Repo
271              
272             L<https://github.com/Ovid/Search-Typesense/>
273              
274             =item * Issue Tracker
275              
276             L<https://github.com/Ovid/Search-Typesense/issues>
277              
278             =item * Search CPAN
279              
280             L<https://metacpan.org/release/Search-Typesense>
281              
282             =back
283              
284             =head1 ACKNOWLEDGEMENTS
285              
286             Thanks for Sebastian Reidel and Matt Trout for feedback.
287              
288             =head1 LICENSE AND COPYRIGHT
289              
290             This software is Copyright (c) 2021 by Curtis "Ovid" Poe.
291              
292             This is free software, licensed under:
293              
294             The Artistic License 2.0 (GPL Compatible)
295              
296             =cut
297              
298             1; # End of Search::Typesense