@@ -16,10 +16,10 @@ use std::fmt;
1616use std:: marker:: PhantomData ;
1717use std:: path:: Path ;
1818
19- pub use error:: ConfigurationError ;
2019use error:: NewConfigurationError ;
20+ pub use error:: { ConfigurationError , NamedTemplateError } ;
2121use sqlx:: sqlite:: { SqliteConnectOptions , SqliteRow } ;
22- use sqlx:: { query , query_as, FromRow , QueryBuilder , Row , Sqlite , SqlitePool } ;
22+ use sqlx:: { query_as, FromRow , QueryBuilder , Row , Sqlite , SqlitePool } ;
2323use tracing:: { info, instrument, trace} ;
2424
2525use crate :: paths:: {
@@ -41,6 +41,15 @@ pub struct NamedTemplate {
4141 pub template : String ,
4242}
4343
44+ impl < ' r > FromRow < ' r , SqliteRow > for NamedTemplate {
45+ fn from_row ( row : & ' r SqliteRow ) -> Result < Self , sqlx:: Error > {
46+ Ok ( Self {
47+ name : row. try_get ( "name" ) ?,
48+ template : row. try_get ( "template" ) ?,
49+ } )
50+ }
51+ }
52+
4453#[ derive( Debug , PartialEq , Eq ) ]
4554struct RawPathTemplate < F > ( String , PhantomData < F > ) ;
4655
@@ -347,37 +356,52 @@ impl SqliteScanPathService {
347356 . ok_or ( ConfigurationError :: MissingInstrument ( instrument. into ( ) ) )
348357 }
349358
350- pub async fn additional_templates (
359+ pub async fn all_additional_templates (
351360 & self ,
352361 beamline : & str ,
353362 ) -> Result < Vec < NamedTemplate > , ConfigurationError > {
354363 Ok ( query_as ! (
355364 NamedTemplate ,
356- "SELECT templates.name, templates.template
357- FROM beamline JOIN templates ON beamline.id = templates.beamline
358- WHERE beamline.name = ?" ,
365+ "SELECT name, template FROM beamline_template WHERE beamline = ?" ,
359366 beamline
360367 )
361368 . fetch_all ( & self . pool )
362369 . await ?)
363370 }
371+ pub async fn additional_templates (
372+ & self ,
373+ beamline : & str ,
374+ names : Vec < String > ,
375+ ) -> Result < Vec < NamedTemplate > , ConfigurationError > {
376+ let mut q =
377+ QueryBuilder :: new ( "SELECT name, template FROM beamline_template WHERE beamline = " ) ;
378+ q. push_bind ( beamline) ;
379+ q. push ( " AND name IN (" ) ;
380+ let mut name_query = q. separated ( ", " ) ;
381+ for name in names {
382+ name_query. push_bind ( name) ;
383+ }
384+ q. push ( ")" ) ;
385+ let query = q. build_query_as ( ) ;
386+ Ok ( query. fetch_all ( & self . pool ) . await ?)
387+ }
364388
365389 pub async fn register_template (
366390 & self ,
367391 beamline : & str ,
368392 name : String ,
369393 template : String ,
370- ) -> Result < ( ) , ConfigurationError > {
371- query ! (
372- "INSERT INTO templates (name, template, beamline)
373- VALUES (?, ?, (SELECT id FROM beamline WHERE name = ?));" ,
394+ ) -> Result < NamedTemplate , NamedTemplateError > {
395+ Ok ( query_as ! (
396+ NamedTemplate ,
397+ "INSERT INTO template (name, template, beamline)
398+ VALUES (?, ?, (SELECT id FROM beamline WHERE name = ?)) RETURNING name, template;" ,
374399 name,
375400 template,
376401 beamline
377402 )
378- . execute ( & self . pool )
379- . await ?;
380- Ok ( ( ) )
403+ . fetch_one ( & self . pool )
404+ . await ?)
381405 }
382406
383407 /// Create a db service from a new empty/schema-less DB
@@ -407,7 +431,9 @@ impl fmt::Debug for SqliteScanPathService {
407431}
408432
409433mod error {
434+
410435 use derive_more:: { Display , Error , From } ;
436+ use sqlx:: error:: ErrorKind ;
411437
412438 #[ derive( Debug , Display , Error , From ) ]
413439 pub enum ConfigurationError {
@@ -431,6 +457,46 @@ mod error {
431457 Self :: MissingField ( value. into ( ) )
432458 }
433459 }
460+
461+ #[ derive( Debug , Display , Error ) ]
462+ pub enum NamedTemplateError {
463+ #[ display( "No configuration for beamline" ) ]
464+ MissingBeamline ,
465+ #[ display( "Template name was empty" ) ]
466+ EmptyName ,
467+ #[ display( "Template was empty" ) ]
468+ EmptyTemplate ,
469+ #[ display( "Error accessing named template: {_0}" ) ]
470+ DbError ( sqlx:: Error ) ,
471+ }
472+
473+ impl From < sqlx:: Error > for NamedTemplateError {
474+ fn from ( value : sqlx:: Error ) -> Self {
475+ match value {
476+ sqlx:: Error :: Database ( err) => match ( err. kind ( ) , err. message ( ) . split_once ( ": " ) ) {
477+ ( ErrorKind :: NotNullViolation , Some ( ( _, "template.beamline" ) ) ) => {
478+ NamedTemplateError :: MissingBeamline
479+ }
480+ // pretty sure these two are not possible as strings can't be null
481+ ( ErrorKind :: NotNullViolation , Some ( ( _, "template.name" ) ) ) => {
482+ NamedTemplateError :: EmptyName
483+ }
484+ ( ErrorKind :: NotNullViolation , Some ( ( _, "template.template" ) ) ) => {
485+ NamedTemplateError :: EmptyTemplate
486+ }
487+ // Values are empty - these rely on the named checks in the schema
488+ ( ErrorKind :: CheckViolation , Some ( ( _, "empty_name" ) ) ) => {
489+ NamedTemplateError :: EmptyName
490+ }
491+ ( ErrorKind :: CheckViolation , Some ( ( _, "empty_template" ) ) ) => {
492+ NamedTemplateError :: EmptyTemplate
493+ }
494+ ( _, _) => NamedTemplateError :: DbError ( sqlx:: Error :: Database ( err) ) ,
495+ } ,
496+ err => err. into ( ) ,
497+ }
498+ }
499+ }
434500}
435501
436502#[ cfg( test) ]
0 commit comments