File Coverage

blib/lib/JsonSQL/Query/Insert.pm
Criterion Covered Total %
statement 54 56 96.4
branch 8 10 80.0
condition n/a
subroutine 9 9 100.0
pod 2 2 100.0
total 73 77 94.8


line stmt bran cond sub pod time code
1             # ABSTRACT: JsonSQL::Query::Insert object. Stores a Perl representation of a set of INSERT statements created from a JSON string.
2              
3              
4              
5 1     1   263958 use strict;
  1         3  
  1         37  
6 1     1   7 use warnings;
  1         2  
  1         26  
7 1     1   15 use 5.014;
  1         3  
8              
9             package JsonSQL::Query::Insert;
10              
11             our $VERSION = '0.4'; # VERSION
12              
13 1     1   6 use base qw( JsonSQL::Query::Query );
  1         2  
  1         321  
14              
15 1     1   7 use JsonSQL::Validator;
  1         1  
  1         16  
16 1     1   4 use JsonSQL::Error;
  1         2  
  1         18  
17 1     1   247 use JsonSQL::Param::Insert;
  1         3  
  1         270  
18              
19              
20              
21             sub new {
22 6     6 1 3675 my ( $class, $query_rulesets, $json_query ) = @_;
23            
24             # Inherit from JsonSQL::Query::Query base class.
25 6         27 my $self = $class->SUPER::new($query_rulesets, 'insert');
26 6 50       11 if ( eval { $self->is_error } ) {
  6         59  
27 0         0 return (0, "Could not create JsonSQL INSERT query object: $self->{message}");
28             }
29            
30             # Validate the $json_query to make sure it conforms to the 'insert' JSON schema.
31 6         149 my $validator = $self->{_validator};
32 6         21 my $multiinserthashref = $validator->validate_schema($json_query);
33 6 50       10 if ( eval { $multiinserthashref->is_error } ) {
  6         65  
34 0         0 return (0, $multiinserthashref->{message});
35             }
36            
37             # Save the default DB schema to use, if one is provided.
38 6 100       166 if ( defined $multiinserthashref->{defaultschema} ) {
39 4         10 $self->{_defaultSchema} = $multiinserthashref->{defaultschema};
40             }
41            
42 6         13 $self->{_inserts} = [];
43 6         9 my @insert_errors;
44            
45 6         9 for my $inserthashref ( @{ $multiinserthashref->{inserts} } ) {
  6         13  
46             # Note: for safety, no default table parameters are supplied, so all column identifiers
47             # must be fully qualified or they will fail whitelisting checks.
48 7         25 my $insertObj = JsonSQL::Param::Insert->new($inserthashref, $self);
49 7 100       11 if ( eval { $insertObj->is_error } ) {
  7         58  
50 3         8 push(@insert_errors, $insertObj->{message});
51             } else {
52 4         84 push (@{ $self->{_inserts} }, $insertObj);
  4         13  
53             }
54             }
55            
56 6 100       13 if ( @insert_errors ) {
57 3         4 my $err = "Error(s) constructing one or more INSERT statements: \n\t";
58 3         7 $err .= join("\n\t", @insert_errors);
59 3         62 return (0, $err);
60             } else {
61 3         7 bless $self, $class;
62 3         19 return $self;
63             }
64             }
65              
66              
67             sub get_all_inserts {
68 3     3 1 1172 my $self = shift;
69            
70 3         6 my @sql_stmts;
71             my @sql_binds;
72 3         5 for my $insertObj (@{ $self->{_inserts} }) {
  3         8  
73 4         11 my ($sql, $binds) = $insertObj->get_insert_stmt($self);
74 4         9 push(@sql_stmts, $sql);
75 4         9 push(@sql_binds, $binds);
76             }
77            
78 3         9 return (\@sql_stmts, \@sql_binds);
79             }
80              
81              
82             1;
83              
84             __END__
85              
86             =pod
87              
88             =encoding UTF-8
89              
90             =head1 NAME
91              
92             JsonSQL::Query::Insert - JsonSQL::Query::Insert object. Stores a Perl representation of a set of INSERT statements created from a JSON string.
93              
94             =head1 VERSION
95              
96             version 0.4
97              
98             =head1 SYNOPSIS
99              
100             Use this to generate an SQL INSERT statement from a JSON string.
101              
102             To use this:
103              
104             use JsonSQL::Query::Insert;
105            
106             my $jsonString = '{
107             "inserts": [
108             {
109             "table": {"table": "table1", "schema": "MySchema"},
110             "values": [
111             {"column": "column1", "value": "value1"},
112             {"column": "column2", "value": "value2"}
113             ],
114             "returning": [{"column": "column1", "as": "bestcolumn"}, {"column": "column2"}]
115             },
116             {
117             "table": {"table": "table2"},
118             "values": [
119             {"column": "columnA", "value": "valueA"},
120             {"column": "columnB", "value": "valueB"}
121             ]
122             }
123             ]
124             }';
125            
126             my $whitelisting_rules = [
127             { schema => '#anySchema', 'table1' => [ 'column1', 'column2' ], 'table2' => [ 'columnA', 'columnB' ] }
128             ];
129            
130             my ( $insertObj, $err ) = JsonSQL::Query::Insert->new($whitelisting_rules, $jsonString);
131             if ( $insertObj ) {
132             my ( $sql, $binds ) = $insertObj->get_all_inserts;
133             <...>
134             } else {
135             die $err;
136             }
137              
138             Now you can go ahead and use $sql and $binds directly with the L<DBI> module to do the query.
139              
140             =head1 DESCRIPTION
141              
142             This is a JsonSQL Query module that supports SQL generation for batched INSERT statements.
143              
144             Examples of INSERT features supported by this module:
145              
146             =head2 A single INSERT statement (minimum),
147              
148             {
149             "inserts": [
150             {
151             "table": {"table": "MyTable"},
152             "values": [
153             {"column": "Animal", "value": "Giraffe"},
154             {"column": "Color", "value": "Yellow/Brown"}
155             ]
156             }
157             ]
158             }
159              
160             =head2 An INSERT statement with a RETURNING clause,
161              
162             {
163             "inserts": [
164             {
165             "table": {"table": "MyTable"},
166             "values": [
167             {"column": "Animal", "value": "Giraffe"},
168             {"column": "Color", "value": "Yellow/Brown"}
169             ],
170             "returning": [
171             {"column": "animal_id"}
172             ]
173             }
174             ]
175             }
176              
177             =head2 Multiple INSERT statements for batch processing,
178              
179             {
180             "inserts": [
181             {
182             "table": {"table": "MyTable"},
183             "values": [
184             {"column": "Animal", "value": "Giraffe"},
185             {"column": "Color", "value": "Yellow/Brown"}
186             ]
187             },
188             {
189             "table": {"table": "MyTable"},
190             "values": [
191             {"column": "Animal", "value": "Elephant"},
192             {"column": "Color", "value": "Grey"}
193             ]
194             },
195             {
196             "table": {"table": "MyTable"},
197             "values": [
198             {"column": "Animal", "value": "Horse"},
199             {"column": "Color", "value": "Black"}
200             ]
201             }
202             ]
203             }
204              
205             =head2 Structure of INSERT JSON object:
206              
207             The top-level property is the "inserts" property, which is an array of objects representing each INSERT. Each INSERT object has the
208             following properties:
209              
210             =head3 Required,
211              
212             =over
213              
214             =item table => { table => "table1" }
215              
216             Generates: INSERT INTO 'table1'
217             See L<JsonSQL::Param::Table> for more info.
218              
219             =item values => [ { column => "scientist", value = "Einstein" }, { column => "theory", value = "Relativity" } ]
220              
221             Generates ('scientist','theory') VALUES (?,?)
222             Bind: ['Einstein','Relativity']
223             See L<JsonSQL::Param::InsertValues> for more info.
224              
225             =back
226              
227             =head3 Optional,
228              
229             =over
230              
231             =item returning => { column => "column_id" }
232              
233             Generates: RETURNING 'column_id';
234             See L<JsonSQL::Param::Insert> for more info.
235              
236             =back
237              
238             =head3 Additional Properties,
239              
240             =over
241              
242             =item defaultschema => 'myschema'
243              
244             If you are using DB schemas, this property can be used to generate the schema identifier for your queries. Particularly useful for
245             per-user DB schemas.
246              
247             =back
248              
249             See L<JsonSQL::Schemas::insert> to view the restrictions enforced by the JSON schema.
250              
251             =head2 Whitelisting Module
252              
253             A set of whitelisting rules is required to successfully use this module to generate SQL. See L<JsonSQL::Validator> to learn how this works.
254              
255             =head1 METHODS
256              
257             =head2 Constructor new($query_rulesets, $json_query)
258              
259             Instantiates and returns a new JsonSQL::Query::Insert object.
260              
261             $query_rulesets => The whitelisting rules to validate the query with.
262             $json_query => A stringified JSON object representing the query.
263              
264             Returns (0, <error message>) on failure.
265              
266             =head2 ObjectMethod get_all_inserts -> ( $sql, $binds )
267              
268             Generates the SQL statement represented by the object. Returns:
269              
270             $sql => An arrayref of SQL INSERT strings.
271             $binds => An arrayref of arrays of parameterized values to pass with each INSERT query.
272              
273             =head1 AUTHOR
274              
275             Chris Hoefler <bhoefler@draper.com>
276              
277             =head1 COPYRIGHT AND LICENSE
278              
279             This software is copyright (c) 2017 by Chris Hoefler.
280              
281             This is free software; you can redistribute it and/or modify it under
282             the same terms as the Perl 5 programming language system itself.
283              
284             =cut