comparison pkg/imports/bn.go @ 2532:452bc714bfd9

Continue importing bottlenecks if one item fails
author Tom Gottfried <tom@intevation.de>
date Thu, 07 Mar 2019 10:46:34 +0100
parents cfc523c70e90
children 6b34d0fb4498
comparison
equal deleted inserted replaced
2531:47b9a4f9a05c 2532:452bc714bfd9
2 // without warranty, see README.md and license for details. 2 // without warranty, see README.md and license for details.
3 // 3 //
4 // SPDX-License-Identifier: AGPL-3.0-or-later 4 // SPDX-License-Identifier: AGPL-3.0-or-later
5 // License-Filename: LICENSES/AGPL-3.0.txt 5 // License-Filename: LICENSES/AGPL-3.0.txt
6 // 6 //
7 // Copyright (C) 2018 by via donau 7 // Copyright (C) 2018, 2019 by via donau
8 // – Österreichische Wasserstraßen-Gesellschaft mbH 8 // – Österreichische Wasserstraßen-Gesellschaft mbH
9 // Software engineering by Intevation GmbH 9 // Software engineering by Intevation GmbH
10 // 10 //
11 // Author(s): 11 // Author(s):
12 // * Sascha L. Teichmann <sascha.teichmann@intevation.de> 12 // * Sascha L. Teichmann <sascha.teichmann@intevation.de>
13 // * Tom Gottfried <tom.gottfried@intevation.de>
13 14
14 package imports 15 package imports
15 16
16 import ( 17 import (
17 "context" 18 "context"
178 return nil, err 179 return nil, err
179 } 180 }
180 181
181 feedback.Info("Found %d bottlenecks for import", len(bns)) 182 feedback.Info("Found %d bottlenecks for import", len(bns))
182 183
183 tx, err := conn.BeginTx(ctx, nil)
184 if err != nil {
185 return nil, err
186 }
187 defer tx.Rollback()
188
189 var hasStmt, insertStmt, trackStmt *sql.Stmt 184 var hasStmt, insertStmt, trackStmt *sql.Stmt
190 185
191 for _, x := range []struct { 186 for _, x := range []struct {
192 sql string 187 sql string
193 stmt **sql.Stmt 188 stmt **sql.Stmt
195 {hasBottleneckSQL, &hasStmt}, 190 {hasBottleneckSQL, &hasStmt},
196 {insertBottleneckSQL, &insertStmt}, 191 {insertBottleneckSQL, &insertStmt},
197 {trackImportSQL, &trackStmt}, 192 {trackImportSQL, &trackStmt},
198 } { 193 } {
199 var err error 194 var err error
200 if *x.stmt, err = tx.PrepareContext(ctx, x.sql); err != nil { 195 if *x.stmt, err = conn.PrepareContext(ctx, x.sql); err != nil {
201 return nil, err 196 return nil, err
202 } 197 }
203 defer (*x.stmt).Close() 198 defer (*x.stmt).Close()
204 } 199 }
205 200
206 var nids []string 201 var nids []string
207 202
208 nextBN:
209 for _, bn := range bns { 203 for _, bn := range bns {
210 204 if err := storeBottleneck(
211 var found bool 205 ctx, importID, conn, feedback, bn, &nids,
212 err := hasStmt.QueryRowContext(ctx, bn.Bottleneck_id).Scan(&found) 206 hasStmt, insertStmt, trackStmt); err != nil {
213 switch {
214 case err == sql.ErrNoRows:
215 // This is good.
216 case err != nil:
217 return nil, err 207 return nil, err
218 case found: 208 }
219 // TODO: Deep comparison database vs. SOAP.
220 continue nextBN
221 }
222
223 rb, lb := splitRBLB(bn.Rb_lb)
224
225 var limiting, country string
226
227 if bn.Limiting_factor != nil {
228 limiting = string(*bn.Limiting_factor)
229 }
230
231 if bn.Responsible_country != nil {
232 country = string(*bn.Responsible_country)
233 }
234
235 var nid int64
236
237 err = insertStmt.QueryRowContext(
238 ctx,
239 bn.Bottleneck_id,
240 bn.Fk_g_fid,
241 bn.OBJNAM,
242 bn.NOBJNM,
243 bn.From_ISRS, bn.To_ISRS,
244 rb,
245 lb,
246 country,
247 revisitingTime(bn.Revisiting_time),
248 limiting,
249 bn.Date_Info,
250 bn.Source,
251 ).Scan(&nid)
252 if err != nil {
253 return nil, err
254 }
255 nids = append(nids, bn.Bottleneck_id)
256 if _, err := trackStmt.ExecContext(
257 ctx, importID, "waterway.bottlenecks", nid,
258 ); err != nil {
259 return nil, err
260 }
261 feedback.Info("Inserted '%s' into database", bn.OBJNAM)
262 } 209 }
263 if len(nids) == 0 { 210 if len(nids) == 0 {
264 return nil, UnchangedError("No new bottlenecks found") 211 return nil, UnchangedError("No new bottlenecks inserted")
265 } 212 }
266 213
267 feedback.Info("Storing %d bottlenecks took %s", len(nids), time.Since(start)) 214 feedback.Info("Storing %d bottlenecks took %s", len(nids), time.Since(start))
268 if err := tx.Commit(); err != nil {
269 return nil, err
270 }
271 feedback.Info("Import of bottlenecks was successful") 215 feedback.Info("Import of bottlenecks was successful")
272 summary := struct { 216 summary := struct {
273 Bottlenecks []string `json:"bottlenecks"` 217 Bottlenecks []string `json:"bottlenecks"`
274 }{ 218 }{
275 Bottlenecks: nids, 219 Bottlenecks: nids,
276 } 220 }
277 return &summary, nil 221 return &summary, nil
278 } 222 }
223
224 func storeBottleneck(
225 ctx context.Context,
226 importID int64,
227 conn *sql.Conn,
228 feedback Feedback,
229 bn *ifbn.BottleNeckType,
230 nids *[]string,
231 hasStmt, insertStmt, trackStmt *sql.Stmt,
232 ) error {
233
234 tx, err := conn.BeginTx(ctx, nil)
235 if err != nil {
236 return err
237 }
238 defer tx.Rollback()
239
240 var found bool
241 err = tx.Stmt(hasStmt).QueryRowContext(ctx, bn.Bottleneck_id).Scan(&found)
242 switch {
243 case err == sql.ErrNoRows:
244 // This is good.
245 case err != nil:
246 return err
247 case found:
248 feedback.Info("'%s' already in database. Skip", bn.OBJNAM)
249 // TODO: Deep comparison database vs. SOAP.
250 return nil
251 }
252
253 rb, lb := splitRBLB(bn.Rb_lb)
254
255 var limiting, country string
256
257 if bn.Limiting_factor != nil {
258 limiting = string(*bn.Limiting_factor)
259 }
260
261 if bn.Responsible_country != nil {
262 country = string(*bn.Responsible_country)
263 }
264
265 var nid int64
266
267 err = tx.Stmt(insertStmt).QueryRowContext(
268 ctx,
269 bn.Bottleneck_id,
270 bn.Fk_g_fid,
271 bn.OBJNAM,
272 bn.NOBJNM,
273 bn.From_ISRS, bn.To_ISRS,
274 rb,
275 lb,
276 country,
277 revisitingTime(bn.Revisiting_time),
278 limiting,
279 bn.Date_Info,
280 bn.Source,
281 ).Scan(&nid)
282 if err != nil {
283 feedback.Warn("Failed to insert '%s' into database", bn.OBJNAM)
284 feedback.Warn("%v", err)
285 return nil
286 }
287
288 if _, err := tx.Stmt(trackStmt).ExecContext(
289 ctx, importID, "waterway.bottlenecks", nid,
290 ); err != nil {
291 return err
292 }
293 if err = tx.Commit(); err != nil {
294 return err
295 }
296 feedback.Info("Inserted '%s' into database", bn.OBJNAM)
297 *nids = append(*nids, bn.Bottleneck_id)
298 return nil
299 }