queries.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. package main
  2. import (
  3. "context"
  4. "database/sql"
  5. "fmt"
  6. "github.com/jmoiron/sqlx"
  7. "github.com/lib/pq"
  8. )
  9. // Queries contains all prepared SQL queries.
  10. type Queries struct {
  11. GetDashboardStats *sqlx.Stmt `query:"get-dashboard-stats"`
  12. InsertSubscriber *sqlx.Stmt `query:"insert-subscriber"`
  13. UpsertSubscriber *sqlx.Stmt `query:"upsert-subscriber"`
  14. UpsertBlacklistSubscriber *sqlx.Stmt `query:"upsert-blacklist-subscriber"`
  15. GetSubscriber *sqlx.Stmt `query:"get-subscriber"`
  16. GetSubscribersByEmails *sqlx.Stmt `query:"get-subscribers-by-emails"`
  17. GetSubscriberLists *sqlx.Stmt `query:"get-subscriber-lists"`
  18. UpdateSubscriber *sqlx.Stmt `query:"update-subscriber"`
  19. BlacklistSubscribers *sqlx.Stmt `query:"blacklist-subscribers"`
  20. AddSubscribersToLists *sqlx.Stmt `query:"add-subscribers-to-lists"`
  21. DeleteSubscriptions *sqlx.Stmt `query:"delete-subscriptions"`
  22. UnsubscribeSubscribersFromLists *sqlx.Stmt `query:"unsubscribe-subscribers-from-lists"`
  23. DeleteSubscribers *sqlx.Stmt `query:"delete-subscribers"`
  24. Unsubscribe *sqlx.Stmt `query:"unsubscribe"`
  25. // Non-prepared arbitrary subscriber queries.
  26. QuerySubscribers string `query:"query-subscribers"`
  27. QuerySubscribersTpl string `query:"query-subscribers-template"`
  28. DeleteSubscribersByQuery string `query:"delete-subscribers-by-query"`
  29. AddSubscribersToListsByQuery string `query:"add-subscribers-to-lists-by-query"`
  30. BlacklistSubscribersByQuery string `query:"blacklist-subscribers-by-query"`
  31. DeleteSubscriptionsByQuery string `query:"delete-subscriptions-by-query"`
  32. UnsubscribeSubscribersFromListsByQuery string `query:"unsubscribe-subscribers-from-lists-by-query"`
  33. CreateList *sqlx.Stmt `query:"create-list"`
  34. GetLists *sqlx.Stmt `query:"get-lists"`
  35. UpdateList *sqlx.Stmt `query:"update-list"`
  36. DeleteLists *sqlx.Stmt `query:"delete-lists"`
  37. CreateCampaign *sqlx.Stmt `query:"create-campaign"`
  38. QueryCampaigns *sqlx.Stmt `query:"query-campaigns"`
  39. GetCampaign *sqlx.Stmt `query:"get-campaign"`
  40. GetCampaignForPreview *sqlx.Stmt `query:"get-campaign-for-preview"`
  41. GetCampaignStats *sqlx.Stmt `query:"get-campaign-stats"`
  42. GetCampaignStatus *sqlx.Stmt `query:"get-campaign-status"`
  43. NextCampaigns *sqlx.Stmt `query:"next-campaigns"`
  44. NextCampaignSubscribers *sqlx.Stmt `query:"next-campaign-subscribers"`
  45. GetOneCampaignSubscriber *sqlx.Stmt `query:"get-one-campaign-subscriber"`
  46. UpdateCampaign *sqlx.Stmt `query:"update-campaign"`
  47. UpdateCampaignStatus *sqlx.Stmt `query:"update-campaign-status"`
  48. UpdateCampaignCounts *sqlx.Stmt `query:"update-campaign-counts"`
  49. RegisterCampaignView *sqlx.Stmt `query:"register-campaign-view"`
  50. DeleteCampaign *sqlx.Stmt `query:"delete-campaign"`
  51. CreateUser *sqlx.Stmt `query:"create-user"`
  52. GetUsers *sqlx.Stmt `query:"get-users"`
  53. UpdateUser *sqlx.Stmt `query:"update-user"`
  54. DeleteUser *sqlx.Stmt `query:"delete-user"`
  55. InsertMedia *sqlx.Stmt `query:"insert-media"`
  56. GetMedia *sqlx.Stmt `query:"get-media"`
  57. DeleteMedia *sqlx.Stmt `query:"delete-media"`
  58. CreateTemplate *sqlx.Stmt `query:"create-template"`
  59. GetTemplates *sqlx.Stmt `query:"get-templates"`
  60. UpdateTemplate *sqlx.Stmt `query:"update-template"`
  61. SetDefaultTemplate *sqlx.Stmt `query:"set-default-template"`
  62. DeleteTemplate *sqlx.Stmt `query:"delete-template"`
  63. CreateLink *sqlx.Stmt `query:"create-link"`
  64. RegisterLinkClick *sqlx.Stmt `query:"register-link-click"`
  65. // GetStats *sqlx.Stmt `query:"get-stats"`
  66. }
  67. // connectDB initializes a database connection.
  68. func connectDB(host string, port int, user, pwd, dbName string) (*sqlx.DB, error) {
  69. db, err := sqlx.Connect("postgres",
  70. fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s", host, port, user, pwd, dbName))
  71. if err != nil {
  72. return nil, err
  73. }
  74. return db, nil
  75. }
  76. // compileSubscriberQueryTpl takes a arbitrary WHERE expressions
  77. // to filter subscribers from the subscribers table and prepares a query
  78. // out of it using the raw `query-subscribers-template` query template.
  79. // While doing this, a readonly transaction is created and the query is
  80. // dry run on it to ensure that it is indeed readonly.
  81. func (q *Queries) compileSubscriberQueryTpl(exp string, db *sqlx.DB) (string, error) {
  82. tx, err := db.BeginTxx(context.Background(), &sql.TxOptions{ReadOnly: true})
  83. if err != nil {
  84. return "", err
  85. }
  86. // Perform the dry run.
  87. if exp != "" {
  88. exp = " AND " + exp
  89. }
  90. stmt := fmt.Sprintf(q.QuerySubscribersTpl, exp)
  91. if _, err := tx.Exec(stmt, true, pq.Int64Array{}); err != nil {
  92. tx.Rollback()
  93. return "", err
  94. }
  95. return stmt, nil
  96. }
  97. // compileSubscriberQueryTpl takes a arbitrary WHERE expressions and a subscriber
  98. // query template that depends on the filter (eg: delete by query, blacklist by query etc.)
  99. // combines and executes them.
  100. func (q *Queries) execSubscriberQueryTpl(exp, tpl string, listIDs []int64, db *sqlx.DB, args ...interface{}) error {
  101. // Perform a dry run.
  102. filterExp, err := q.compileSubscriberQueryTpl(exp, db)
  103. if err != nil {
  104. return err
  105. }
  106. if len(listIDs) == 0 {
  107. listIDs = pq.Int64Array{}
  108. }
  109. // First argument is the boolean indicating if the query is a dry run.
  110. a := append([]interface{}{false, pq.Int64Array(listIDs)}, args...)
  111. if _, err := db.Exec(fmt.Sprintf(tpl, filterExp), a...); err != nil {
  112. return err
  113. }
  114. return nil
  115. }