File Coverage

blib/lib/Search/Typesense.pm
Criterion Covered Total %
statement 53 53 100.0
branch 2 4 50.0
condition n/a
subroutine 18 18 100.0
pod 2 3 66.6
total 75 78 96.1


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