compile.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. package compiler
  2. import (
  3. "errors"
  4. "fmt"
  5. "io"
  6. "os"
  7. "path/filepath"
  8. "regexp"
  9. "strings"
  10. "github.com/kyleconroy/sqlc/internal/metadata"
  11. "github.com/kyleconroy/sqlc/internal/migrations"
  12. "github.com/kyleconroy/sqlc/internal/multierr"
  13. "github.com/kyleconroy/sqlc/internal/opts"
  14. "github.com/kyleconroy/sqlc/internal/sql/ast"
  15. "github.com/kyleconroy/sqlc/internal/sql/sqlerr"
  16. "github.com/kyleconroy/sqlc/internal/sql/sqlpath"
  17. )
  18. // TODO: Rename this interface Engine
  19. type Parser interface {
  20. Parse(io.Reader) ([]ast.Statement, error)
  21. CommentSyntax() metadata.CommentSyntax
  22. IsReservedKeyword(string) bool
  23. }
  24. // copied over from gen.go
  25. func structName(name string) string {
  26. out := ""
  27. for _, p := range strings.Split(name, "_") {
  28. if p == "id" {
  29. out += "ID"
  30. } else {
  31. out += strings.Title(p)
  32. }
  33. }
  34. return out
  35. }
  36. var identPattern = regexp.MustCompile("[^a-zA-Z0-9_]+")
  37. func enumValueName(value string) string {
  38. name := ""
  39. id := strings.Replace(value, "-", "_", -1)
  40. id = strings.Replace(id, ":", "_", -1)
  41. id = strings.Replace(id, "/", "_", -1)
  42. id = identPattern.ReplaceAllString(id, "")
  43. for _, part := range strings.Split(id, "_") {
  44. name += strings.Title(part)
  45. }
  46. return name
  47. }
  48. // end copypasta
  49. func (c *Compiler) parseCatalog(schemas []string) error {
  50. files, err := sqlpath.Glob(schemas)
  51. if err != nil {
  52. return err
  53. }
  54. merr := multierr.New()
  55. for _, filename := range files {
  56. blob, err := os.ReadFile(filename)
  57. if err != nil {
  58. merr.Add(filename, "", 0, err)
  59. continue
  60. }
  61. contents := migrations.RemoveRollbackStatements(string(blob))
  62. stmts, err := c.parser.Parse(strings.NewReader(contents))
  63. if err != nil {
  64. merr.Add(filename, contents, 0, err)
  65. continue
  66. }
  67. for i := range stmts {
  68. if err := c.catalog.Update(stmts[i], c); err != nil {
  69. merr.Add(filename, contents, stmts[i].Pos(), err)
  70. continue
  71. }
  72. }
  73. }
  74. if len(merr.Errs()) > 0 {
  75. return merr
  76. }
  77. return nil
  78. }
  79. func (c *Compiler) parseQueries(o opts.Parser) (*Result, error) {
  80. var q []*Query
  81. merr := multierr.New()
  82. set := map[string]struct{}{}
  83. files, err := sqlpath.Glob(c.conf.Queries)
  84. if err != nil {
  85. return nil, err
  86. }
  87. for _, filename := range files {
  88. blob, err := os.ReadFile(filename)
  89. if err != nil {
  90. merr.Add(filename, "", 0, err)
  91. continue
  92. }
  93. src := string(blob)
  94. stmts, err := c.parser.Parse(strings.NewReader(src))
  95. if err != nil {
  96. merr.Add(filename, src, 0, err)
  97. continue
  98. }
  99. for _, stmt := range stmts {
  100. query, err := c.parseQuery(stmt.Raw, src, o)
  101. if err == ErrUnsupportedStatementType {
  102. continue
  103. }
  104. if err != nil {
  105. var e *sqlerr.Error
  106. loc := stmt.Raw.Pos()
  107. if errors.As(err, &e) && e.Location != 0 {
  108. loc = e.Location
  109. }
  110. merr.Add(filename, src, loc, err)
  111. continue
  112. }
  113. if query.Name != "" {
  114. if _, exists := set[query.Name]; exists {
  115. merr.Add(filename, src, stmt.Raw.Pos(), fmt.Errorf("duplicate query name: %s", query.Name))
  116. continue
  117. }
  118. set[query.Name] = struct{}{}
  119. }
  120. query.Filename = filepath.Base(filename)
  121. if query != nil {
  122. q = append(q, query)
  123. }
  124. }
  125. }
  126. if len(merr.Errs()) > 0 {
  127. return nil, merr
  128. }
  129. if len(q) == 0 {
  130. return nil, fmt.Errorf("no queries contained in paths %s", strings.Join(c.conf.Queries, ","))
  131. }
  132. return &Result{
  133. Catalog: c.catalog,
  134. Queries: q,
  135. }, nil
  136. }