рдЧреЛрд▓рдВрдЧ рдбреЗрдЯрд╛рдмреЗрд╕-рдЖрдзрд╛рд░рд┐рдд рдХреНрд▓рд╛рдЗрдВрдЯ рдЬреЗрдирд░реЗрдЯрд░ рдЗрдВрдЯрд░рдлрд╝реЗрд╕

рдЧреЛрд▓рд╛рдВрдЧ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреНрд▓рд╛рдЗрдВрдЯ рдЬрдирд░реЗрдЯрд░ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдкрд░ рдЖрдзрд╛рд░рд┐рдд рд╣реИред



рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЧреЛрд▓рд╛рдВрдЧ database/sql рдкреИрдХреЗрдЬ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ, рдЬреЛ рд░рд┐рд▓реЗрд╢рдирд▓ рдбреЗрдЯрд╛рдмреЗрд╕ рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рдЗрдВрдЯрд░рдлреЗрд╕ рдХрд╛ рдПрдХ рдЕрдореВрд░реНрдд рд╣рд┐рд╕реНрд╕рд╛ рд╣реИред рдПрдХ рддрд░рдл, рдкреИрдХреЗрдЬ рдореЗрдВ рдХрдиреЗрдХреНрд╢рди рдкреВрд▓ рдХреЗ рдкреНрд░рдмрдВрдзрди рдХреЗ рд▓рд┐рдП рд╢рдХреНрддрд┐рд╢рд╛рд▓реА рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛, рддреИрдпрд╛рд░ рдХрд┐рдП рдЧрдП рдмрдпрд╛рдиреЛрдВ, рд▓реЗрдирджреЗрди рдФрд░ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреНрд╡реЗрд░реА рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдирд╛ рд╢рд╛рдорд┐рд▓ рд╣реИред рджреВрд╕рд░реА рдУрд░, рдЖрдкрдХреЛ рдПрдХ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЗ рд╕рд╛рде рдмрд╛рддрдЪреАрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╡реЗрдм рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЗрдВ рдПрдХ рд╣реА рдкреНрд░рдХрд╛рд░ рдХреЗ рдХреЛрдб рдХреА рдХрд╛рдлреА рдорд╛рддреНрд░рд╛ рд▓рд┐рдЦрдиреА рд╣реЛрдЧреАред рдЧреЛ-рдЧреИрдЬреЗрдЯ / рд╕реИрд▓ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рд╡рд░реНрдгрд┐рдд рдЗрдВрдЯрд░рдлреЗрд╕ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдПрдХ рд╣реА рдкреНрд░рдХрд╛рд░ рдХреЗ рдХреЛрдб рдХреЛ рдЬреЗрдирд░реЗрдЯ рдХрд░рдиреЗ рдХреЗ рд░реВрдк рдореЗрдВ рдПрдХ рд╕рдорд╛рдзрд╛рди рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред


рдкреНрд░реЗрд░рдгрд╛


рдЖрдЬ рдкрд░реНрдпрд╛рдкреНрдд рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рдкреБрд╕реНрддрдХрд╛рд▓рдп рд╣реИрдВ рдЬреЛ ORMs рдХреЗ рд░реВрдк рдореЗрдВ рд╕рдорд╛рдзрд╛рди рдкреНрд░рд╕реНрддреБрдд рдХрд░рддреЗ рд╣реИрдВ, рдкреНрд░рд╢реНрдиреЛрдВ рдХреЗ рдирд┐рд░реНрдорд╛рдг рдХреЗ рд▓рд┐рдП рд╕рд╣рд╛рдпрдХ, рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реНрдХреАрдорд╛ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рд╕рд╣рд╛рдпрдХреЛрдВ рдХреЛ рдЙрддреНрдкрдиреНрди рдХрд░рддреЗ рд╣реИрдВред



рдЬрдм рдореИрдВрдиреЗ рдХрдИ рд╕рд╛рд▓ рдкрд╣рд▓реЗ рдЧреЛрд▓рд╛рдВрдЧ рднрд╛рд╖рд╛ рдореЗрдВ рд╕реНрд╡рд┐рдЪ рдХрд┐рдпрд╛, рддреЛ рдореБрдЭреЗ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рд╡рд┐рднрд┐рдиреНрди рднрд╛рд╖рд╛рдУрдВ рдореЗрдВ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХрд╛ рдЕрдиреБрднрд╡ рдерд╛ред ORM рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛, рдЬреИрд╕реЗ рдХрд┐ ActiveRecord, рдФрд░ рдмрд┐рдирд╛ред рдкреНрд░реЗрдо рд╕реЗ рдШреГрдгрд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдХреЛрдб рдХреА рдХреБрдЫ рдЕрддрд┐рд░рд┐рдХреНрдд рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХреЛ рд▓рд┐рдЦрдиреЗ рдореЗрдВ рдХреЛрдИ рд╕рдорд╕реНрдпрд╛ рдирд╣реАрдВ рд╣реИ, рдЧреЛрд▓рдВрдЧ рдореЗрдВ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЗ рд╕рд╛рде рдмрд╛рддрдЪреАрдд рдХрд░рдирд╛ рдПрдХ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдкреИрдЯрд░реНрди рдЬреИрд╕реА рдЪреАрдЬ рдХреЗ рд╕рд╛рде рдЖрдпрд╛ред рд╣рдо рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рддреЗ рд╣реИрдВ, рд╣рдо рдЗрд╕реЗ рдорд╛рдирдХ db.Query, row.Scan рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд▓рд╛рдЧреВ рдХрд░рддреЗ рд╣реИрдВред рдЕрддрд┐рд░рд┐рдХреНрдд рд░реИрдкрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрд╕ рд╕рдордЭ рдореЗрдВ рдирд╣реАрдВ рдЖрдпрд╛, рдпрд╣ рдЕрдкрд╛рд░рджрд░реНрд╢реА рдерд╛, рдпрд╣ рдЕрд▓рд░реНрдЯ рдкрд░ рд░рд╣рдиреЗ рдХреЗ рд▓рд┐рдП рдордЬрдмреВрд░ рдХрд░реЗрдЧрд╛ред


SQL рднрд╛рд╖рд╛ рд╣реА рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдЖрдкрдХреЗ рдкреНрд░реЛрдЧреНрд░рд╛рдо рдФрд░ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдХреЗ рдбреЗрдЯрд╛ рдХреЗ рдмреАрдЪ рдПрдХ рдЕрдореВрд░реНрдд рд╣реИред рдпрд╣ рд╣рдореЗрд╢рд╛ рдореБрдЭреЗ рдПрдХ рдбреЗрдЯрд╛ рдпреЛрдЬрдирд╛ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдФрд░ рдлрд┐рд░ рдЬрдЯрд┐рд▓ рдкреНрд░рд╢реНрдиреЛрдВ рдХрд╛ рдирд┐рд░реНрдорд╛рдг рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрддрд╛рд░реНрдХрд┐рдХ рд▓рдЧрд╛ред рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рд╕рдВрд░рдЪрдирд╛ рдбреЗрдЯрд╛ рдпреЛрдЬрдирд╛ рд╕реЗ рдЕрд▓рдЧ рд╣реИред рдпрд╣ рдкрддрд╛ рдЪрд▓рд╛ рд╣реИ рдХрд┐ рдЕрдиреБрдмрдВрдз рдХреЛ рдбреЗрдЯрд╛ рдпреЛрдЬрдирд╛ рдХреЗ рд╕реНрддрд░ рдкрд░ рдирд╣реАрдВ, рдмрд▓реНрдХрд┐ рдЕрдиреБрд░реЛрдз рдФрд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХреЗ рд╕реНрддрд░ рдкрд░ рд╡рд░реНрдгрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред рд╣рдо рд╡реЗрдм рд╡рд┐рдХрд╛рд╕ рдореЗрдВ рдЗрд╕ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ рдЬрдм рд╣рдо рдПрдкреАрдЖрдИ рдЕрдиреБрд░реЛрдзреЛрдВ рдФрд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛рдУрдВ рдХреА рдбреЗрдЯрд╛ рд╕рдВрд░рдЪрдирд╛рдУрдВ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рддреЗ рд╣реИрдВред RESTful JSON рдпрд╛ gRPC рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП рд╕реЗрд╡рд╛ рддрдХ рдкрд╣реБрдБрдЪрдиреЗ рдкрд░, рд╣рдо JSON рд╕реНрдХреАрдорд╛ рдпрд╛ рдкреНрд░реЛрдЯреЛрдмреЙрдлрд╝ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЕрдиреБрд░реЛрдз рдФрд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рд╕реНрддрд░ рдкрд░ рдЕрдиреБрдмрдВрдз рдХреА рдШреЛрд╖рдгрд╛ рдХрд░рддреЗ рд╣реИрдВ, рди рдХрд┐ рд╕реЗрд╡рд╛рдУрдВ рдХреЗ рдЕрдВрджрд░ рд╕рдВрд╕реНрдерд╛рдУрдВ рдХреЗ рдбреЗрдЯрд╛ рд╕реНрдХреАрдорд╛ рдХрд╛ред


рдпрд╣реА рд╣реИ, рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЗ рд╕рд╛рде рдмрд╛рддрдЪреАрдд рдПрдХ рд╕рдорд╛рди рд╡рд┐рдзрд┐ рдХреЗ рд▓рд┐рдП рдиреАрдЪреЗ рдЖрдпрд╛:


 type User struct { ID int64 Name string } type Store interface { FindUser(id int64) (*User, error) } type Postgres struct { DB *sql.DB } func (pg *Postgres) FindUser(id int64) (*User, error) { var resp User err := pg.DB.QueryRow("SELECT id, name FROM users WHERE id=$1", id).Scan(&resp.ID, &resp.Name) if err != nil { return nil, err } return &resp, nil } func HanlderFindUser(s Store, id int) (*User, error) { // logic of service object user, err := s.FindUser(id) //... } 

рдпрд╣ рддрд░реАрдХрд╛ рдЖрдкрдХреЗ рдкреНрд░реЛрдЧреНрд░рд╛рдо рдХреЛ рдкреНрд░реЗрдбрд┐рдХреНрдЯреЗрдмрд▓ рдмрдирд╛рддрд╛ рд╣реИред рд▓реЗрдХрд┐рди рд╕рдЪ рдХрд╣реВрдВ рддреЛ рдпрд╣ рдХрд╡рд┐ рдХрд╛ рд╕рдкрдирд╛ рдирд╣реАрдВ рд╣реИред рд╣рдо рдХреНрд╡реЗрд░реА рдмрдирд╛рдиреЗ, рдбреЗрдЯрд╛ рд╕рдВрд░рдЪрдирд╛рдУрдВ рдХреЛ рдкреЙрдкреНрдпреБрд▓реЗрдЯ рдХрд░рдиреЗ, рд╡реИрд░рд┐рдПрдмрд▓ рдмрд╛рдЗрдВрдбрд┐рдВрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдЖрджрд┐ рдХреЗ рд▓рд┐рдП рдмреЙрдпрд▓рд░рдкреНрд▓реЗрдЯ рдХреЛрдб рдХреА рдорд╛рддреНрд░рд╛ рдХреЛ рдХрдо рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред рдореИрдВрдиреЗ рдЖрд╡рд╢реНрдпрдХрддрд╛рдУрдВ рдХреА рдПрдХ рд╕реВрдЪреА рддреИрдпрд╛рд░ рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХреА рд╣реИ рдХрд┐ рдЙрдкрдпреЛрдЧрд┐рддрд╛рдУрдВ рдХреЗ рд╡рд╛рдВрдЫрд┐рдд рд╕реЗрдЯ рдХреЛ рд╕рдВрддреБрд╖реНрдЯ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред


рдЖрд╡рд╢реНрдпрдХрддрд╛рдПрдБ


  • рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЗ рд░реВрдк рдореЗрдВ рдмрд╛рддрдЪреАрдд рдХрд╛ рд╡рд┐рд╡рд░рдгред
  • рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдЕрдиреБрд░реЛрдзреЛрдВ рдФрд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛рдУрдВ рдХреЗ рддрд░реАрдХреЛрдВ рдФрд░ рд╕рдВрджреЗрд╢реЛрдВ рджреНрд╡рд╛рд░рд╛ рд╡рд░реНрдгрд┐рдд рд╣реИред
  • рд╡реИрд░рд┐рдПрдмрд▓ рдФрд░ рддреИрдпрд╛рд░ рдмрдпрд╛рдиреЛрдВ рдХреЗ рд▓рд┐рдП рд╕рдорд░реНрдердиред
  • рдирд╛рдорд┐рдд рддрд░реНрдХ рдХреЗ рд▓рд┐рдП рд╕рдорд░реНрдердиред
  • рд╕рдВрджреЗрд╢ рдбреЗрдЯрд╛ рд╕рдВрд░рдЪрдирд╛ рдХреЗ рдХреНрд╖реЗрддреНрд░ рдореЗрдВ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреА рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХреЛ рдЬреЛрдбрд╝рдирд╛ред
  • Atypical рдбреЗрдЯрд╛ рд╕рдВрд░рдЪрдирд╛рдУрдВ (рд╕рд░рдгреА, json) рдХреЗ рд▓рд┐рдП рд╕рдорд░реНрдердиред
  • рд▓реЗрди-рджреЗрди рдХреЗ рд╕рд╛рде рдкрд╛рд░рджрд░реНрд╢реА рдХрд╛рдоред
  • рдорд┐рдбрд▓рд╡реЗрдпрд░ рдХреЗ рд▓рд┐рдП рдореВрд▓ рд╕рдорд░реНрдердиред

рд╣рдо рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЗ рд╕рд╛рде рдЗрдВрдЯрд░реИрдХреНрд╢рди рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЛ рдЕрдореВрд░реНрдд рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред рдпрд╣ рд╣рдореЗрдВ рдбрд┐рдЬрд╛рдЗрди рдкреИрдЯрд░реНрди рдЬреИрд╕реЗ рдХрд┐ рднрдВрдбрд╛рд░ рдХреЗ рд╕рдорд╛рди рдХреБрдЫ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрдЧрд╛ред рдКрдкрд░ рдХреЗ рдЙрджрд╛рд╣рд░рдг рдореЗрдВ, рд╣рдордиреЗ рд╕реНрдЯреЛрд░ рдЗрдВрдЯрд░рдлреЗрд╕ рдХрд╛ рд╡рд░реНрдгрди рдХрд┐рдпрд╛ред рдЕрдм рд╣рдо рдЗрд╕реЗ рдПрдХ рдирд┐рд░реНрднрд░рддрд╛ рдХреЗ рд░реВрдк рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдкрд░реАрдХреНрд╖рдг рдХреЗ рдЪрд░рдг рдореЗрдВ, рд╣рдо рдЗрд╕ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдЙрддреНрдкрдиреНрди рдПрдХ рд╕реНрдЯрдм рдкрд╛рд╕ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдФрд░ рдЙрддреНрдкрд╛рдж рдореЗрдВ рд╣рдо рдкреЛрд╕реНрдЯрдЧреНрд░реЗрдЬ рд╕рдВрд░рдЪрдирд╛ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рд╣рдорд╛рд░реЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред


рдкреНрд░рддреНрдпреЗрдХ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рд╡рд┐рдзрд┐ рдПрдХ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреНрд╡реЗрд░реА рдХрд╛ рд╡рд░реНрдгрди рдХрд░рддреА рд╣реИред рдЕрдиреБрд░реЛрдз рдХреЗ рд▓рд┐рдП рд╡рд┐рдзрд┐ рдХрд╛ рдЗрдирдкреБрдЯ рдФрд░ рдЖрдЙрдЯрдкреБрдЯ рдкреИрд░рд╛рдореАрдЯрд░ рдЕрдиреБрдмрдВрдз рдХрд╛ рд╣рд┐рд╕реНрд╕рд╛ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред рдЗрдирдкреБрдЯ рдорд╛рдкрджрдВрдбреЛрдВ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдХреНрд╡реЗрд░реА рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЛ рдкреНрд░рд╛рд░реВрдкрд┐рдд рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред рдЬрдЯрд┐рд▓ рдирдореВрдирд╛рдХрд░рдг рд╕реНрдерд┐рддрд┐ рдХреЗ рд╕рд╛рде рдкреНрд░рд╢реНрдиреЛрдВ рдХрд╛ рд╕рдВрдХрд▓рди рдХрд░рддреЗ рд╕рдордп рдпрд╣ рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рд╕рдЪ рд╣реИред


рдХреНрд╡реЗрд░реА рдХрд╛ рд╕рдВрдХрд▓рди рдХрд░рддреЗ рд╕рдордп, рд╣рдо рдкреНрд░рддрд┐рд╕реНрдерд╛рдкрди рдФрд░ рдЪрд░ рдмрдВрдзрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, PostgreSQL рдореЗрдВ, рдЖрдк рдореВрд▓реНрдп рдХреЗ рдмрдЬрд╛рдп $1 рд▓рд┐рдЦрддреЗ рд╣реИрдВ, рдФрд░ рдХреНрд╡реЗрд░реА рдХреЗ рд╕рд╛рде, рддрд░реНрдХреЛрдВ рдХрд╛ рдПрдХ рд╕рд░рдгреА рдкрд╛рд╕ рдХрд░рддреЗ рд╣реИрдВред рдкрд╣рд▓реЗ рддрд░реНрдХ рдХреЛ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рдХреНрд╡реЗрд░реА рдореЗрдВ рдорд╛рди рдХреЗ рд░реВрдк рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рддреИрдпрд╛рд░ рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП рд╕рдорд░реНрдерди рдЖрдкрдХреЛ рдЗрди рд╕рдорд╛рди рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐рдпреЛрдВ рдХреЗ рднрдВрдбрд╛рд░рдг рдХреЗ рдЖрдпреЛрдЬрди рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЪрд┐рдВрддрд╛ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рдирд╣реАрдВ рджреЗрддрд╛ рд╣реИред рдбреЗрдЯрд╛рдмреЗрд╕ / рдПрд╕рдХреНрдпреВрдПрд▓ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рддреИрдпрд╛рд░ рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐рдпреЛрдВ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╢рдХреНрддрд┐рд╢рд╛рд▓реА рдЙрдкрдХрд░рдг рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ, рдпрд╣ рд╕реНрд╡рдпрдВ рдХрдиреЗрдХреНрд╢рди рдкреВрд▓, рдмрдВрдж рдХрдиреЗрдХреНрд╢рди рдХрд╛ рдЦреНрдпрд╛рд▓ рд░рдЦрддрд╛ рд╣реИред рд▓реЗрдХрд┐рди рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреА рдУрд░ рд╕реЗ, рд▓реЗрдирджреЗрди рдореЗрдВ рддреИрдпрд╛рд░ рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рдХрд╛ рдкреБрди: рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдЕрддрд┐рд░рд┐рдХреНрдд рдХрд╛рд░реНрд░рд╡рд╛рдИ рдЖрд╡рд╢реНрдпрдХ рд╣реИред


рдбреЗрдЯрд╛рдмреЗрд╕, рдЬреИрд╕реЗ PostgreSQL рдФрд░ MySQL, рдкреНрд░рддрд┐рд╕реНрдерд╛рдкрди рдФрд░ рдЪрд░ рдмрд╛рдЗрдВрдбрд┐рдВрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрд▓рдЧ-рдЕрд▓рдЧ рд╕рд┐рдВрдЯреИрдХреНрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВред PostgreSQL $1 , $2 , ... MySQL рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ ? рдореВрд▓реНрдп рдХреЗ рд╕реНрдерд╛рди рдХреА рдкрд░рд╡рд╛рд╣ рдХрд┐рдП рдмрд┐рдирд╛ред рдбреЗрдЯрд╛рдмреЗрд╕ / рдПрд╕рдХреНрдпреВрдПрд▓ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдиреЗ рдирд╛рдорд┐рдд рддрд░реНрдХреЛрдВ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рд╛рд░реНрд╡рднреМрдорд┐рдХ рдкреНрд░рд╛рд░реВрдк рдХрд╛ рдкреНрд░рд╕реНрддрд╛рд╡ рджрд┐рдпрд╛ https://golang.org/pkg/database/sql/#NamedArg ред рдЙрдкрдпреЛрдЧ рдЙрджрд╛рд╣рд░рдг:


 db.ExecContext(ctx, `DELETE FROM orders WHERE created_at < @end`, sql.Named("end", endTime)) 

PostgreSQL рдпрд╛ MySQL рд╕рдорд╛рдзрд╛рдиреЛрдВ рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рдЗрд╕ рдкреНрд░рд╛рд░реВрдк рдХреЗ рд▓рд┐рдП рд╕рдорд░реНрдерди рдмреЗрд╣рддрд░ рд╣реИред


рд╕реЙрдлрд╝реНрдЯрд╡реЗрдпрд░ рдбреНрд░рд╛рдЗрд╡рд░ рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХреЛ рдирд┐рдореНрдирд╛рдиреБрд╕рд╛рд░ рд╕рд╢рд░реНрдд рд░реВрдк рд╕реЗ рджрд░реНрд╢рд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ:


 dev > SELECT * FROM rubrics; id | created_at | title | url ----+-------------------------+-------+------------ 1 | 2012-03-13 11:17:23.609 | Tech | technology 2 | 2015-07-21 18:05:43.412 | Style | fashion (2 rows) 

рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рд╕реНрддрд░ рдкрд░ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЗ рджреГрд╖реНрдЯрд┐рдХреЛрдг рд╕реЗ, рдкреНрд░рдкрддреНрд░ рдХреА рд╕рдВрд░рдЪрдирд╛рдУрдВ рдХреА рдПрдХ рд╕рд░рдгреА рдХреЗ рд░реВрдк рдореЗрдВ рдЖрдЙрдЯрдкреБрдЯ рдкреИрд░рд╛рдореАрдЯрд░ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдирд╛ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реИ:


 type GetRubricsResp struct { ID int CreatedAt time.Time Title string URL string } 

рдЕрдЧрд▓рд╛, resp.ID рдкрд░ id рд╡реИрд▓реНрдпреВ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдХрд░реЗрдВред рд╕рд╛рдорд╛рдиреНрдп рддреМрд░ рдкрд░, рдпрд╣ рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рд╕рдмрд╕реЗ рдЕрдзрд┐рдХ рдЬрд░реВрд░рддреЛрдВ рдХреЛ рдХрд╡рд░ рдХрд░рддреА рд╣реИред


рдЖрдВрддрд░рд┐рдХ рдбреЗрдЯрд╛ рд╕рдВрд░рдЪрдирд╛рдУрдВ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╕рдВрджреЗрд╢реЛрдВ рдХреА рдШреЛрд╖рдгрд╛ рдХрд░рддреЗ рд╕рдордп, рд╕рд╡рд╛рд▓ рдЙрдарддрд╛ рд╣реИ рдХрд┐ рдЧреИрд░-рдорд╛рдирдХ рдбреЗрдЯрд╛ рдкреНрд░рдХрд╛рд░реЛрдВ рдХрд╛ рд╕рдорд░реНрдерди рдХреИрд╕реЗ рдХрд░реЗрдВред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдПрдХ рд╕рд░рдгреАред рдпрджрд┐ рдЖрдк PostgreSQL рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рддреЗ рд╕рдордп github.com/lib/pq рдбреНрд░рд╛рдЗрд╡рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдЖрдк рдХреНрд╡реЗрд░реА рддрд░реНрдХ рдпрд╛ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХреЛ рд╕реНрдХреИрди рдХрд░рддреЗ рд╕рдордп pq.Array(&x) рдЬреИрд╕реЗ рд╕рд╣рд╛рдпрдХ рдХрд╛рд░реНрдпреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдкреНрд░рд▓реЗрдЦрди рд╕реЗ рдЙрджрд╛рд╣рд░рдг:


 db.Query(`SELECT * FROM t WHERE id = ANY($1)`, pq.Array([]int{235, 401})) var x []sql.NullInt64 db.QueryRow('SELECT ARRAY[235, 401]').Scan(pq.Array(&x)) 

рддрджрдиреБрд╕рд╛рд░, рдбреЗрдЯрд╛ рд╕рдВрд░рдЪрдирд╛рдУрдВ рдХреЛ рддреИрдпрд╛рд░ рдХрд░рдиреЗ рдХреЗ рддрд░реАрдХреЗ рд╣реЛрдиреЗ рдЪрд╛рд╣рд┐рдПред


рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЗ рдХрд┐рд╕реА рднреА рддрд░реАрдХреЗ рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рддреЗ рд╕рдордп, рдбреЗрдЯрд╛рдмреЗрд╕ рдХрдиреЗрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ *sql.DB рдХреЗ рд░реВрдк рдореЗрдВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдпрджрд┐ рдЖрдкрдХреЛ рдХрд┐рд╕реА рдПрдХрд▓ рд▓реЗрди-рджреЗрди рдХреЗ рднреАрддрд░ рдХрдИ рддрд░реАрдХреЛрдВ рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рддреЛ рдореИрдВ рдПрдХ рд▓реЗрдирджреЗрди рдХреЗ рдмрд╛рд╣рд░ рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рдорд╛рди рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХреЗ рд╕рд╛рде рдкрд╛рд░рджрд░реНрд╢реА рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ, рдЕрддрд┐рд░рд┐рдХреНрдд рддрд░реНрдХ рдкрд╛рд░рд┐рдд рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реВрдВред


рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рддреЗ рд╕рдордп, рдЯреВрд▓рдХрд┐рдЯ рдХреЛ рдПрдореНрдмреЗрдб рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛрдирд╛ рд╣рдорд╛рд░реЗ рд▓рд┐рдП рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рд╕рднреА рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЛ рд▓реЙрдЧ рдХрд░рдирд╛ред рдЯреВрд▓рдХрд┐рдЯ рдХреЛ рдЕрдиреБрд░реЛрдз рдЪрд░, рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рддреНрд░реБрдЯрд┐, рд░рдирдЯрд╛рдЗрдо, рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рд╡рд┐рдзрд┐ рдирд╛рдо рддрдХ рдкрд╣реБрдВрдЪ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреА рдЪрд╛рд╣рд┐рдПред


рдЕрдзрд┐рдХрд╛рдВрд╢ рднрд╛рдЧ рдХреЗ рд▓рд┐рдП, рдбреЗрдЯрд╛рдмреЗрд╕ рдкрд░рд┐рджреГрд╢реНрдпреЛрдВ рдХреЗ рд╡реНрдпрд╡рд╕реНрдерд┐рддрдХрд░рдг рдХреЗ рд░реВрдк рдореЗрдВ рдЖрд╡рд╢реНрдпрдХрддрд╛рдУрдВ рдХреЛ рддреИрдпрд╛рд░ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред


рд╕рдорд╛рдзрд╛рди: рдЧреЛ-рдЧреИрдЬреЗрдЯ / рд╕реИрд▓


рдмреЙрдпрд▓рд░рдкреНрд▓реЗрдЯ рдХреЛрдб рд╕реЗ рдирд┐рдкрдЯрдиреЗ рдХрд╛ рдПрдХ рддрд░реАрдХрд╛ рдЗрд╕реЗ рдЙрддреНрдкрдиреНрди рдХрд░рдирд╛ рд╣реИред рд╕реМрднрд╛рдЧреНрдп рд╕реЗ, рдЧреЛрд▓рдВрдЧ рдХреЗ рдкрд╛рд╕ рдЗрд╕ https://blog.golang.org/generate рдХреЗ рдЙрдкрдХрд░рдг рдФрд░ рдЙрджрд╛рд╣рд░рдг рд╣реИрдВред GoMock рдХреЗ https://github.com/golang/mock рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХреЛ рдкреАрдврд╝реА рдХреЗ рд▓рд┐рдП рдПрдХ рд╡рд╛рд╕реНрддреБ рд╕рдорд╛рдзрд╛рди рдХреЗ рд░реВрдк рдореЗрдВ рд▓рд┐рдпрд╛ рдЧрдпрд╛ рдерд╛, рдЬрд╣рд╛рдВ рдкреНрд░рддрд┐рдмрд┐рдВрдм рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдЗрд╕ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХреЗ рдЖрдзрд╛рд░ рдкрд░, рдЖрд╡рд╢реНрдпрдХрддрд╛рдУрдВ рдХреЗ рдЕрдиреБрд╕рд╛рд░, рд╕реИрд▓реНрдЬреЗрди рдЙрдкрдпреЛрдЧрд┐рддрд╛ рдФрд░ рд╕реИрд▓ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХреЛ рд▓рд┐рдЦрд╛ рдЧрдпрд╛ рдерд╛, рдЬреЛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЛрдб рдЙрддреНрдкрдиреНрди рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рд╕рд╣рд╛рдпрдХ рдХрд╛рд░реНрдпреЛрдВ рдХрд╛ рдПрдХ рд╕реЗрдЯ рдкреНрд░рджрд╛рди рдХрд░рддреЗ рд╣реИрдВред


рдЗрд╕ рд╕рдорд╛рдзрд╛рди рдХрд╛ рдЙрдкрдпреЛрдЧ рд╢реБрд░реВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЗ рд╕рд╛рде рд╕рд╣рднрд╛рдЧрд┐рддрд╛ рдкрд░рдд рдХреЗ рд╡реНрдпрд╡рд╣рд╛рд░ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реИред рдЬрд╛рдиреЗ рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░реЗрдВ go:generate рдирд┐рд░реНрджреЗрд╢реЛрдВ рдХреЗ рдПрдХ рд╕реЗрдЯ рдХреЗ рд╕рд╛рде рдирд┐рд░реНрджреЗрд╢ go:generate рдХрд░реЗрдВ рдФрд░ рдкреАрдврд╝реА рд╢реБрд░реВ рдХрд░реЗрдВред рдЖрдкрдХреЛ рдПрдХ рдХрдВрд╕реНрдЯреНрд░рдХреНрдЯрд░ рдФрд░ рдмреЙрдпрд▓рд░рдкреНрд▓реЗрдЯ рдХреЛрдб рдХрд╛ рдПрдХ рдЧреБрдЪреНрдЫрд╛ рдорд┐рд▓реЗрдЧрд╛, рдЬреЛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рддреИрдпрд╛рд░ рд╣реИред


 package repo import "context" //go:generate salgen -destination=./postgres_client.go -package=dev/taxi/repo dev/taxi/repo Postgres type Postgres interface { CreateDriver(ctx context.Context, r *CreateDriverReq) error } type CreateDriverReq struct { taxi.Driver } func (r *CreateDriverReq) Query() string { return `INSERT INTO drivers(id, name) VALUES(@id, @name)` } 

рдЗрдВрдЯрд░рдлрд╝реЗрд╕


рдпрд╣ рд╕рдм рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдФрд░ go generate рдпреВрдЯрд┐рд▓рд┐рдЯреА рдХреЗ рд▓рд┐рдП рдПрдХ рд╡рд┐рд╢реЗрд╖ рдХрдорд╛рдВрдб рдХреА рдШреЛрд╖рдгрд╛ рдХреЗ рд╕рд╛рде рд╢реБрд░реВ рд╣реЛрддрд╛ рд╣реИ:


 //go:generate salgen -destination=./client.go -package=github.com/go-gad/sal/examples/profile/storage github.com/go-gad/sal/examples/profile/storage Store type Store interface { ... 

рдпрд╣рд╛рдВ рдпрд╣ рд╡рд░реНрдгрд┐рдд рд╣реИ рдХрд┐ рд╣рдорд╛рд░реЗ Store рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЗ рд▓рд┐рдП, рдХрдВрд╕реЛрд▓ рдЙрдкрдпреЛрдЧрд┐рддрд╛ salgen рдХреЛ рдкреИрдХреЗрдЬ рд╕реЗ рдмреБрд▓рд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛, рдЬрд┐рд╕рдореЗрдВ рджреЛ рд╡рд┐рдХрд▓реНрдк рдФрд░ рджреЛ рддрд░реНрдХ рд╣реЛрдВрдЧреЗред рдкрд╣рд▓рд╛ рд╡рд┐рдХрд▓реНрдк -destination рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдХрд┐рд╕ рдХреЛрдб рдореЗрдВ рдЬрдирд░реЗрдЯ рдХреЛрдб рд▓рд┐рдЦрд╛ рдЬрд╛рдПрдЧрд╛ред рджреВрд╕рд░рд╛ рд╡рд┐рдХрд▓реНрдк- -package рдЙрддреНрдкрдиреНрди рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рд▓рд┐рдП рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХреЗ рдкреВрд░реНрдг рдкрде (рдЖрдпрд╛рдд рдкрде) рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рддрд╛ рд╣реИред рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рджреЛ рддрд░реНрдХ рд╣реИрдВред рдкрд╣рд▓реЗ рдкреВрд░реНрдг рдкреИрдХреЗрдЬ рдкрде ( github.com/go-gad/sal/examples/profile/storage ) рдХрд╛ рд╡рд░реНрдгрди рдХрд░рддрд╛ рд╣реИ рдЬрд╣рд╛рдБ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рд╕реНрдерд┐рдд рд╣реИ, рджреВрд╕рд░рд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЗ рдирд╛рдо рдХреЛ рдЗрдВрдЧрд┐рдд рдХрд░рддрд╛ рд╣реИред рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ go generate рд▓рд┐рдП рдХрдорд╛рдВрдб рдХрд╣реАрдВ рднреА рд╕реНрдерд┐рдд рд╣реЛ рд╕рдХрддреА рд╣реИ, рдЬрд░реВрд░реА рдирд╣реАрдВ рдХрд┐ рд▓рдХреНрд╖реНрдп рдЗрдВрдЯрд░рдлреЗрд╕ рдХреЗ рдмрдЧрд▓ рдореЗрдВ рд╣реЛред


go generate рдХрдорд╛рдВрдб рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж, рд╣рдореЗрдВ рдПрдХ рдХрдВрд╕реНрдЯреНрд░рдХреНрдЯрд░ рдорд┐рд▓рддрд╛ рд╣реИ рдЬрд┐рд╕рдХрд╛ рдирд╛рдо рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдирд╛рдо рдореЗрдВ New рдЙрдкрд╕рд░реНрдЧ рдЬреЛрдбрд╝рдХрд░ рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рд╣реИред sal.QueryHandler рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЗ рдЕрдиреБрд░реВрдк рдПрдХ рдЖрд╡рд╢реНрдпрдХ рдкреИрд░рд╛рдореАрдЯрд░ рд▓реЗрддрд╛ рд╣реИ:


 type QueryHandler interface { QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) PrepareContext(ctx context.Context, query string) (*sql.Stmt, error) } 

рдпрд╣ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ *sql.DB рдСрдмреНрдЬреЗрдХреНрдЯ рд╕реЗ рдореЗрд▓ *sql.DB рд╣реИред


 connStr := "user=pqgotest dbname=pqgotest sslmode=verify-full" db, err := sql.Open("postgres", connStr) client := storage.NewStore(db) 

рддрд░реАрдХреЗ


рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рд╡рд┐рдзрд┐рдпрд╛рдБ рдЙрдкрд▓рдмреНрдз рдбреЗрдЯрд╛рдмреЗрд╕ рдХреНрд╡реЗрд░реА рдХреЗ рд╕реЗрдЯ рдХреЛ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рддреА рд╣реИрдВред


 type Store interface { CreateAuthor(ctx context.Context, req CreateAuthorReq) (CreateAuthorResp, error) GetAuthors(ctx context.Context, req GetAuthorsReq) ([]*GetAuthorsResp, error) UpdateAuthor(ctx context.Context, req *UpdateAuthorReq) error } 

  • рддрд░реНрдХреЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ рд╣рдореЗрд╢рд╛ рдХрдбрд╝рд╛рдИ рд╕реЗ рджреЛ рд╣реЛрддреА рд╣реИред
  • рдкрд╣рд▓рд╛ рддрд░реНрдХ рд╕рдВрджрд░реНрдн рд╣реИред
  • рджреВрд╕рд░реЗ рддрд░реНрдХ рдореЗрдВ рдмрд╛рдзреНрдпрдХрд╛рд░реА рдЪрд░ рдХреЗ рд▓рд┐рдП рдбреЗрдЯрд╛ рд╣реИ рдФрд░ рдХреНрд╡реЗрд░реА рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рддрд╛ рд╣реИред
  • рдкрд╣рд▓рд╛ рдЖрдЙрдЯрдкреБрдЯ рдкреИрд░рд╛рдореАрдЯрд░ рдСрдмреНрдЬреЗрдХреНрдЯ, рдСрдмреНрдЬреЗрдХреНрдЯ рдХреА рдПрдХ рд╕рд░рдгреА рдпрд╛ рдЕрдиреБрдкрд╕реНрдерд┐рдд рд╣реЛ рд╕рдХрддрд╛ рд╣реИред
  • рдЕрдВрддрд┐рдо рдЖрдЙрдЯрдкреБрдЯ рдкреИрд░рд╛рдореАрдЯрд░ рд╣рдореЗрд╢рд╛ рдПрдХ рддреНрд░реБрдЯрд┐ рд╣реИред

рдкрд╣рд▓рд╛ рддрд░реНрдХ рд╣рдореЗрд╢рд╛ context.Context рд╣реИред context.Context рд╡рд╕реНрддреБред рдбреЗрдЯрд╛рдмреЗрд╕ рдФрд░ рдЯреВрд▓рдХрд┐рдЯ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рддреЗ рд╕рдордп рдЗрд╕ рд╕рдВрджрд░реНрдн рдХреЛ рдкрд╛рд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рджреВрд╕рд░рд╛ рддрд░реНрдХ рдмреЗрд╕ рдЯрд╛рдЗрдк struct (рдпрд╛ рдкреЙрдЗрдВрдЯрд░ рдЯреВ struct ) рдХреЗ рд╕рд╛рде рдПрдХ рдкреИрд░рд╛рдореАрдЯрд░ рдХреА рдЕрдкреЗрдХреНрд╖рд╛ рдХрд░рддрд╛ рд╣реИред рдкреИрд░рд╛рдореАрдЯрд░ рдХреЛ рдирд┐рдореНрди рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЛ рдкреВрд░рд╛ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП:


 type Queryer interface { Query() string } 

рдбреЗрдЯрд╛рдмреЗрд╕ рдХреНрд╡реЗрд░реА рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ Query() рдкрджреНрдзрддрд┐ рдХреЛ рдХреЙрд▓ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рдкрд░рд┐рдгрд╛рдореА рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЛ рдбреЗрдЯрд╛рдмреЗрд╕-рд╡рд┐рд╢рд┐рд╖реНрдЯ рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рдпрд╣реА рд╣реИ, PostgreSQL рдХреЗ рд▓рд┐рдП, @end рдХреЛ $1 рдмрджрд▓ рджрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛, рдФрд░ рдорд╛рди &req.End рдХреЛ рддрд░реНрдХреЛрдВ рдХреА рд╕рд░рдгреА рдореЗрдВ рдкрд╛рд╕ рдХрд░ рджрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛


рдЖрдЙрдЯрдкреБрдЯ рдорд╛рдкрджрдВрдбреЛрдВ рдХреЗ рдЖрдзрд╛рд░ рдкрд░, рдпрд╣ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдХрд┐ рдХреМрди рд╕реЗ рддрд░реАрдХреЗ (рдХреНрд╡реЗрд░реА / рдПрдХреНрдЬрд╝реЗрдХ) рдХрд╣рд▓рд╛рдПрдВрдЧреЗ:


  • рдпрджрд┐ рдкрд╣рд▓рд╛ рдкреИрд░рд╛рдореАрдЯрд░ рдмреЗрд╕ рдЯрд╛рдЗрдк struct (рдпрд╛ struct рд▓рд┐рдП рдПрдХ рдкреЙрдЗрдВрдЯрд░) рдХрд╛ рд╣реИ, рддреЛ QueryContext рдореЗрдердб рдХрд╣рд╛ рдЬрд╛рдПрдЧрд╛ред рдпрджрд┐ рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдореЗрдВ рдПрдХ рднреА рдкрдВрдХреНрддрд┐ рдирд╣реАрдВ рд╣реЛрддреА рд╣реИ, рддреЛ sql.ErrNoRows рддреНрд░реБрдЯрд┐ sql.ErrNoRows рдЬрд╛рдПрдЧреАред рдпрд╣реА рд╣реИ, рд╡реНрдпрд╡рд╣рд╛рд░ db.QueryRow рд╕рдорд╛рди рд╣реИред
  • рдпрджрд┐ рдкрд╣рд▓рд╛ рдкреИрд░рд╛рдореАрдЯрд░ рдЖрдзрд╛рд░ рдкреНрд░рдХрд╛рд░ рдХреЗ slice , рддреЛ QueryContext рд╡рд┐рдзрд┐ рдХреЛ рдмреБрд▓рд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рдпрджрд┐ рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдореЗрдВ рдкрдВрдХреНрддрд┐рдпрд╛рдБ рдирд╣реАрдВ рд╣реЛрддреА рд╣реИрдВ, рддреЛ рдПрдХ рдЦрд╛рд▓реА рд╕реВрдЪреА рд╡рд╛рдкрд╕ рдЖ рдЬрд╛рдПрдЧреАред рд╕реВрдЪреА рдЖрдЗрдЯрдо рдХрд╛ рдЖрдзрд╛рд░ рдкреНрд░рдХрд╛рд░ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП (рдпрд╛ рдХрд┐рд╕реА struct рд▓рд┐рдП рд╕реВрдЪрдХ)ред
  • рдпрджрд┐ рдЖрдЙрдЯрдкреБрдЯ рдкреИрд░рд╛рдореАрдЯрд░ error рдкреНрд░рдХрд╛рд░ рдХреЗ рд╕рд╛рде рдПрдХ рд╣реИ, рддреЛ ExecContext рд╡рд┐рдзрд┐ рдХреЛ рдмреБрд▓рд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛ред

рддреИрдпрд╛рд░ рдмрдпрд╛рди


рдЙрддреНрдкрдиреНрди рдХреЛрдб рддреИрдпрд╛рд░ рднрд╛рд╡реЛрдВ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рддрд╛ рд╣реИред рддреИрдпрд╛рд░ рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐рдпрд╛рдБ рдХреИрд╢ рдХреА рдЬрд╛рддреА рд╣реИрдВред рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рдХреА рдкрд╣рд▓реА рддреИрдпрд╛рд░реА рдХреЗ рдмрд╛рдж, рдпрд╣ рдХреИрд╢реНрдб рд╣реИред рдбреЗрдЯрд╛рдмреЗрд╕ / рдПрд╕рдХреНрдпреВрдПрд▓ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рд╕реНрд╡рдпрдВ рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддреА рд╣реИ рдХрд┐ рддреИрдпрд╛рд░ рдХрд┐рдП рдЧрдП рднрд╛рд╡реЛрдВ рдХреЛ рдкрд╛рд░рджрд░реНрд╢реА рдбреЗрдЯрд╛рдмреЗрд╕ рдХрдиреЗрдХреНрд╢рди рдкрд░ рдкрд╛рд░рджрд░реНрд╢реА рд░реВрдк рд╕реЗ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЬрд┐рд╕рдореЗрдВ рдмрдВрдж рдХрдиреЗрдХреНрд╢рди рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рднреА рд╢рд╛рдорд┐рд▓ рд╣реИред рдмрджрд▓реЗ рдореЗрдВ, go-gad/sal рд▓рд╛рдЗрдмреНрд░реЗрд░реА рд▓реЗрди-рджреЗрди рдХреЗ рд╕рдВрджрд░реНрдн рдореЗрдВ рддреИрдпрд╛рд░ рдХрдерди рдХрд╛ рдкреБрди: рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рдЦреНрдпрд╛рд▓ рд░рдЦрддрд╛ рд╣реИред рдЬрдм рддреИрдпрд╛рд░ рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рд╣реЛрддреА рд╣реИ, рддреЛ рддрд░реНрдХ рдХреЛ рдЪрд░ рдмрдВрдзрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдкрд╛рд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдбреЗрд╡рд▓рдкрд░ рдХреЗ рд▓рд┐рдП рдкрд╛рд░рджрд░реНрд╢реАред


go-gad/sal рд▓рд╛рдЗрдмреНрд░реЗрд░реА рд╕рд╛рдЗрдб рдкрд░ рдирд╛рдорд┐рдд рддрд░реНрдХреЛрдВ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЕрдиреБрд░реЛрдз рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреБрдХреНрдд рджреГрд╢реНрдп рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рд╣реЛ рдЬрд╛рддрд╛ рд╣реИред рдЕрдм PostgreSQL рдХреЗ рд▓рд┐рдП рд░реВрдкрд╛рдВрддрд░рдг рд╕рдорд░реНрдерди рд╣реИред рдХреНрд╡реЗрд░реА рдСрдмреНрдЬреЗрдХреНрдЯ рдХрд╛ рдлрд╝реАрд▓реНрдб рдирд╛рдо рдирд╛рдорд┐рдд рддрд░реНрдХреЛрдВ рдореЗрдВ рд╕реНрдерд╛рдирд╛рдкрдиреНрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдСрдмреНрдЬреЗрдХреНрдЯ рдлрд╝реАрд▓реНрдб рдирд╛рдо рдХреЗ рдмрдЬрд╛рдп рдПрдХ рдЕрд▓рдЧ рдирд╛рдо рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рд╕рдВрд░рдЪрдирд╛ рдлрд╝реАрд▓реНрдб рдХреЗ рд▓рд┐рдП sql рдЯреИрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред рдПрдХ рдЙрджрд╛рд╣рд░рдг рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВ:


 type DeleteOrdersRequest struct { UserID int64 `sql:"user_id"` CreateAt time.Time `sql:"created_at"` } func (r * DeleteOrdersRequest) Query() string { return `DELETE FROM orders WHERE user_id=@user_id AND created_at<@end` } 

рдХреНрд╡реЗрд░реА рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЛ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛, рдФрд░ рдкрддреНрд░рд╛рдЪрд╛рд░ рддрд╛рд▓рд┐рдХрд╛ рдФрд░ рдЪрд░ рдмрдВрдзрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП, рдПрдХ рд╕реВрдЪреА рдХреНрд╡реЗрд░реА рдирд┐рд╖реНрдкрд╛рджрди рддрд░реНрдХреЛрдВ рдХреЛ рдкрд╛рд╕ рдХреА рдЬрд╛рдПрдЧреА:


 // generated code: db.Query("DELETE FROM orders WHERE user_id=$1 AND created_at<$2", &req.UserID, &req.CreatedAt) 

рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЗ рддрд░реНрдХреЛрдВ рдФрд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рд╕рдВрджреЗрд╢реЛрдВ рдХреЗ рд▓рд┐рдП рдорд╛рдирдЪрд┐рддреНрд░ рдХреА рд╕рдВрд░рдЪрдирд╛


go-gad/sal рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдбреЗрдЯрд╛рдмреЗрд╕ рд╕рдВрд░рдЪрдирд╛рдУрдВ рдХреА рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рд▓рд╛рдЗрдиреЛрдВ рдХреЛ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рд╕рдВрд░рдЪрдирд╛рдУрдВ рдХреЗ рд╕рд╛рде, рд╕рдВрд░рдЪрдирд╛ рдХреНрд╖реЗрддреНрд░реЛрдВ рдХреЗ рд╕рд╛рде рдЯреЗрдмрд▓ рдХреЙрд▓рдо рдХрд╛ рдзреНрдпрд╛рди рд░рдЦрддреА рд╣реИ:


 type GetRubricsReq struct {} func (r GetRubricReq) Query() string { return `SELECT * FROM rubrics` } type Rubric struct { ID int64 `sql:"id"` CreateAt time.Time `sql:"created_at"` Title string `sql:"title"` } type GetRubricsResp []*Rubric type Store interface { GetRubrics(ctx context.Context, req GetRubricsReq) (GetRubricsResp, error) } 

рдФрд░ рдЕрдЧрд░ рдбреЗрдЯрд╛рдмреЗрд╕ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рд╣реИ:


 dev > SELECT * FROM rubrics; id | created_at | title ----+-------------------------+------- 1 | 2012-03-13 11:17:23.609 | Tech 2 | 2015-07-21 18:05:43.412 | Style (2 rows) 

рдлрд┐рд░ GetRubricsResp рд╕реВрдЪреА рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рд╡рд╛рдкрд╕ рдЖ рдЬрд╛рдПрдЧреА, рдЬрд┐рдирдореЗрдВ рд╕реЗ рддрддреНрд╡ рд░реВрдмреНрд░рд┐рдХ рдХреЛ рдЗрдВрдЧрд┐рдд рдХрд┐рдП рдЬрд╛рдПрдВрдЧреЗ, рдЬрд╣рд╛рдВ рдлрд╝реАрд▓реНрдб рдЙрди рд╕реНрддрдВрднреЛрдВ рд╕реЗ рдорд╛рдиреЛрдВ рд╕реЗ рднрд░реЗ рд╣реБрдП рд╣реИрдВ рдЬреЛ рдЯреИрдЧ рдирд╛рдореЛрдВ рдХреЗ рдЕрдиреБрд░реВрдк рд╣реИрдВред


рдпрджрд┐ рдбреЗрдЯрд╛рдмреЗрд╕ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдореЗрдВ рд╕рдорд╛рди рдирд╛рдо рд╡рд╛рд▓реЗ рдХреЙрд▓рдо рд╣реЛрддреЗ рд╣реИрдВ, рддреЛ рд╕рдВрдмрдВрдзрд┐рдд рд╕рдВрд░рдЪрдирд╛ рдлрд╝реАрд▓реНрдб рдХреЛ рдШреЛрд╖рдгрд╛ рдХреНрд░рдо рдореЗрдВ рдЪреБрдирд╛ рдЬрд╛рдПрдЧрд╛ред


 dev > select * from rubrics, subrubrics; id | title | id | title ----+-------+----+---------- 1 | Tech | 3 | Politics 

 type Rubric struct { ID int64 `sql:"id"` Title string `sql:"title"` } type Subrubric struct { ID int64 `sql:"id"` Title string `sql:"title"` } type GetCategoryResp struct { Rubric Subrubric } 

рдЧреИрд░-рдорд╛рдирдХ рдбреЗрдЯрд╛ рдкреНрд░рдХрд╛рд░


database/sql рдкреИрдХреЗрдЬ рдмреБрдирд┐рдпрд╛рджреА рдбреЗрдЯрд╛ рдкреНрд░рдХрд╛рд░реЛрдВ (рддрд╛рд░, рд╕рдВрдЦреНрдпрд╛) рдХреЗ рд▓рд┐рдП рд╕рдорд░реНрдерди рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред рдЕрдиреБрд░реЛрдз рдпрд╛ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдореЗрдВ рдбреЗрдЯрд╛ рдкреНрд░рдХрд╛рд░реЛрдВ рдЬреИрд╕реЗ рд╕рд░рдгреА рдпрд╛ driver.Valuer рдХреЛ driver.Valuer рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, driver.Valuer рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реИред driver.Valuer рдФрд░ sql.Scanner ред рд╡рд┐рднрд┐рдиреНрди рдЪрд╛рд▓рдХ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдореЗрдВ рд╡рд┐рд╢реЗрд╖ рд╕рд╣рд╛рдпрдХ рдХрд╛рд░реНрдп рд╣реЛрддреЗ рд╣реИрдВред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП lib/pq.Array ( https://godoc.org/github.com/lib/pq#Array ):


 func Array(a interface{}) interface { driver.Valuer sql.Scanner } 

рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ, рджреГрд╢реНрдп рд╕рдВрд░рдЪрдирд╛ рдХреНрд╖реЗрддреНрд░реЛрдВ рдХреЗ рд▓рд┐рдП go-gad/sql рд▓рд╛рдЗрдмреНрд░реЗрд░реА


 type DeleteAuthrosReq struct { Tags []int64 `sql:"tags"` } 

рдореВрд▓реНрдп &req.Tags рдЙрдкрдпреЛрдЧ рдХрд░реЗрдЧрд╛ред рдпрджрд┐ рд╕рдВрд░рдЪрдирд╛ sal.ProcessRower рдХреЛ sal.ProcessRower рд╣реИред


 type ProcessRower interface { ProcessRow(rowMap RowMap) } 

рддрдм рдЗрд╕реНрддреЗрдорд╛рд▓ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдореВрд▓реНрдп рд╕рдорд╛рдпреЛрдЬрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ


 func (r *DeleteAuthorsReq) ProcessRow(rowMap sal.RowMap) { rowMap.Set("tags", pq.Array(r.Tags)) } func (r *DeleteAuthorsReq) Query() string { return `DELETE FROM authors WHERE tags=ANY(@tags::UUID[])` } 

рдЗрд╕ рд╣реИрдВрдбрд▓рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдЕрдиреБрд░реЛрдз рдФрд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рддрд░реНрдХреЛрдВ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдореЗрдВ рдПрдХ рд╕реВрдЪреА рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рд╡рд┐рдзрд┐ рд╕реВрдЪреА рдЖрдЗрдЯрдо рд╕реЗ рд╕рдВрдмрдВрдзрд┐рдд рд╣реЛрдиреА рдЪрд╛рд╣рд┐рдПред


рд▓реЗрди-рджреЗрди


рд▓реЗрдирджреЗрди рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЗрдВрдЯрд░рдлрд╝реЗрд╕ (рд╕реНрдЯреЛрд░) рдХрд╛ рд╡рд┐рд╕реНрддрд╛рд░ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рддрд░реАрдХреЛрдВ рд╕реЗ рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП:


 type Store interface { BeginTx(ctx context.Context, opts *sql.TxOptions) (Store, error) sal.Txer ... 

рд╡рд┐рдзрд┐рдпреЛрдВ рдХрд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдЙрддреНрдкрдиреНрди рд╣реЛрдЧрд╛ред BeginTx рд╡рд┐рдзрд┐ рд╡рд░реНрддрдорд╛рди sal.QueryHandler рдСрдмреНрдЬреЗрдХреНрдЯ рд╕реЗ рдХрдиреЗрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреА рд╣реИ рдФрд░ рд▓реЗрдирджреЗрди db.BeginTx(...) рдЦреЛрд▓рддрд╛ рд╣реИ; Store рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХрд╛ рдПрдХ рдирдпрд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдСрдмреНрдЬреЗрдХреНрдЯ рджреЗрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдкреНрд░рд╛рдкреНрдд *sql.Tx рд░реВрдк рдореЗрдВ рдкреНрд░рд╛рдкреНрдд *sql.Tx рдСрдмреНрдЬреЗрдХреНрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ


middleware


рд╣реБрдХ рдПрдореНрдмреЗрдбрд┐рдВрдЧ рдЙрдкрдХрд░рдг рдХреЗ рд▓рд┐рдП рдкреНрд░рджрд╛рди рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВред


 type BeforeQueryFunc func(ctx context.Context, query string, req interface{}) (context.Context, FinalizerFunc) type FinalizerFunc func(ctx context.Context, err error) 

рдЗрд╕рд╕реЗ рдкрд╣рд▓реЗ рдХрд┐ BeforeQueryFunc рд╣реБрдХ рдХреЛ db.PrepareContext рдпрд╛ db.Query рдкрд╣рд▓реЗ db.Query ред рдпрд╣реА рд╣реИ, рдкреНрд░реЛрдЧреНрд░рд╛рдо рдХреЗ рд╢реБрд░реВ рдореЗрдВ, рдЬрдм рддреИрдпрд╛рд░ рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рдХреИрд╢ рдЦрд╛рд▓реА рд╣реЛрддреА рд╣реИ, рдЬрдм store.GetAuthors рдХреЙрд▓ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ BeforeQueryFunc рд╣реБрдХ рдХреЛ рджреЛ рдмрд╛рд░ рдХрд╣рд╛ рдЬрд╛рдПрдЧрд╛ред рдЗрд╕рд╕реЗ рдкрд╣рд▓реЗ рдХрд┐ рдЖрдк рд╣рдорд╛рд░реЗ рдХреЗрд╕ store.GetAuthors рдореЗрдВ рдмрд╛рд╣рд░ store.GetAuthors , рдЗрд╕рд╕реЗ рдкрд╣рд▓реЗ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИред


рд╣реБрдХ рдХреЗ рдирд┐рд╖реНрдкрд╛рджрди рдХреЗ рд╕рдордп, рд╕реЗрд╡рд╛ рдХреЛ рдирд┐рдореНрди рдорд╛рдиреЛрдВ рдХреЗ рд╕рд╛рде рд╕реЗрд╡рд╛ рдХреБрдВрдЬрд┐рдпреЛрдВ рд╕реЗ рднрд░рд╛ рдЬрд╛рддрд╛ рд╣реИ:


  • ctx.Value(sal.ContextKeyTxOpened) рдмреВрд▓рд┐рдпрди рдорд╛рди рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рддрд╛ рд╣реИ рдХрд┐ рд╡рд┐рдзрд┐ рд▓реЗрдирджреЗрди рдХреЗ рд╕рдВрджрд░реНрдн рдореЗрдВ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ рдпрд╛ рдирд╣реАрдВред
  • ctx.Value(sal.ContextKeyOperationType) , рдСрдкрд░реЗрд╢рди рдХреЗ рдкреНрд░рдХрд╛рд░ рдХрд╛ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдорд╛рди, "QueryRow" , "Query" , "Exec" , "Commit" , рдЖрджрд┐ред
  • ctx.Value(sal.ContextKeyMethodName) рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рд╡рд┐рдзрд┐ рдХрд╛ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдорд╛рди, рдЬреИрд╕реЗ "GetAuthors" ред

рддрд░реНрдХреЛрдВ рдХреЗ рд░реВрдк рдореЗрдВ, BeforeQueryFunc рд╣реБрдХ рдХреНрд╡реЗрд░реА рдХреЗ sql рд╕реНрдЯреНрд░рд┐рдВрдЧ рдФрд░ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреНрд╡реЗрд░реА рд╡рд┐рдзрд┐ рдХреЗ req рддрд░реНрдХ рдХреЛ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рддрд╛ рд╣реИред FinalizerFunc рд╣реБрдХ рдПрдХ рддрд░реНрдХ рдХреЗ рд░реВрдк рдореЗрдВ рдПрдХ err рдЪрд░ рд▓реЗрддрд╛ рд╣реИред


 beforeHook := func(ctx context.Context, query string, req interface{}) (context.Context, sal.FinalizerFunc) { start := time.Now() return ctx, func(ctx context.Context, err error) { log.Printf( "%q > Opeartion %q: %q with req %#v took [%v] inTx[%v] Error: %+v", ctx.Value(sal.ContextKeyMethodName), ctx.Value(sal.ContextKeyOperationType), query, req, time.Since(start), ctx.Value(sal.ContextKeyTxOpened), err, ) } } client := NewStore(db, sal.BeforeQuery(beforeHook)) 

рдЖрдЙрдЯрдкреБрдЯ рдЙрджрд╛рд╣рд░рдг:


 "CreateAuthor" > Opeartion "Prepare": "INSERT INTO authors (Name, Desc, CreatedAt) VALUES($1, $2, now()) RETURNING ID, CreatedAt" with req <nil> took [50.819┬╡s] inTx[false] Error: <nil> "CreateAuthor" > Opeartion "QueryRow": "INSERT INTO authors (Name, Desc, CreatedAt) VALUES(@Name, @Desc, now()) RETURNING ID, CreatedAt" with req bookstore.CreateAuthorReq{BaseAuthor:bookstore.BaseAuthor{Name:"foo", Desc:"Bar"}} took [150.994┬╡s] inTx[false] Error: <nil> 

рдЖрдЧреЗ рдХреНрдпрд╛ рд╣реИ


  • MySQL рдХреЗ рд▓рд┐рдП рдмрд╛рдзреНрдпрдХрд╛рд░реА рдЪрд░ рдФрд░ рддреИрдпрд╛рд░ рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП рд╕рдорд░реНрдердиред
  • RowAppender рд╣реБрдХ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХреЛ рд╕рдорд╛рдпреЛрдЬрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдПред
  • Exec.Result рдХрд╛ рдорд╛рди Exec.Result ред

Source: https://habr.com/ru/post/hi431984/


All Articles