File Coverage

blib/lib/Google/BigQuery.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             package Google::BigQuery;
2 1     1   813 use 5.010001;
  1         3  
  1         32  
3 1     1   4 use strict;
  1         1  
  1         28  
4 1     1   4 use warnings;
  1         8  
  1         42  
5              
6             our $VERSION = "1.00";
7              
8 1     1   442 use Class::Load qw(load_class);
  1         21509  
  1         54  
9 1     1   187 use Crypt::OpenSSL::PKCS12;
  0            
  0            
10             use JSON qw(decode_json encode_json);
11             use JSON::WebToken;
12             use LWP::UserAgent;
13              
14             sub create {
15             my (%args) = @_;
16              
17             my $version = $args{version} // 'v2';
18             my $class = 'Google::BigQuery::' . ucfirst($version);
19              
20             if (load_class($class)) {
21             return $class->new(%args);
22             } else {
23             die "Can't load class: $class";
24             }
25             }
26              
27             sub new {
28             my ($class, %args) = @_;
29              
30             die "undefined client_eamil" if !defined $args{client_email};
31             die "undefined private_key_file" if !defined $args{private_key_file};
32             die "not found private_key_file" if !-f $args{private_key_file};
33              
34             my $self = bless { %args }, $class;
35              
36             $self->{GOOGLE_API_TOKEN_URI} = 'https://accounts.google.com/o/oauth2/token';
37             $self->{GOOGLE_API_GRANT_TYPE} = 'urn:ietf:params:oauth:grant-type:jwt-bearer';
38              
39             if ($self->{private_key_file} =~ /\.json$/) {
40             open my $in, "<", $self->{private_key_file} or die "can't open $self->{private_key_file} : $!";
41             my $private_key_json = decode_json(join('', <$in>));
42             close $in;
43             $self->{private_key} = $private_key_json->{private_key};
44             } elsif ($self->{private_key_file} =~ /\.p12$/) {
45             my $password = "notasecret";
46             my $pkcs12 = Crypt::OpenSSL::PKCS12->new_from_file($self->{private_key_file});
47             $self->{private_key} = $pkcs12->private_key($password);
48             } else {
49             die "invalid private_key_file format";
50             }
51              
52             $self->_auth;
53             $self->_set_rest_description;
54              
55             return $self;
56             }
57              
58             sub DESTROY {
59             }
60              
61             sub _auth {
62             my ($self) = @_;
63              
64             $self->{scope} //= [qw(https://www.googleapis.com/auth/bigquery)];
65             $self->{exp} = time + 3600;
66             $self->{iat} = time;
67             $self->{ua} = LWP::UserAgent->new;
68              
69             my $claim = {
70             iss => $self->{client_email},
71             scope => join(" ", @{$self->{scope}}),
72             aud => $self->{GOOGLE_API_TOKEN_URI},
73             exp => $self->{exp},
74             iat => $self->{iat},
75             };
76              
77             my $jwt = JSON::WebToken::encode_jwt($claim, $self->{private_key}, 'RS256', { type => 'JWT' });
78              
79             my $response = $self->{ua}->post(
80             $self->{GOOGLE_API_TOKEN_URI},
81             { grant_type => $self->{GOOGLE_API_GRANT_TYPE}, assertion => $jwt }
82             );
83              
84             if ($response->is_success) {
85             $self->{access_token} = decode_json($response->decoded_content);
86             } else {
87             my $error = decode_json($response->decoded_content);
88             die $error->{error};
89             }
90             }
91              
92             sub _set_rest_description {
93             my ($self) = @_;
94             my $response = $self->{ua}->get($self->{GOOGLE_BIGQUERY_REST_DESCRIPTION});
95             $self->{rest_description} = decode_json($response->decoded_content);
96             }
97              
98             sub use_project {
99             my ($self, $project_id) = @_;
100             $self->{project_id} = $project_id // return;
101             }
102              
103             sub use_dataset {
104             my ($self, $dataset_id) = @_;
105             $self->{dataset_id} = $dataset_id // return;
106             }
107              
108             sub create_dataset {
109             my ($self, %args) = @_;
110              
111             my $project_id = $args{project_id} // $self->{project_id};
112             my $dataset_id = $args{dataset_id} // $self->{dataset_id};
113              
114             unless ($project_id) {
115             warn "no project\n";
116             return 0;
117             }
118             unless ($dataset_id) {
119             warn "no dataset\n";
120             return 0;
121             }
122              
123             my $content = {
124             datasetReference => {
125             projectId => $project_id,
126             datasetId => $dataset_id
127             }
128             };
129              
130             # option
131             $content->{access} = $args{access} if defined $args{access};
132             $content->{description} = $args{description} if defined $args{description};
133             $content->{friendlyName} = $args{friendlyName} if defined $args{friendlyName};
134              
135             my $response = $self->request(
136             resource => 'datasets',
137             method => 'insert',
138             project_id => $project_id,
139             dataset_id => $dataset_id,
140             content => $content,
141             );
142             $self->{response} = $response;
143              
144             if (defined $response->{error}) {
145             warn $response->{error}{message};
146             return 0;
147             } else {
148             return 1;
149             }
150             }
151              
152             sub drop_dataset {
153             my ($self, %args) = @_;
154              
155             my $project_id = $args{project_id} // $self->{project_id};
156             my $dataset_id = $args{dataset_id};
157              
158             unless ($project_id) {
159             warn "no project\n";
160             return 0;
161             }
162             unless ($dataset_id) {
163             warn "no dataset\n";
164             return 0;
165             }
166              
167             # option
168             my $query_string = {};
169             if (defined $args{deleteContents}) {
170             $query_string->{deleteContents} = $args{deleteContents} ? 'true' : 'false';
171             }
172              
173             my $response = $self->request(
174             resource => 'datasets',
175             method => 'delete',
176             project_id => $project_id,
177             dataset_id => $dataset_id,
178             query_string => $query_string,
179             );
180             $self->{response} = $response;
181              
182             if (defined $response->{error}) {
183             warn $response->{error}{message};
184             return 0;
185             } else {
186             return 1;
187             }
188             }
189              
190             sub show_datasets {
191             my ($self, %args) = @_;
192              
193             my $project_id = $args{project_id} // $self->{project_id};
194              
195             unless ($project_id) {
196             warn "no project\n";
197             return undef;
198             }
199              
200             # option
201             my $query_string = {};
202             if (defined $args{all}) {
203             $query_string->{all} = $args{all} ? 'true' : 'false';
204             }
205             $query_string->{maxResults} = $args{maxResults} if defined $args{maxResults};
206             $query_string->{pageToken} = $args{pageToken} if defined $args{pageToken};
207              
208             my $response = $self->request(
209             resource => 'datasets',
210             method => 'list',
211             project_id => $project_id,
212             query_string => $query_string,
213             );
214             $self->{response} = $response;
215              
216             if (defined $response->{error}) {
217             warn $response->{error}{message};
218             return undef;
219             }
220              
221             my @ret = ();
222             foreach my $dataset (@{$response->{datasets}}) {
223             push @ret, $dataset->{datasetReference}{datasetId};
224             }
225              
226             return @ret;
227             }
228              
229             sub desc_dataset {
230             my ($self, %args) = @_;
231              
232             my $project_id = $args{project_id} // $self->{project_id};
233             my $dataset_id = $args{dataset_id} // $self->{dataset_id};
234              
235             unless ($project_id) {
236             warn "no project\n";
237             return 0;
238             }
239             unless ($dataset_id) {
240             warn "no dataset\n";
241             return 0;
242             }
243              
244             my $response = $self->request(
245             resource => 'datasets',
246             method => 'get',
247             project_id => $project_id,
248             dataset_id => $dataset_id,
249             );
250             $self->{response} = $response;
251              
252             if (defined $response->{error}) {
253             warn $response->{error}{message};
254             return undef;
255             } else {
256             return $response;
257             }
258             }
259              
260             sub create_table {
261             my ($self, %args) = @_;
262              
263             my $project_id = $args{project_id} // $self->{project_id};
264             my $dataset_id = $args{dataset_id} // $self->{dataset_id};
265             my $table_id = $args{table_id};
266              
267             unless ($project_id) {
268             warn "no project\n";
269             return 0;
270             }
271             unless ($dataset_id) {
272             warn "no dataset\n";
273             return 0;
274             }
275             unless ($table_id) {
276             warn "no table\n";
277             return 0;
278             }
279              
280             my $content = {
281             tableReference => {
282             projectId => $project_id,
283             datasetId => $dataset_id,
284             tableId => $table_id
285             },
286             };
287              
288             # option
289             $content->{description} = $args{description} if defined $args{description};
290             $content->{expirationTime} = $args{expirationTime} if defined $args{expirationTime};
291             $content->{friendlyName} = $args{friendlyName} if defined $args{friendlyName};
292             $content->{schema}{fields} = $args{schema} if defined $args{schema};
293             $content->{view}{query} = $args{view} if defined $args{view};
294              
295             my $response = $self->request(
296             resource => 'tables',
297             method => 'insert',
298             project_id => $project_id,
299             dataset_id => $dataset_id,
300             table_id => $table_id,
301             content => $content,
302             );
303             $self->{response} = $response;
304              
305             if (defined $response->{error}) {
306             warn $response->{error}{message};
307             return 0;
308             } elsif (defined $args{schema} && !defined $response->{schema}) {
309             warn "no create schema";
310             return 0;
311             } else {
312             return 1;
313             }
314             }
315              
316             sub drop_table {
317             my ($self, %args) = @_;
318              
319             my $project_id = $args{project_id} // $self->{project_id};
320             my $dataset_id = $args{dataset_id} // $self->{dataset_id};
321             my $table_id = $args{table_id};
322              
323             unless ($project_id) {
324             warn "no project\n";
325             return 0;
326             }
327             unless ($dataset_id) {
328             warn "no dataset\n";
329             return 0;
330             }
331             unless ($table_id) {
332             warn "no table\n";
333             return 0;
334             }
335              
336             my $response = $self->request(
337             resource => 'tables',
338             method => 'delete',
339             project_id => $project_id,
340             dataset_id => $dataset_id,
341             table_id => $table_id
342             );
343             $self->{response} = $response;
344              
345             if (defined $response->{error}) {
346             warn $response->{error}{message};
347             return 0;
348             } else {
349             return 1;
350             }
351             }
352              
353             sub show_tables {
354             my ($self, %args) = @_;
355              
356             my $project_id = $args{project_id} // $self->{project_id};
357             my $dataset_id = $args{dataset_id} // $self->{dataset_id};
358              
359             unless ($project_id) {
360             warn "no project\n";
361             return undef;
362             }
363             unless ($dataset_id) {
364             warn "no dataset\n";
365             return undef;
366             }
367              
368             # option
369             my $query_string = {};
370             $query_string->{maxResults} = $args{maxResults} if defined $args{maxResults};
371             $query_string->{pageToken} = $args{pageToken} if defined $args{pageToken};
372              
373             my $response = $self->request(
374             resource => 'tables',
375             method => 'list',
376             project_id => $project_id,
377             dataset_id => $dataset_id,
378             query_string => $query_string,
379             );
380             $self->{response} = $response;
381              
382             if (defined $response->{error}) {
383             warn $response->{error}{message};
384             return undef;
385             }
386              
387             my @ret = ();
388             foreach my $table (@{$response->{tables}}) {
389             push @ret, $table->{tableReference}{tableId};
390             }
391              
392             return @ret;
393             }
394              
395             sub desc_table {
396             my ($self, %args) = @_;
397              
398             my $project_id = $args{project_id} // $self->{project_id};
399             my $dataset_id = $args{dataset_id} // $self->{dataset_id};
400             my $table_id = $args{table_id};
401              
402             unless ($project_id) {
403             warn "no project\n";
404             return 0;
405             }
406             unless ($dataset_id) {
407             warn "no dataset\n";
408             return 0;
409             }
410             unless ($table_id) {
411             warn "no table\n";
412             return 0;
413             }
414              
415             my $response = $self->request(
416             resource => 'tables',
417             method => 'get',
418             project_id => $project_id,
419             dataset_id => $dataset_id,
420             table_id => $table_id,
421             );
422             $self->{response} = $response;
423              
424             if (defined $response->{error}) {
425             warn $response->{error}{message};
426             return undef;
427             } else {
428             return $response;
429             }
430             }
431              
432             sub load {
433             my ($self, %args) = @_;
434              
435             my $project_id = $args{project_id} // $self->{project_id};
436             my $dataset_id = $args{dataset_id} // $self->{dataset_id};
437             my $table_id = $args{table_id};
438             my $data = $args{data};
439              
440             unless ($project_id) {
441             warn "no project\n";
442             return 0;
443             }
444             unless ($dataset_id) {
445             warn "no dataset\n";
446             return 0;
447             }
448             unless ($table_id) {
449             warn "no table\n";
450             return 0;
451             }
452             unless ($data) {
453             warn "no data\n";
454             return 0;
455             }
456              
457             my $content = {
458             configuration => {
459             load => {
460             destinationTable => {
461             projectId => $project_id,
462             datasetId => $dataset_id,
463             tableId => $table_id,
464             }
465             }
466             }
467             };
468              
469             if (ref($data) =~ /ARRAY/) {
470             $content->{configuration}{load}{sourceUris} = $data;
471             } elsif ($data =~ /^gs:\/\//) {
472             $content->{configuration}{load}{sourceUris} = [($data)];
473             }
474              
475             my $suffix;
476             if (defined $content->{configuration}{load}{sourceUris}) {
477             $suffix = $1 if $content->{configuration}{load}{sourceUris}[0] =~ /\.(tsv|csv|json)(?:\.gz)?$/i;
478             } else {
479             $suffix = $1 if $data =~ /\.(tsv|csv|json)(?:\.gz)?$/i;
480             }
481              
482             if (defined $suffix) {
483             my $source_format;
484             my $field_delimiter;
485             if ($suffix =~ /^tsv$/i) {
486             $field_delimiter = "\t";
487             } elsif ($suffix =~ /^json$/i) {
488             $source_format = "NEWLINE_DELIMITED_JSON";
489             }
490             $content->{configuration}{load}{sourceFormat} = $source_format if defined $source_format;
491             $content->{configuration}{load}{fieldDelimiter} = $field_delimiter if defined $field_delimiter;
492             }
493              
494             # load options
495             if (defined $args{allowJaggedRows}) {
496             $content->{configuration}{load}{allowJaggedRows} = $args{allowJaggedRows} ? 'true' : 'false';
497             }
498             if (defined $args{allowQuotedNewlines}) {
499             $content->{configuration}{load}{allowQuotedNewlines} = $args{allowQuotedNewlines} ? 'true' : 'false';
500             }
501             $content->{configuration}{load}{createDisposition} = $args{createDisposition} if defined $args{createDisposition};
502             $content->{configuration}{load}{encoding} = $args{encoding} if defined $args{encoding};
503             $content->{configuration}{load}{fieldDelimiter} = $args{fieldDelimiter} if defined $args{fieldDelimiter};
504             if (defined $args{ignoreUnknownValues}) {
505             $content->{configuration}{load}{ignoreUnknownValues} = $args{ignoreUnknownValues} ? 'true' : 'false';
506             }
507             $content->{configuration}{load}{maxBadRecords} = $args{maxBadRecords} if defined $args{maxBadRecords};
508             $content->{configuration}{load}{quote} = $args{quote} if defined $args{quote};
509             $content->{configuration}{load}{schema}{fields} = $args{schema} if defined $args{schema};
510             $content->{configuration}{load}{skipLeadingRows} = $args{skipLeadingRows} if defined $args{skipLeadingRows};
511             $content->{configuration}{load}{sourceFormat} = $args{sourceFormat} if defined $args{sourceFormat};
512             $content->{configuration}{load}{sourceUris} = $args{sourceUris} if defined $args{sourceUris};
513             $content->{configuration}{load}{writeDisposition} = $args{writeDisposition} if defined $args{writeDisposition};
514              
515             my $response = $self->request(
516             resource => 'jobs',
517             method => 'insert',
518             project_id => $project_id,
519             dataset_id => $dataset_id,
520             talbe_id => $table_id,
521             content => $content,
522             data => $data
523             );
524             $self->{response} = $response;
525              
526             if (defined $response->{error}) {
527             warn $response->{error}{message};
528             return 0;
529             } elsif ($response->{status}{state} eq 'DONE') {
530             if (defined $response->{status}{errors}) {
531             foreach my $error (@{$response->{status}{errors}}) {
532             warn encode_json($error), "\n";
533             }
534             return 0;
535             } else {
536             return 1;
537             }
538             } else {
539             return 0;
540             }
541             }
542              
543             sub insert {
544             my ($self, %args) = @_;
545              
546             my $project_id = $args{project_id} // $self->{project_id};
547             my $dataset_id = $args{dataset_id} // $self->{dataset_id};
548             my $table_id = $args{table_id};
549             my $values = $args{values};
550              
551             unless ($project_id) {
552             warn "no project\n";
553             return 0;
554             }
555             unless ($dataset_id) {
556             warn "no dataset\n";
557             return 0;
558             }
559             unless ($table_id) {
560             warn "no table\n";
561             return 0;
562             }
563             unless ($values) {
564             warn "no values\n";
565             return 0;
566             }
567              
568             my $rows = [];
569             foreach my $value (@$values) {
570             push @$rows, { json => $value };
571             }
572              
573             my $response = $self->request(
574             resource => 'tabledata',
575             method => 'insertAll',
576             project_id => $project_id,
577             dataset_id => $dataset_id,
578             table_id => $table_id,
579             content => {
580             rows => $rows
581             }
582             );
583             $self->{response} = $response;
584              
585             if (defined $response->{error}) {
586             warn $response->{error}{message};
587             return 0;
588             } elsif (defined $response->{insertErrors}) {
589             foreach my $error (@{$response->{insertErrors}}) {
590             warn encode_json($error), "\n";
591             }
592             return 0;
593             } else {
594             return 1;
595             }
596             }
597              
598             sub selectrow_array {
599             my ($self, %args) = @_;
600              
601             my $query = $args{query};
602             my $project_id = $args{project_id} // $self->{project_id};
603             my $dataset_id = $args{dataset_id} // $self->{dataset_id};
604              
605             unless ($query) {
606             warn "no query\n";
607             return 0;
608             }
609             unless ($project_id) {
610             warn "no project\n";
611             return 0;
612             }
613              
614             my $content = {
615             query => $query,
616             };
617              
618             # option
619             if (defined $dataset_id) {
620             $content->{defaultDataset}{projectId} = $project_id;
621             $content->{defaultDataset}{datasetId} = $dataset_id;
622             }
623             $content->{maxResults} = $args{maxResults} if defined $args{maxResults};
624             $content->{timeoutMs} = $args{timeoutMs} if defined $args{timeoutMs};
625             if (defined $args{dryRun}) {
626             $content->{dryRun} = $args{dryRun} ? 'true' : 'false';
627             }
628             if (defined $args{useQueryCache}) {
629             $content->{useQueryCache} = $args{useQueryCache} ? 'true' : 'false';
630             }
631              
632             my $response = $self->request(
633             resource => 'jobs',
634             method => 'query',
635             content => $content
636             );
637             $self->{response} = $response;
638              
639             if (defined $response->{error}) {
640             warn $response->{error}{message};
641             return 0;
642             }
643              
644             my @ret = ();
645             foreach my $field (@{$response->{rows}[0]{f}}) {
646             push @ret, $field->{v};
647             }
648              
649             return @ret;
650             }
651              
652             sub selectall_arrayref {
653             my ($self, %args) = @_;
654              
655             my $query = $args{query};
656             my $project_id = $args{project_id} // $self->{project_id};
657             my $dataset_id = $args{dataset_id} // $self->{dataset_id};
658              
659             unless ($query) {
660             warn "no query\n";
661             return 0;
662             }
663             unless ($project_id) {
664             warn "no project\n";
665             return 0;
666             }
667              
668             my $content = {
669             query => $query,
670             };
671              
672             # option
673             if (defined $dataset_id) {
674             $content->{defaultDataset}{projectId} = $project_id;
675             $content->{defaultDataset}{datasetId} = $dataset_id;
676             }
677             $content->{maxResults} = $args{maxResults} if defined $args{maxResults};
678             $content->{timeoutMs} = $args{timeoutMs} if defined $args{timeoutMs};
679             if (defined $args{dryRun}) {
680             $content->{dryRun} = $args{dryRun} ? 'true' : 'false';
681             }
682             if (defined $args{useQueryCache}) {
683             $content->{useQueryCache} = $args{useQueryCache} ? 'true' : 'false';
684             }
685              
686             my $response = $self->request(
687             resource => 'jobs',
688             method => 'query',
689             content => $content
690             );
691             $self->{response} = $response;
692              
693             if (defined $response->{error}) {
694             warn $response->{error}{message};
695             return 0;
696             }
697              
698             my $ret = [];
699             foreach my $rows (@{$response->{rows}}) {
700             my $row = [];
701             foreach my $field (@{$rows->{f}}) {
702             push @$row, $field->{v};
703             }
704             push @$ret, $row;
705             }
706              
707             return $ret;
708             }
709              
710             sub is_exists_dataset {
711             my ($self, %args) = @_;
712              
713             my $project_id = $args{project_id} // $self->{project_id};
714             my $dataset_id = $args{dataset_id} // $self->{dataset_id};
715              
716             unless ($project_id) {
717             warn "no project\n";
718             return 0;
719             }
720             unless ($dataset_id) {
721             warn "no dataset\n";
722             return 0;
723             }
724              
725             my $response = $self->request(
726             resource => 'datasets',
727             method => 'get',
728             project_id => $project_id,
729             dataset_id => $dataset_id
730             );
731             $self->{response} = $response;
732              
733             if (defined $response->{error}) {
734             #warn $response->{error}{message};
735             return 0;
736             } else {
737             return 1;
738             }
739             }
740              
741             sub is_exists_table {
742             my ($self, %args) = @_;
743              
744             my $project_id = $args{project_id} // $self->{project_id};
745             my $dataset_id = $args{dataset_id} // $self->{dataset_id};
746             my $table_id = $args{table_id};
747              
748             unless ($project_id) {
749             warn "no project\n";
750             return 0;
751             }
752             unless ($dataset_id) {
753             warn "no dataset\n";
754             return 0;
755             }
756             unless ($table_id) {
757             warn "no table\n";
758             return 0;
759             }
760              
761             my $response = $self->request(
762             resource => 'tables',
763             method => 'get',
764             project_id => $project_id,
765             dataset_id => $dataset_id,
766             table_id => $table_id
767             );
768             $self->{response} = $response;
769              
770             if (defined $response->{error}) {
771             #warn $response->{error}{message};
772             return 0;
773             } else {
774             return 1;
775             }
776             }
777              
778             sub extract {
779             my ($self, %args) = @_;
780              
781             my $project_id = $args{project_id} // $self->{project_id};
782             my $dataset_id = $args{dataset_id} // $self->{dataset_id};
783             my $table_id = $args{table_id};
784             my $data = $args{data};
785              
786             unless ($project_id) {
787             warn "no project\n";
788             return 0;
789             }
790             unless ($dataset_id) {
791             warn "no dataset\n";
792             return 0;
793             }
794             unless ($table_id) {
795             warn "no table\n";
796             return 0;
797             }
798             unless ($data) {
799             warn "no data\n";
800             return 0;
801             }
802              
803             my $content = {
804             configuration => {
805             extract => {
806             sourceTable => {
807             projectId => $project_id,
808             datasetId => $dataset_id,
809             tableId => $table_id,
810             }
811             }
812             }
813             };
814              
815             if (ref($data) =~ /ARRAY/) {
816             $content->{configuration}{extract}{destinationUris} = $data;
817             } elsif ($data =~ /^gs:\/\//) {
818             $content->{configuration}{extract}{destinationUris} = [($data)];
819             } else {
820             $content->{configuration}{extract}{destinationUris} = [('')];
821             }
822              
823             my $suffix;
824             my $compression;
825             if (defined $content->{configuration}{extract}{destinationUris}) {
826             $suffix = $1 if $content->{configuration}{extract}{destinationUris}[0] =~ /\.(tsv|csv|json|avro)(?:\.gz)?$/i;
827             $compression = 'GZIP' if $content->{configuration}{extract}{destinationUris}[0] =~ /\.gz$/i;
828             }
829              
830             if (defined $suffix) {
831             my $destination_format;
832             my $field_delimiter;
833             if ($suffix =~ /^tsv$/i) {
834             $field_delimiter = "\t";
835             } elsif ($suffix =~ /^json$/i) {
836             $destination_format = "NEWLINE_DELIMITED_JSON";
837             } elsif ($suffix =~ /^avro$/) {
838             $destination_format = "AVRO";
839             }
840             $content->{configuration}{extract}{destinationFormat} = $destination_format if defined $destination_format;
841             $content->{configuration}{extract}{fieldDelimiter} = $field_delimiter if defined $field_delimiter;
842             }
843             $content->{configuration}{extract}{compression} = $compression if defined $compression;
844              
845             # extract options
846             $content->{configuration}{extract}{compression} = $args{compression} if defined $args{compression};
847             $content->{configuration}{extract}{destinationFormat} = $args{destinationFormat} if defined $args{destinationFormat};
848             $content->{configuration}{extract}{destinationUris} = $args{destinationUris} if defined $args{destinationUris};
849             $content->{configuration}{extract}{fieldDelimiter} = $args{fieldDelimiter} if defined $args{fieldDelimiter};
850             if (defined $args{printHeader}) {
851             $content->{configuration}{extract}{printHeader} = $args{printHeader} ? 'true' : 'false';
852             }
853              
854             my $response = $self->request(
855             resource => 'jobs',
856             method => 'insert',
857             project_id => $project_id,
858             dataset_id => $dataset_id,
859             talbe_id => $table_id,
860             content => $content,
861             data => $data
862             );
863             $self->{response} = $response;
864              
865             if (defined $response->{error}) {
866             warn $response->{error}{message};
867             return 0;
868             } elsif ($response->{status}{state} eq 'DONE') {
869             if (defined $response->{status}{errors}) {
870             foreach my $error (@{$response->{status}{errors}}) {
871             warn encode_json($error), "\n";
872             }
873             return 0;
874             } else {
875             return 1;
876             }
877             } else {
878             return 0;
879             }
880             }
881              
882             sub get_nextPageToken {
883             my $self = shift;
884              
885             if (defined $self->{response}{nextPageToken}) {
886             return $self->{response}{nextPageToken};
887             } else {
888             return undef;
889             }
890             }
891              
892             1;
893             __END__