package simplesql import ( "context" "embed" "fmt" "path/filepath" "strings" "github.com/jmoiron/sqlx" ) // Stmts is a map of named statements type Stmts map[string]*sqlx.NamedStmt // Close will close all prepared statements. // This should be called after all statements are no longer needed. func (s *Stmts) Close() { for _, stmt := range *s { _ = stmt.Close() } } // Prepare will create a Stmts from an embed.FS. The file name is the key. func Prepare(ctx context.Context, db *sqlx.DB, queries embed.FS) (Stmts, error) { // Read entries from sqlq dir entries, err := queries.ReadDir("sqlq") if err != nil { return nil, fmt.Errorf("reading sqlq dir: %w", err) } // Get file content per entry and map to file name as prepared statement s := Stmts{} for _, entry := range entries { // Get file content fp := filepath.Join("sqlq", entry.Name()) qb, err := queries.ReadFile(fp) if err != nil { return nil, fmt.Errorf("reading file %q from sqlq: %w", fp, err) } // Cleanse input query qs := cleanseQuery(string(qb)) // Prepare statement stmt, err := db.PrepareNamedContext(ctx, qs) if err != nil { return nil, fmt.Errorf("preparing statement %q: %w", qs, err) } // Map to file name, without the extension, which is assumed to be .sql s[strings.TrimSuffix(entry.Name(), ".sql")] = stmt } return s, nil } func cleanseQuery(s string) string { var cleansed []string for _, line := range strings.Split(s, "\n") { line := strings.TrimSpace(line) if !strings.HasPrefix(line, "--") { cleansed = append(cleansed, line) } } return strings.Join(cleansed, "\n") }