compile.go 3.3 KB

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