
рдЪрд▓реЛ рд╕рдВрдмрдВрдзрдкрд░рдХ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдХреНрд▓реЛрдЬрд░ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рд▓рд┐рдЦреЗрдВред рдЙрд╕реА рд╕рдордп, рдЪрд▓реЛ рдореИрдХреНрд░реЛрдЬрд╝ рд▓рд┐рдЦрдиреЗ рдХрд╛ рдЕрднреНрдпрд╛рд╕ рдХрд░реЗрдВ, рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдФрд░ рдорд▓реНрдЯреАрдорд┐рдереЛрдбреНрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░реЗрдВред рдЖрдЦрд┐рд░рдХрд╛рд░, рдХрд┐рд╕реА рднрд╛рд╖рд╛ рдХреЛ рд╕реАрдЦрдиреЗ рдХрд╛ рдЗрд╕рд╕реЗ рдмреЗрд╣рддрд░ рддрд░реАрдХрд╛ рдирд╣реАрдВ рд╣реИ рдХрд┐ рдЙрд╕рдореЗрдВ рдХреБрдЫ рд▓рд┐рдЦрд╛ рдЬрд╛рдПред рдЕрдЪреНрдЫрд╛ ... рдпрд╛ рдкрдврд╝рд╛, рдЬреИрд╕рд╛ рдХрд┐рд╕реА рдФрд░ рдиреЗ рд▓рд┐рдЦрд╛ рд╣реИред
рдХреНрдпреЛрдВ?рдПрдХ рд╕рдордп рдореЗрдВ рдореБрдЭреЗ рд╡реНрдпрдХреНрддрд┐рдЧрдд рдЙрдкрдпреЛрдЧ рдХреЗ рд▓рд┐рдП рдЗрд╕ рддрд░рд╣ рдХреЗ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдереАред рдЙрд╕ рд╕рдордп, рджреЛ рд╕рд╛рдорд╛рдиреНрдп рд╕рдорд╛рдзрд╛рди рдереЗ - рдХреНрд▓реЛрдЬреБрд░реЗрдХреНрд▓рд┐рди рдФрд░ рдХреЛрд░рдорд╛ред рдПрдХ рдХрд╛рд░рдг рдпрд╛ рдХрд┐рд╕реА рдЕрдиреНрдп рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ рдЙрдиреНрд╣реЗрдВ рдкрд╕рдВрдж рдирд╣реАрдВ рдХрд┐рдпрд╛ (рд╣рд╛рдВ, рдПрдХ рдШрд╛рддрдХ рджреЛрд╖), рдпрд╣ рдореЗрд░реА рдмрд╛рдЗрдХ рдмрдирд╛рдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред рдмрд╛рдЗрдХ рдХрд╛рдлреА рдХрд╛рдо рдХрд░ рд░рд╣реА рд╣реИ, рдореИрдВ рд╕рдВрддреБрд╖реНрдЯ рд╣реВрдВред рдмрд╛рд╣рд░реА рдорддрднреЗрджреЛрдВ рдореЗрдВ рд╕реЗ - рдЙрдЪреНрдЪ рдПрдХреНрд╕реНрдЯреЗрдВрд╕рд┐рдмрд┐рд▓рд┐рдЯреА, рдирдП рдСрдкрд░реЗрдЯрд░реЛрдВ рдФрд░ рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рдЬреЛрдбрд╝рдиреЗ рдореЗрдВ рдЖрд╕рд╛рдиреА рдкрд░ рдЬреЛрд░ рджрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛, рдирдВрдЧреЗ рдПрд╕рдХреНрдпреВрдПрд▓ рд╕реЗ рдЙрдкрд╢реНрд░реЗрдгрд┐рдпреЛрдВ рдФрд░ рдЖрд╡реЗрд╖рдг рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рдирд╛ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдерд╛ред
рд▓реЗрдЦ рдЗрд╕ рдмрд╛рдЗрдХ рдХреА рд╕рд╛рдорд╛рдиреНрдп рд╕рдВрд░рдЪрдирд╛ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рддрд╛ рд╣реИ, рд╣рд╛рд▓рд╛рдВрдХрд┐, рдХреБрдЫ рд╣рдж рддрдХ рд╕рд░рд▓ рд░реВрдк рдореЗрдВред рдХреБрдЫ рд╡рд┐рд╢реЗрд╖рддрд╛рдПрдВ рдЧрд╛рдпрдм рд╣реИрдВ, рдХреЛрдб рдЖрдорддреМрд░ рдкрд░ рдПрдХ рдЕрд▓рдЧ рдЕрдиреБрдХреНрд░рдо рдореЗрдВ рд╡рд┐рдХрд╕рд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛, рдХрдИ рдордзреНрдпрд╡рд░реНрддреА рдПрдкреАрдЖрдИ рд╡рд┐рдХрд▓реНрдк рдУрд╡рд░рдмреЛрд░реНрдб рдмрдиреЗ рд░рд╣реЗред рд▓реЗрдХрд┐рди, рд╕рд╛рдорд╛рдиреНрдп рддреМрд░ рдкрд░, рдмреБрдирд┐рдпрд╛рджреА рд╡рд╛рд╕реНрддреБрдХрд▓рд╛ рд╡рд┐рдЪрд╛рд░реЛрдВ рдХреЛ рд╕рдЯреАрдХ рд░реВрдк рд╕реЗ рд╡рд░реНрдгрд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред рдореБрдЭреЗ рдЖрд╢рд╛ рд╣реИ рдХрд┐ рдХрд┐рд╕реА рдХреЛ рд▓реЗрдЦ рдЙрдкрдпреЛрдЧреА рд▓рдЧреЗрдЧрд╛ред
рддреЛ рд╣рдо рдХреНрдпрд╛ рд▓рд┐рдЦрддреЗ рд╣реИрдВ?
рдПрдХ рдбреАрдПрд╕рдПрд▓ рдмрдирд╛рдПрдВ (рдУрдЖрд░рдПрдо
рдирд╣реАрдВ )ред ORM рдХреЗ рд╡рд┐рдкрд░реАрдд:
- рдХреЛрдИ "рд╕реНрдорд╛рд░реНрдЯ рдСрдмреНрдЬреЗрдХреНрдЯреНрд╕" - рдХреЗрд╡рд▓ рдлрд╝рдВрдХреНрд╢рди рдФрд░ рдЕрдВрддрд░реНрдирд┐рд╣рд┐рдд рдбреЗрдЯрд╛ рд╕рдВрд░рдЪрдирд╛рдПрдВ (рд░рд┐рдХреЙрд░реНрдб рд╕рд╣рд┐рдд);
- рдХреЛрдИ "рдЖрд▓рд╕реА" рдХрдиреЗрдХреНрд╢рди, рд░рд┐рдХреЙрд░реНрдб рдФрд░ рдЕрдиреНрдп "рдЧрдВрджрд╛ рдЪреАрдЬреЛрдВ" рдХрд╛ рдЬрд╛рджреБрдИ рд▓реЛрдбрд┐рдВрдЧ;
- рд╣рдо рд╕рд╛рдЗрдб рдЗрдлреЗрдХреНрдЯ рдХреА рдШрдЯрдирд╛ рдХреЗ рд╕рдордп рдХреЛ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ - рд╡реЗ рдХреЗрд╡рд▓ рдХрдбрд╝рд╛рдИ рд╕реЗ рдЕрдкреЗрдХреНрд╖рд┐рдд рд╕реНрдерд╛рдиреЛрдВ рдореЗрдВ рд╣реЛрдиреЗ рдЪрд╛рд╣рд┐рдПред
рдХреБрдЫ рдФрд░ рдЖрд╡рд╢реНрдпрдХрддрд╛рдПрдВ рдЬреЛрдбрд╝реЗрдВ:
- рдПрд╕рдХреНрдпреВрдПрд▓ рдХреЗ рд╕рд╛рде рд╕рдорд╛рдирддрд╛;
- рдкрд╛рд░рджрд░реНрд╢рд┐рддрд╛, рдХрдо "рдЬрд╛рджреВ" - рдмреЗрд╣рддрд░;
- рдкреНрд░рд╢реНрдиреЛрдВ, рд╕реНрдХреАрдорд╛ рдФрд░ рдЬреИрд╕реЗ рдХреА рдХреЛрдИ рдорд╛рдиреНрдпрддрд╛ рдирд╣реАрдВ - рд╣рдо рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЛ рдЕрдВрддрд░рд╛рддреНрдорд╛ рдХреА рдЖрд╡рд╛рдЬ рдкрд░ рдЫреЛрдбрд╝ рджреЗрддреЗ рд╣реИрдВ;
- рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛рдУрдВ рдФрд░ рддрд░реНрдХреЛрдВ рдХреЗ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рдЙрджреНрдзрд░рдг;
- рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдЖрдзрд╛рд░ рд╕реЗ рд╕реНрд╡рддрдВрддреНрд░рддрд╛ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдирд╛ (рд▓реЗрдХрд┐рди рдХрдЯреНрдЯрд░рддрд╛ рдХреЗ рдмрд┐рдирд╛);
- рдХрднреА-рдХрднреА рд╣рдореЗрдВ рдПрдХ рдбреАрдмреА-рдбрд┐рдкреЗрдВрдбреЗрдВрдЯ рдХреЛрдб (рд╕реНрдЯреЛрд░реЗрдЬ, рдЯреНрд░рд┐рдЧрд░реНрд╕ рдЖрджрд┐) рд▓рд┐рдЦрдирд╛ рдкрдбрд╝рддрд╛ рд╣реИред
"рдереЛрдбрд╝рд╛ рдЬрд╛рджреВ" рд╕реЗ рдХреНрдпрд╛ рдорддрд▓рдм рд╣реИ? рдореЛрдЯреЗ рддреМрд░ рдкрд░, рдЗрд╕ рддрд░рд╣ рдХреА рд▓рд╛рдЗрдмреНрд░реЗрд░реА
рдХреЛ рдХреНрд╡реЗрд░реА рдСрдкреНрдЯрд┐рдорд╛рдЗрдЬрд╝реЗрд╢рди рдФрд░ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдРрд╕реА рдХрд┐рд╕реА рднреА рдЧрддрд┐рд╡рд┐рдзрд┐ рдореЗрдВ
рдирд╣реАрдВ рд▓рдЧрд╛рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП ред рд╕реИрджреНрдзрд╛рдВрддрд┐рдХ рд░реВрдк рд╕реЗ, рдпрд╣, рд╢рд╛рдпрдж, рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЛ рдЙрддрд╛рд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреБрдЫ (рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ, рдереЛрдбрд╝рд╛ рд╕рд╛) рдЕрдиреБрдорддрд┐ рджреЗрдЧрд╛, рд╡реНрдпрд╡рд╣рд╛рд░ рдореЗрдВ, рдЪреАрдЬреЗрдВ рдЖрдорддреМрд░ рдкрд░ рдмрджрддрд░ рд╣реЛрддреА рд╣реИрдВред рдЖрдЦрд┐рд░рдХрд╛рд░, рдХреЗрд╡рд▓ рдбреЗрдЯрд╛рдмреЗрд╕ рдФрд░ рдкреНрд░реЛрдЧреНрд░рд╛рдорд░ (рдХрднреА-рдХрднреА) рдХреЛ рдЖрд╡рд╢реНрдпрдХ рдЕрдиреБрдХреВрд▓рди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рдкреНрдд рдЬреНрдЮрд╛рди рд╣реИред рдЦрд░рд╛рдм рд╡рд┐рдХрд▓реНрдк: рдбреЗрд╡рд▓рдкрд░ рдПрдХ рдХреНрд╡реЗрд░реА рд▓рд┐рдЦрддрд╛ рд╣реИ, рдлрд┐рд░ рдмрд╣реБрдд рд╕рд╛рд╡рдзрд╛рдиреА рд╕реЗ рдЖрд╡реЗрджрди рд▓реЙрдЧ рдХреА рдЬрд╛рдВрдЪ рдХрд░рддрд╛ рд╣реИ рддрд╛рдХрд┐ рдкрддрд╛ рд▓рдЧрд╛рдпрд╛ рдЬрд╛ рд╕рдХреЗ рдХрд┐ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдХрд┐рд╕ рддрд░рд╣ рдХрд╛ SQL рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рднреЗрдЬрд╛ рдЧрдпрд╛ рд╣реИред рдЖрдкрдХреЛ рд▓реЙрдЧ рдХреЛ рдирд┐рдпрдорд┐рдд рд░реВрдк рд╕реЗ рдбрдмрд▓-рдЪреЗрдХ рдХрд░рдирд╛ рд╣реЛрдЧрд╛, рдХреНрдпреЛрдВрдХрд┐ рдПрдХ рдирдИ рд░рд┐рд▓реАрдЬрд╝ рдХреЗ рдмрд╛рдж рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдЕрдЪрд╛рдирдХ "рд╕реНрдорд╛рд░реНрдЯ" рд╣реЛ рд╕рдХрддреА рд╣реИ!
рддреЛ, рд╣рдорд╛рд░реА DSL рдЕрдкрдиреА рдХреНрд╖рдорддрд╛рдУрдВ рдореЗрдВ рдкрд░реНрдпрд╛рдкреНрдд рдкрд╛рд░рджрд░реНрд╢реА рд╣реЛрдЧреА - рд╣рдо рд╢рдмреНрджрд╛рд░реНрде рдирдВрдЧреЗ SQL рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди Clojure рд╕рд┐рдВрдЯреИрдХреНрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВред рдПрд╕-рдПрдХреНрд╕рдкреНрд░реЗрд╢рдВрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП рдПрд╕рдХреНрдпреВрдПрд▓ рд▓рд┐рдЦрдиреЗ рдЬреИрд╕рд╛ рдХреБрдЫ, рд╣рдорд╛рд░реА рднрд╛рд╖рд╛ рдХреА рдмрд╛рд░реАрдХрд┐рдпреЛрдВ рдХреЛ рдзреНрдпрд╛рди рдореЗрдВ рд░рдЦрддреЗ рд╣реБрдПред рд╕рдм рдХреБрдЫ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦреЗрдЧрд╛:
(select (fields [:name :role_name]) (from :Users) (join-inner :Roles (== :Users.role_id :Roles.id)) (where (= :Roles.name "admin")) (order :Users.name) (limit 100))
рдЗрд╕ рдХреЛрдб рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдПрдХ рдХреНрд╡реЗрд░реА рдЙрддреНрдкрдиреНрди рдХрд░рдиреА рд╣реЛрдЧреА:
SELECT `name`, `role_name` FROM `Users` INNER JOIN `Roles` ON `Users`.`role_id` = `Roles`.`id` WHERE `Roles`.`name` = ? ORDER BY `Users`.`name` LIMIT ?
рд╣рдо рд╕рднреА рдирд╛рдореЛрдВ рд╕реЗ рдмрдЪрддреЗ рд╣реИрдВред рдЕрдЪреНрдЫреЗ рддрд░реАрдХреЗ рд╕реЗ, рдЖрдкрдХреЛ рджреЛрд╣рд░реЗ рдЙрджреНрдзрд░рдг рдЪрд┐рд╣реНрдиреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП (рдпрд╛ рдмреЗрд╣рддрд░ рдЕрднреА рддрдХ, рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЗ рдкреНрд░рдХрд╛рд░ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВ), рд▓реЗрдХрд┐рди рдкрдардиреАрдпрддрд╛ рдХреЗ рд▓рд┐рдП, рд╣рдо рдЙрджрд╛рд╣рд░рдгреЛрдВ рдореЗрдВ MySQL рд╢реИрд▓реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред
?
рд╕реНрдерд┐рд░рд╛рдВрдХ рджреНрд╡рд╛рд░рд╛ рдкреНрд░рддрд┐рд╕реНрдерд╛рдкрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ
?
- рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдбреЗрдЯрд╛рдмреЗрд╕ рдХрд╛ jdbc рдЪрд╛рд▓рдХ рдЦреБрдж рд╣реА рдорд╛рдкрджрдВрдбреЛрдВ рдХреЗ рдкреНрд░рд╕рд╛рд░рдг рдФрд░ рд╕реНрдХреНрд░реАрдирд┐рдВрдЧ рдореЗрдВ рд▓рдЧрд╛ рд╣реЛрдЧрд╛ред
рд╕реЗрд▓реЗрдХреНрдЯреЗрдб рдХреНрд╡реЗрд╢реНрдЪрди рдХрд╛ рд╕реАрдзрд╛ рдирд┐рд╖реНрдкрд╛рджрди рдЕрд▓рдЧ-рдЕрд▓рдЧ рдлрдВрдХреНрд╢рдиреНрд╕ рджреНрд╡рд╛рд░рд╛ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛:
fetch-all
,
fetch-one
,
with-fetch
ред рд╡реЗ рд╕рднреА рдбреЗрдЯрд╛рдмреЗрд╕ рдХрдиреЗрдХреНрд╢рди рдорд╛рдкрджрдВрдбреЛрдВ рдФрд░ рдЙрд╕ рдЕрдиреБрд░реЛрдз рдХреЛ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рддреЗ рд╣реИрдВ рдЬрд┐рд╕реЗ рд╣рдо рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ:
(def db {:classname "com.mysql.jdbc.Driver" :subprotocol "mysql" :user "test" :password "test" :subname "//localhost/test"}) ; 1 Users (fetch-one db (select (from :Users) (where (== :id 123)))) ; (fetch-all db (select (from :Users))) (with-fetch db [rows (select (from :Users))] ; ** `rows` (doseq [r rows] (print ">" r)))
SQL рдЙрддреНрдкрдиреНрди рдХрд░реЗрдВ
рд╢реБрд░реВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдпрд╣ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░реЗрдВрдЧреЗ рдХрд┐ рд╣рдо рдЕрдкрдиреЗ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХреЗ рдЕрдВрджрд░ рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЛ рдХреИрд╕реЗ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░реЗрдВрдЧреЗред
(def raw-select ['SELECT :name :role_name ['FROM :Users ['JOIN :Roles ['ON :Users.role_id :Roles_id]]] ['WHERE ['LIKE :Users.name "And%"] ['LIMIT 100]]])
рдЗрд╕ рдЙрджрд╛рд╣рд░рдг рдореЗрдВ, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рд╡реИрдХреНрдЯрд░, рд╡рд░реНрдг рдФрд░ рдХреБрдВрдЬрд┐рдпреЛрдВ рдХрд╛ рдПрдХ рдкреЗрдбрд╝ рд╣реИред рдкреНрд░рддреАрдХреЛрдВ рдХреА рд╕рд╣рд╛рдпрддрд╛ рд╕реЗ рд╣рдо рдПрд╕рдХреНрдпреВрдПрд▓ рдХреЗ рдЦреЛрдЬрд╢рдмреНрджреЛрдВ рдХреЛ рдирд┐рд░реВрдкрд┐рдд рдХрд░реЗрдВрдЧреЗ, рдХреБрдВрдЬреА рдХреА рдорджрдж рд╕реЗ - рддрд╛рд▓рд┐рдХрд╛рдУрдВ рдФрд░ рдХреНрд╖реЗрддреНрд░реЛрдВ рдХреЗ рдирд╛рдо, рдорд╛рди (рд╕реНрдЯреНрд░рд┐рдВрдЧреНрд╕, рд╕рдВрдЦреНрдпрд╛рдПрдБ, рджрд┐рдирд╛рдВрдХ рдЖрджрд┐) "рдЬреИрд╕рд╛ рд╣реИ" рдЫреЛрдбрд╝ рджрд┐рдП рдЧрдП рд╣реИрдВред рд╣рдо рдПрдХ рдЬреЛрдбрд╝реА рдХреЗ рд░реВрдк рдореЗрдВ рд╕рдВрдХрд▓рд┐рдд рдХреНрд╡реЗрд░реА рдХрд╛ рдкреНрд░рддрд┐рдирд┐рдзрд┐рддреНрд╡ рдХрд░рддреЗ рд╣реИрдВ: рдПрд╕рдХреНрдпреВрдПрд▓ рдХреЛрдб (рд╕реНрдЯреНрд░рд┐рдВрдЧ) рдФрд░ рддрд░реНрдХреЛрдВ рдХреЗ рд╡реЗрдХреНрдЯрд░ред рд╣рдореЗрдВ рдПрдХ рдЕрд▓рдЧ рдкреНрд░рдХрд╛рд░ рдорд┐рд▓рддрд╛ рд╣реИ:
(defrecord Sql [sql args]) ;; : (Sql. "SELECT * FROM `Users` WHERE `id` = ?" [123])
рдпрд╣ рд╣рдорд╛рд░реЗ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдореЗрдВ рдиреАрдЪреЗ рдХрд╛ рджреГрд╢реНрдп рд╣реИред рд╣рдо рд░реВрдкрд╛рдВрддрд░рдг рдХреЛ рдПрдХ рдкреНрд░рддрд┐рдирд┐рдзрд┐рддреНрд╡ рд╕реЗ рджреВрд╕рд░реЗ рдореЗрдВ рд▓рд╛рдЧреВ рдХрд░рддреЗ рд╣реИрдВред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ
рдХрд┐рд╕реА рднреА рдЗрдХрд╛рдИ рдХреЛ
Sql
рд░рд┐рдХреЙрд░реНрдб рдореЗрдВ рдмрджрд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдХреБрдЫ
рд╕рд╛рд░реНрд╡рднреМрдорд┐рдХ рддрд░реАрдХреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдмрд╣реБрдд рдЕрдЪреНрдЫреЗ рд╣реИрдВ:
(defprotocol SqlLike (as-sql [this])) ; (defn quote-name [s] (let [x (name s)] (if (= "*" x) x (str \` x \`)))) (extend-protocol SqlLike ; `x` (= (as-sql (as-sql x)) (as-sql x)) Sql (as-sql [this] this) ; Object (as-sql [this] (Sql. "?" [this])) ; clojure.lang.Keyword (as-sql [this] (Sql. (quote-name this) nil)) ; SQL clojure.lang.Symbol (as-sql [this] (Sql. (name this) nil)) ; nil nil (as-sql [this] (Sql. "NULL" nil)))
рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдХреЗ рдмрдЬрд╛рдп, рдХреЛрдИ рд╕рд╛рдорд╛рдиреНрдп рд░реВрдк рд╕реЗ рдореЗрд▓ рдЦрд╛рддреЗ рд╣реБрдП
if
рдпрд╛ рдкреИрдЯрд░реНрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддрд╛ рд╣реИред рд▓реЗрдХрд┐рди рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдореЗрдВ рдПрдХ рдирд┐рд░реНрд╡рд┐рд╡рд╛рдж рдкреНрд▓рд╕ рд╣реИ: рдкреБрд╕реНрддрдХрд╛рд▓рдп рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛
рд╕реНрд╡рдпрдВ рдХрд┐рд╕реА рднреА рдкреНрд░рдХрд╛рд░ рдХреЗ рд▓рд┐рдП рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рд░реВрдкрд╛рдВрддрд░рдг
рдХреЛ рд▓рд╛рдЧреВ рдХрд░ рд╕рдХрддреЗ
рд╣реИрдВ ред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдХреЛрдИ рд╡реНрдпрдХреНрддрд┐ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рд▓рд┐рдВрдХ рд╕реЗ рдорд╛рди рдирд┐рдХрд╛рд▓рдирд╛ рдЪрд╛рд╣ рд╕рдХрддрд╛ рд╣реИ:
(extend-protocol SqlLike clojure.lang.ARef (as-sql [this] (as-sql @this))) ; ; (ref, agent, var, atom) (def a (atom 123)) (assert (= (as-sql a) (as-sql @a) (Sql. "?" [123])))
рд╣рдо рд╡реИрдХреНрдЯрд░ рдФрд░ рд╕реВрдЪрд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП рдЕрдкрдирд╛ рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рд▓рд╛рдЧреВ рдХрд░рддреЗ рд╣реИрдВ:
; , 2 sql- (defn- join-sqls ([] (Sql. "" nil)) ([^Sql s1 ^Sql s2] (Sql. (str (.sql s1) " " (.sql s2)) (concat (.args s1) (.args s2))))) (extend-protocol SqlLike clojure.lang.Sequential (as-sql [this] (reduce join-sqls (map as-sql this))))
рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рдХреА рджрдХреНрд╖рддрд╛ рдХреЗ рд╕рд╛рде, рдпрд╣ рдпрд╣рд╛рдБ рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рдирд╣реАрдВ рд╣реИ, рдЖрдк рддреЗрдЬреА рд╕реЗ рдХреЛрдб рд▓рд┐рдЦ рд╕рдХрддреЗ рд╣реИрдВред рд▓реЗрдХрд┐рди рдЕрдм:
(as-sql ['SELECT '* ['FROM :Users] ['WHERE :id '= 1 'AND :name 'IS 'NOT nil]]) ; => #user.Sql{:sql "SELECT * FROM `Users` WHERE `id` = ? AND `name` IS NOT NULL" :args (1)}
рдмрд╣реБрдд рдмрдврд╝рд┐рдпрд╛! рдЖрдЗрдП рдХреБрдЫ рдФрд░ рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рддреЗ рд╣реИрдВ ...
(require '[clojure.java.jdbc :as jdbc]) (defn- to-sql-params [relation] (let [{s :sql p :args} (as-sql relation)] (vec (cons sp)))) (defn fetch-all [db relation] (jdbc/query db (to-sql-params relation) :result-set-fn vec))
JDBC рдХреЗ рд╕рд╛рде рд╕реАрдзреЗ рдХрд╛рдо рдХрд░рдирд╛ рдердХрд╛рдК рд╣реИ, рдЗрд╕рд▓рд┐рдП рдореБрд╢реНрдХрд┐рд▓ - clojure.java.jdbc рд╣рдорд╛рд░реЗ рд▓рд┐рдП рд╕рднреА рдЧрдВрджреЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред рдЕрдВрдд рдореЗрдВ, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдХрд╛рдлреА рд╕реНрд╡реАрдХрд╛рд░реНрдп рдкрд░рд┐рдгрд╛рдо рд╣реИрдВ, рдЖрдк рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХрд╛ рдЙрдкрдпреЛрдЧ рднреА рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:
; (def db {:classname "com.mysql.jdbc.Driver" :subprotocol "mysql" :user "test" :password "test" :subname "//localhost/test"}) ; (fetch-all db (as-sql '[SELECT * FROM :users ORDER BY :name]))
рдЕрд░реЗ рд╣рд╛рдБ, рд╣рдо
with-fetch
рдмрд╛рд░реЗ рдореЗрдВ рднреВрд▓ рдЧрдПред рд╣рдореЗрдВ рдПрд╣рд╕рд╛рд╕ рд╣реЛрддрд╛ рд╣реИ:
(defmacro with-fetch [db [v rel :as vr] & body] `(let [params
рдкреНрд░рд╢реНрдиреЛрдВ рдХреЛ рдХреНрд░рдорд┐рдХ рд░реВрдк рд╕реЗ рдмрдврд╝рд╛рдирд╛
рдЪрдпрдирд┐рдд рджреГрд╢реНрдп рдХреЗ рдЧрдВрднреАрд░ рдиреБрдХрд╕рд╛рди рд╣реИрдВ - рдкреНрд░рд╢реНрдиреЛрдВ рдХрд╛ рдирд┐рд░реНрдорд╛рдг рдХрд░рдирд╛ рдореБрд╢реНрдХрд┐рд▓ рд╣реИред рдорд╛рди рд▓реАрдЬрд┐рдП рдХрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдХ
SELECT FROM `Users` LIMIT 10
рд▓рд┐рдП рдПрдХ рдкреЗрдбрд╝ рд╣реИ, рдЬреЛ
SELECT FROM `Users` LIMIT 10
рдХреНрд╡реЗрд░реА рд╕реЗ рд╕рдВрдмрдВрдзрд┐рдд рд╣реИ, рдФрд░ рд╣рдо рдЗрд╕рдореЗрдВ рдПрдХ
WHERE
рд╕реЗрдХреНрд╢рди рдЬреЛрдбрд╝рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред рд╕рд╛рдорд╛рдиреНрдп рддреМрд░ рдкрд░, рдЗрд╕рдХреЗ рд▓рд┐рдП рдЖрдкрдХреЛ рдПрд╕рдХреНрдпреВрдПрд▓ рд╕рд┐рдВрдЯреИрдХреНрд╕ (рдПрдПрд╕рдЯреА рдЯреНрд░реА рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг) рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рдирд╛ рд╣реЛрдЧрд╛, рдЬреЛ рдХрд┐, рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдореИрдВ рдмрд╣реБрдд рд╕реЗ рдмрдЪрдирд╛ рдЪрд╛рд╣реВрдВрдЧрд╛ред
рд╣рдореЗрдВ "рдЗрдЯреЗрд░реЗрдЯрд┐рд╡рд▓реА рдмрд┐рд▓реНрдб рдЕрдк" рдкреНрд░рд╢реНрдиреЛрдВ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреНрдпреЛрдВ рд╣реИ? рдЦреИрд░, рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдпрд╣ рдЕрдкрдиреЗ рдЖрдк рдореЗрдВ рдПрдХ рдЙрдкрдпреЛрдЧреА рд╡рд┐рдХрд▓реНрдк рд╣реИред рдкреНрд░реЛрдЧреНрд░рд╛рдо рд▓рд┐рдЦрддреЗ рд╕рдордп, рд╣рдо рдЕрдХреНрд╕рд░ рдЕрдЧреНрд░рд┐рдо рдореЗрдВ рдирд╣реАрдВ рдЬрд╛рдирддреЗ рд╣реИрдВ рдХрд┐ рд╣рдо рдХреНрдпрд╛ рдЕрдиреБрд░реЛрдз рдкреВрд░рд╛ рдХрд░реЗрдВрдЧреЗред рдЙрджрд╛рд╣рд░рдг: рд╡реНрдпрд╡рд╕реНрдерд╛рдкрдХ рдкреИрдирд▓ рдореЗрдВ
WHERE
рдФрд░ ORDER BY рдЕрдиреБрднрд╛рдЧреЛрдВ рдХреЗ рд▓рд┐рдП рдЧрддрд┐рд╢реАрд▓ рд░реВрдк рд╕реЗ рдордирдорд╛рдиреЗ рдврдВрдЧ рд╕реЗ рд╕реНрдерд┐рддрд┐рдпрд╛рдВ рдмрдирд╛рдПрдВред
рд▓реЗрдХрд┐рди рдЗрд╕рд╕реЗ рднреА рдорд╣рддреНрд╡рдкреВрд░реНрдг рдмрд╛рдд, рдпрд╣ рдХреНрд▓реЛрдЬрд░ рдореЗрдВ рдкреНрд░реЛрдЧреНрд░рд╛рдо рд▓рд┐рдЦрддреЗ рд╕рдордп рдЕрдЪреНрдЫрд╛ рдЕрднреНрдпрд╛рд╕ рд╣реИред рд╣рдо рдХрдИ рдЫреЛрдЯреЗ рдЯреБрдХрдбрд╝реЛрдВ рдореЗрдВ рдХрд╛рдо рдХреЛ рддреЛрдбрд╝ рджреЗрддреЗ рд╣реИрдВ рдЬреЛ рдкреБрдирд░рд╛рд╡реГрддрд┐ рд╕реЗ рдЕрдкрдирд╛ рдХрд╛рдо рдХрд░рддреЗ рд╣реИрдВред рдЗрд╕ рддрд░рд╣ рдХреА рдкреНрд░рддреНрдпреЗрдХ рдИрдВрдЯ (рд╢реБрджреНрдз рдХрд╛рд░реНрдп) рдЗрдирдкреБрдЯ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рддреА рд╣реИ рдФрд░ "рд╕рд╣реА" рдкрд░рд┐рдгрд╛рдо рджреЗрддреА рд╣реИред рдИрдВрдЯреЛрдВ рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдФрд░ рд╡рд┐рдХрд╛рд╕ рдХрд░рдирд╛ рдЖрд╕рд╛рди рд╣реИред рдФрд░ рдЕрдВрдд рдореЗрдВ, рдпреЗ рдЯреБрдХрдбрд╝реЗ рдЖрд╕рд╛рдиреА рд╕реЗ рдПрдХ рд╕рд╛рде рдЖрддреЗ рд╣реИрдВред
рд╣рдо рдПрдХ рд╣реИрд╢ рддрд╛рд▓рд┐рдХрд╛ рдХреЗ рд░реВрдк рдореЗрдВ рдЕрдиреБрд░реЛрдзреЛрдВ рдХрд╛ рдкреНрд░рддрд┐рдирд┐рдзрд┐рддреНрд╡ рдХрд░рддреЗ рд╣реИрдВред рдПрдХ рдЙрджрд╛рд╣рд░рдг:
(def some-query-example { ; " - " :tables {:r :Roles, :u :Users}, ; [ , , ON] ; -- [ , nil, nil] ; , .. join' :joins [[:u nil nil] [:r :inner ['= :Users.role_id :Roles.id]]] ; ast- :where [:= :u.name "Ivan"], ; " - " :fields {:name :name, :role_name :role_name}, ; :offset 1000, :limit 100, ; order, group, having, etc... })
WHERE
,
ORDER BY
рдЖрджрд┐ рд╡рд░реНрдЧреЛрдВ рдХреЗ рд▓рд┐рдПред рд╣рдо рдПрдПрд╕рдЯреА рдПрдХреНрд╕рдкреНрд░реЗрд╢рди рдЯреНрд░реА рдХреЛ рд╕реНрдЯреЛрд░ рдХрд░рддреЗ рд╣реИрдВ - рдпрд╣ рдЖрд╕рд╛рди рд╣реИред рддрд╛рд▓рд┐рдХрд╛ рдФрд░ рдлрд╝реАрд▓реНрдб рдХреА рд╕реВрдЪреА рдХреЗ рд▓рд┐рдП рд╣рдо рд╢рдмреНрджрдХреЛрд╢реЛрдВ рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рддреЗ рд╣реИрдВ, рдЪрд╛рдмрд┐рдпрд╛рдБ рдЙрдкрдирд╛рдореЛрдВ рдХреЗ рдирд╛рдо рд╣реИрдВ, рдорд╛рди рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рдпрд╛ рдЯреЗрдмрд▓ рдирд╛рдо рд╣реИрдВред рдЗрд╕ рд╕рдВрд░рдЪрдирд╛ рдХреЗ рдврд╛рдВрдЪреЗ рдХреЗ рднреАрддрд░, рд╣рдо рдЖрд╡рд╢реНрдпрдХ рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рддреЗ рд╣реИрдВ:
; `limit` & `offset` (defn limit [relation v] (assoc relation :limit v)) ; ** (defn fields [query fd] (assoc query :fields fd)) (defn where [query wh] (assoc query :where wh)) ; helper- (defn join* [{:keys [tables joins] :as q} type alias table on] (let [a (or alias table)] (assoc q :tables (assoc tables a table) :joins (conj (or joins []) [a type on])))) (defn from ([q table] (join* q nil table table nil)) ([q table alias] (join* q nil table alias nil))) (defn join-cross ([q table] (join* q :cross table table nil)) ([q table alias] (join* q :cross table alias nil))) ;; join- (left, right, full) -
рдЗрд╕рд▓рд┐рдП, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдХрдИ рдХрд╛рд░реНрдп рд╣реИрдВ (
where
,
fields
,
from
,
join
,
limit
рдФрд░ рдЕрдиреНрдп) рдЬреЛ "рдЯреНрд╡реАрдХ" рдЕрдиреБрд░реЛрдз рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдкреНрд░рд╕реНрдерд╛рди рдмрд┐рдВрджреБ рдПрдХ рдЦрд╛рд▓реА рдЕрдиреБрд░реЛрдз рд╣реИред
(def empty-select {})
рдЕрдм рд╣рдо рд▓рд┐рдЦ рд╕рдХрддреЗ рд╣реИрдВ:
(-> empty-select (fields [:name :role_name]) (from :Users) (limit 100))
рдпрд╣ рдХреЛрдб рдПрдХ рдореИрдХреНрд░реЛ
-> рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ, рдЬреЛ рдХреБрдЫ рдЗрд╕ рддрд░рд╣ рд╕реЗ рд╡рд┐рд╕реНрддрд╛рд░рд┐рдд рд╣реЛрддрд╛ рд╣реИ:
(limit (from (fields empty-select [:name :role_name]) :Users) 100)
рд╕реБрдВрджрд░рддрд╛ рдХреЗ рд▓рд┐рдП, рдЕрдкрдиреЗ
select
рдореИрдХреНрд░реЛ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░реЗрдВ, рдЬреЛ рд╡реНрдпрд╡рд╣рд╛рд░ рдХрд░рддрд╛ рд╣реИ
->
:
(defmacro select [& body] `(-> empty-select ~@body))
рдпрд╣ рд╣рдорд╛рд░реА рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХреЛ рд╕рд┐рдЦрд╛рддрд╛ рд╣реИ рдХрд┐ рдПрдХ рджреГрд╢реНрдп рдХреЛ рджреВрд╕рд░реЗ рдореЗрдВ рдХреИрд╕реЗ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПред
; SQL, nil "NULL" (def NONE (Sql. "" nil)) ; (defn render-limit [s] (if-let [l (:limit s)] ['LIMIT l] NONE)) (defn render-fields [s] '*) ; ; (defn render-where [s] NONE) (defn render-order [s] NONE) (defn render-expression [s] NONE) ; (defn render-group [s] NONE) (defn render-having [s] NONE) (defn render-offset [s] NONE) ; (defn render-table [[alias table]] (if (= alias table) ; , 'AS' table [table 'AS alias])) (defn render-join-type [jt] (get {nil (symbol ",") :cross '[CROSS JOIN], :left '[LEFT OUTER JOIN], :right '[RIGHT OUTER JOIN], :inner '[INNER JOIN], :full '[FULL JOIN], } jt jt)) ; (defn render-from [{:keys [tables joins]}] ; FROM ! (if (not (empty? joins)) ['FROM ; (let [[a jn] (first joins) t (tables a)] ; `(from ..)` (assert (nil? jn)) (render-table [at])) ; (for [[a jn c] (rest joins) :let [t (tables a)]] [(render-join-type jn) ; JOIN XX (render-table [at]) ; (if c ['ON (render-expression c)] NONE) ; 'ON' ])] NONE)) (defn render-select [select] ['SELECT (mapv #(% select) [render-fields render-from render-where render-group render-having render-order render-limit render-offset])])
рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛
SqlLike
рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдФрд░
as-sql
рдлрд╝рдВрдХреНрд╢рди рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рднреА рдирд╣реАрдВ рдЬрд╛рдирддреЗ
SqlLike
ред рдЕрдЪреНрдЫрд╛ рдЕрднреНрдпрд╛рд╕ред рддреБрд▓рдирд╛ рдореЗрдВ, рдЬрд╛рд╡рд╛ рдореЗрдВ, рдЗрдВрдЯрд░рдлреЗрд╕ рдЕрдХреНрд╕рд░ рдПрдХ рдореЙрдбреНрдпреВрд▓ / рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдПрдкреАрдЖрдИ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рддреЗ рд╣реИрдВред рдХреНрд▓реЛрдЬрд░ рдореЗрдВ, рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдЖрдорддреМрд░ рдкрд░ рд╕рдмрд╕реЗ рдирд┐рдЪрд▓реЗ рд╕реНрддрд░ рдХреЗ рд╕рдВрдЪрд╛рд▓рди рдХреЗ рд▓рд┐рдП рдмрдирд╛рдП рдЬрд╛рддреЗ рд╣реИрдВ, рдХреБрдЫ рдЖрдзрд╛рд░ рдЬрд┐рдирдХреЗ рдЖрдзрд╛рд░ рдкрд░ рд╕рд╣рд╛рдпрдХ рдХрд╛рд░реНрдпреЛрдВ рдХрд╛ рдПрдХ рд╕реЗрдЯ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдХрд╛рдо рдХрд░ рд░рд╣рд╛ рд╣реИред рдФрд░ рдЕрдм рдпреЗ рд╕рд╣рд╛рдпрдХ рд╕рд╛рд░реНрд╡рдЬрдирд┐рдХ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдПрдкреАрдЖрдИ рдкреНрд░рджрд╛рди рдХрд░рддреЗ рд╣реИрдВред рд╣рдо рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдХреНрд╡реЗрд░реА рдЙрддреНрдкрдиреНрди рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░ рд░рд╣реЗ рд╣реИрдВ:
(fetch-all db (render-select (select (from :Users) (limit 10)))
рд╣реЛ рдЧрдпрд╛! рд╕рд╣реА рд╣реИ, рдХреЙрд▓рд┐рдВрдЧ
render-select
рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рдердХрд╛рдК рд╣реИред рд╣рдо рдареАрдХ рдХрд░рддреЗ рд╣реИрдВ:
(declare render-select) ; ; record , (defrecord Select [fields where order joins tables offet limit] SqlLike (as-sql [this] (as-sql (render-select this)))) (def empty-select (map->Select {}))
рдЕрдм рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рддреЗ рд╕рдордп
(as-sql (select ...))
,
render-select
рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдХрд╣рд╛ рдЬрд╛рдПрдЧрд╛:
(fetch-all db (select (from :Users) (limit 10))) ; SQL (as-sql (select (from :Table) (limit 10))) ; (select (from :Table) (limit 10) (as-sql))
рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рдХрд╛ рд╕рдорд░реНрдерди
рдЪрд▓рд┐рдП рд▓рд┐рдЦрддреЗ рд╣реИрдВ
where
рдлрдВрдХреНрд╢рди
where
рд╣реИред рд╣рдо рдЗрд╕реЗ рдЗрд╕ рддрд░рд╣ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛрдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ:
(select (from :Table) (where (and (> :x 1) (== :y "z"))))
рдЬрд╛рд╣рд┐рд░ рд╣реИ, рдЖрдк рдХреЙрд▓ рдХреЗ рд╕рдордп
(> :x 1)
рдЧрдгрдирд╛ рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ -
where
рдЖрдкрдХреЛ рдореИрдХреНрд░реЛ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рд╣рдо рдПрдХ рдПрдПрд╕рдЯреА рдкреЗрдбрд╝ рдХреЗ рд░реВрдк рдореЗрдВ рдирд┐рд░реНрдорд┐рдд рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐рдпреЛрдВ рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░реЗрдВрдЧреЗ: рдиреЛрдбреНрд╕ рдСрдкрд░реЗрдЯрд░ рд╣реИрдВ, рдкрддреНрддрд┐рдпрд╛рдВ рд▓рдЧрд╛рддрд╛рд░ рдФрд░ рдХреНрд╖реЗрддреНрд░ рд╣реИрдВред рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд╕рд╣рд╛рдпрдХ рдлрд╝рдВрдХреНрд╢рди рд▓рд┐рдЦреЗрдВ
where*
:
; 2 AND (defn- conj-expression [e1 e2] (cond (not (seq e1)) e2 (= 'and (first e1)) (conj (vec e1) e2) :else (vector 'and e1 e2))) (conj-expression '[> 1 2] '[< "a" "b"]) ; => '[and [> 1 2] [< "a" "b"]]) (conj-expression '[and [> 1 [+ 2 3]] [= :x :y]] '[<> "a" "b"]) ; => '[and [> 1 [+ 2 3]] [= :x :y] [<> "a" "b"]] (defn where* [query expr] (assoc query :where (conj-expression (:where query) expr)))
рдЕрдм рдпрд╣
render-where
рд▓рд┐рдП рд╕рдордп рд╣реИ,
render-where
:
; (declare render-operator) (declare render-expression) ; ? (defn- function-symbol? [s] (re-matches #"\w+" (name s))) ; (defn render-operator [op & args] (let [ra (map render-expression args) lb (symbol "(") rb (symbol ")")] (if (function-symbol? op) ; (count, max, ...) [op lb (interpose (symbol ",") ra) rb] ; (+, *, ...) [lb (interpose op (map render-expression args)) rb]))) (defn render-expression [etree] (if (and (sequential? etree) (symbol? (first etree))) (apply render-operator etree) etree)) (defn render-where [{:keys [where]}] (if where ['WHERE (render-expression where)] NONE))
рдареАрдХ рд╣реИ, рдЕрдм рд╣рдо рд╕рдмрд╕реЗ рд╕рд░рд▓ рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рд▓рд┐рдЦ рд╕рдХрддреЗ рд╣реИрдВ:
(select (from :Users) (where* ['= :id 1]) (as-sql))
рдпрд╣ рдмрджрд╕реВрд░рдд рдирд┐рдХрд▓рд╛, рдЗрд╕реЗ рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдореИрдХреНрд░реЛ рдХреЗ рд╕рд╛рде рдареАрдХ рдХрд░реЗрдВ:
(defn prepare-expression [e] (if (seq? e) `(vector (quote ~(first e)) ~@(map prepare-expression (rest e))) e)) (defmacro where [q body] `(where* ~q ~(prepare-expression body)))
рд╡реИрдХреНрдЯрд░ рдХреЗ рд╕рд╛рде рд╕рднреА рдЕрдиреБрдХреНрд░рдореЛрдВ (рд╕реВрдЪрд┐рдпреЛрдВ) рдХреЛ рдмрджрд▓реЗрдВред рд╢реЗрд╖ рдорд╛рдиреЛрдВ рдХреЛ рдЫреЛрдбрд╝ рджрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред рд╣рдо рдПрдХ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдмрд┐рдВрджреБ рд╕реЗ рдЪреВрдХ рдЧрдП - рдХреНрд▓реЛрдЬрд░ рдФрд░ рдПрд╕рдХреНрдпреВрдПрд▓ рдореЗрдВ рдХреБрдЫ рдмрдпрд╛рдиреЛрдВ рдХреЛ рдЕрд▓рдЧ рддрд░рд╣ рд╕реЗ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП,
<>
рдФрд░
not=
ред рдПрдХ рджрд╛рд░реНрд╢рдирд┐рдХ рдкреНрд░рд╢реНрди, рдХрд┐рд╕ рд╡рд┐рдХрд▓реНрдк рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдмреЗрд╣рддрд░ рд╣реИред рдПрдХ рдУрд░, рд╣рдордиреЗ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХреЛ "рдмреЗрд╡рдХреВрдл" рдХреЗ рд░реВрдк рдореЗрдВ рд╕рдВрднрд╡ рдХреЗ рд░реВрдк рдореЗрдВ рдЫреЛрдбрд╝рдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛, рджреВрд╕рд░реА рдУрд░, "рджреЗрд╢реА" рдХреНрд▓реЛрдЬрд░ рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рджреЗрдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рдерд╛ред рдЪрд▓реЛ рджреЛрдиреЛрдВ рд╡рд┐рдХрд▓реНрдкреЛрдВ рдХреЛ рд╕рдХреНрд╖рдо рдХрд░рддреЗ рд╣реИрдВ:
(defn- canonize-operator-symbol [op] (get '{not= <>, == =} op op)) ; (defn prepare-expression [e] (if (seq? e) `(vector (quote ~(canonize-operator-symbol (first e))) ~@(map prepare-expression (rest e))) e))
рдареАрдХ рд╣реИ,
where
рдореИрдХреНрд░реЛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╕рдордп, рдЖрдк рджреЛрдиреЛрдВ рд▓рд┐рдЦ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рд╣рдорд╛рд░реЗ рдХреНрд╡реЗрд░реА рджреГрд╢реНрдп рдореЗрдВ рдХреЗрд╡рд▓ рдПрдХ рд╣реА рд╣реЛрдЧрд╛ред рдЖрдкрдХреЛ рдХреНрдпрд╛ рдЪрд╛рд╣рд┐рдП рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЕрднреА рднреА рдПрдХ рдЫреЛрдЯрд╛ рд╕рд╛ рдХрд░реНрдЬ рд╣реИ - рдЬреБрдбрд╝рдиреЗ рд╕реЗ рдХрд╛рдо рдирд╣реАрдВ рдЪрд▓рддрд╛ред
(defmacro join-left ([q table cond] `(let [t# ~table] (join-left ~qt# t# ~cond))) ([q table alias cond] (join* ~q :cross ~table ~alias ~(prepare-expression cond))))
рдХрдИ рд╕рдорд╛рди рдореИрдХреНрд░реЛрдЬрд╝ рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдЗрдореЛрдмрд▓ рдЕрдлреЗрдпрд░ рд╣реИ:
; `do-template` (use 'clojure.template) ; 5 (do-template [join-name join-key] ; ; (defmacro join-name ([relation alias table cond] `(join* ~relation ~join-key ~alias ~table ~(prepare-expression cond))) ([relation table cond] `(let [table# ~table] (join* ~relation ~join-key nil table# ~(prepare-expression cond))))) ; join-inner :inner, join :inner, join-right :right, join-left :left, join-full :full)
рдЕрдзрд┐рдХ рд╕реБрд╡рд┐рдзрд╛рдПрдБ
рдЕрдм рддрдХ рд╣рдо рдХреЗрд╡рд▓ рд╕рдмрд╕реЗ рд╕рд░рд▓ рдкреНрд░рд╢реНрдиреЛрдВ рдХреЛ рдкреВрд░рд╛ рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реИрдВред рд╣рдо рд╕реНрддрдВрднреЛрдВ рдХреА рд╕реВрдЪреА рдореЗрдВ рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐рдпреЛрдВ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░реЗрдВрдЧреЗред
; `f` `m` ( ) (defn- map-vals [fm] (into (if (map? m) (empty m) {}) (for [[kv] m] [k (fv)]))) ; (def surrogate-alias-counter (atom 0)) ; :__00001234 (defn generate-surrogate-alias [] (let [k (swap! surrogate-alias-counter
рдмреБрд░рд╛ рдирд╣реАрдВ рд╣реИред рдЕрдм рдЖрдк рдЗрд╕ рддрд░рд╣ рд▓рд┐рдЦ рд╕рдХрддреЗ рд╣реИрдВ:
(select (fields {:n :name, :a :age}) ; (from :users)) ; (select (fields {:cnt (count :*), :max-age (max :age)}) (from :users)) ; (select (fields [(count :*)]) (from :users))
рдЫрдБрдЯрд╛рдИ рдЬреЛрдбрд╝реЗрдВред рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рд╕рд╛рдорд╛рдиреНрдп рдХреНрд░рд┐рдпрд╛рдУрдВ рдХрд╛ рдХреНрд░рдо: рдПрдХ
order*
рдлрдВрдХреНрд╢рди рдФрд░ рдПрдХ
order
рдореИрдХреНрд░реЛ рдмрдирд╛рдПрдВ,
render-order
рд▓рд╛рдЧреВ
render-order
:
(defn order* ([relation column] (order* relation column nil)) ([{order :order :as relation} column dir] (assoc relation :order (cons [column dir] order)))) (defmacro order ([relation column] `(order* ~relation ~(prepare-expression column))) ([relation column dir] `(order* ~relation ~(prepare-expression column) ~dir))) (defn render-order [{order :order}] (let [f (fn [[cd]] [(render-expression c) (get {nil [] :asc 'ASC :desc 'DESC} dd)])] (if order ['[ORDER BY] (interpose (symbol ",") (map f order))] [])))
рдЕрдм рдЖрдк рдордирдорд╛рдиреА рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рд╕рд╣рд┐рдд рд╣рдорд╛рд░реЗ рдкреНрд░рд╢реНрдиреЛрдВ рдореЗрдВ рдЪрдпрди рдХреЛ рдЫрд╛рдБрдЯ рд╕рдХрддреЗ рд╣реИрдВ:
(select (from :User) (order (+ :message_cnt :post_cnt)))
рдЗрд╕реА рддрд░рд╣ рд╕реЗ, рд╣рдо рд╕рдореВрд╣, рдЙрдкрд╢реНрд░реЗрдгрд┐рдпреЛрдВ рдФрд░ рдЗрд╕ рддрд░рд╣ рдХреЗ рд▓рд┐рдП рд╕рдорд░реНрдерди рдЬреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВ ... рдпрд╣рд╛рдБ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП,
UNION ALL
рд▓рд┐рдП рдПрдХ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди
UNION ALL
рддрд░рд╣ рд▓рдЧ рд╕рдХрддрд╛ рд╣реИ:
; - (defn render-union-all [{ss :selects}] (interpose ['UNION 'ALL] (map render-select ss))) ; , (defrecord UnionAll [selects] SqlLike (as-sql [this] (as-sql (render-union-all this)))) ; ** - (defn union-all [& ss] (->UnionAll ss)) ;; ... (as-sql (union-all (select (from :Users) (fields [:email])) (select (from :Accounts) (fields [:email]))))
рдХрдИ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЗ рд▓рд┐рдП рд╕рдорд░реНрдерди - рдмреЛрд▓рд┐рдпрд╛рдБ
рдХрдИ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЗ рд▓рд┐рдП рд╕рдорд░реНрдерди рдЬреЛрдбрд╝реЗрдВред рдпрд╣ рд╡рд┐рдЪрд╛рд░ рд╕рд░рд▓ рд╣реИ: рд╣рдорд╛рд░реЗ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдореЗрдВ рдХрдИ рдХрд╛рд░реНрдп рд╣рдорд╛рд░реЗ рд╡реНрдпрд╡рд╣рд╛рд░ рдХреЛ рдмрджрд▓ рд╕рдХрддреЗ рд╣реИрдВ рдЬреЛ рд╣рдо рдЖрдзрд╛рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВред рд╣рдо рдмреЛрд▓рд┐рдпреЛрдВ рдХреЗ рдкреЗрдбрд╝ рдХреА рддрд░рд╣ рдкрджрд╛рдиреБрдХреНрд░рдо рдХрд╛ рдЖрдпреЛрдЬрди рдХрд░рддреЗ рд╣реИрдВ:
; (def ^:const default-dialect ::sql92) ; (def ^:dynamic *dialect* nil) ; (def dialects-hierarchy (make-hierarchy)) ; , (defn register-dialect ([dialect parent] (alter-var-root #'dialects-hierarchy derive dialect parent)) ; ::sql92 ([dialect] (register-dialect dialect default-dialect))) ; (register-dialect ::pgsql) (register-dialect ::pgsql92 ::pgsql) ; postgresql ; ad-hoc (register-dialect ::my-custom-db-with-extra-functions ::pgsql92)
рдЕрдм рдПрдХ рдЫреЛрдЯреЗ рд╕реЗ
defndialect
рдореИрдХреНрд░реЛ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░реЗрдВ:
; ; (defn current-dialect [& _] (or *dialect* default-dialect)) ; "" (defmacro defndialect [name & args-and-body] `(do ; (defmulti ~name current-dialect :hierarchy
рдЕрдм рдЖрдкрдХреЛ
*dialect*
рдЪрд░ рдореЗрдВ рдмреЛрд▓реА рдореВрд▓реНрдп рдбрд╛рд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдпрд╛рдж рд░рдЦрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:
(defmacro with-db-dialect [db & body] ; `(binding [*dialect* (:dialect ~db)] ~@body))
рдмрд╣реБрдд рдмрдврд╝рд┐рдпрд╛ред рдЕрдВрддрд┐рдо рдЪрд░рдг рдмрдирд╛ рд╣реБрдЖ рд╣реИ: рд╣рдо рд░реЗрдВрдбрд░рд┐рдВрдЧ рдХреЗ рд▓рд┐рдП рдлрд╝рдВрдХреНрд╢рди рдХреА рд╕рднреА рдкрд░рд┐рднрд╛рд╖рд╛рдУрдВ рдХреЛ рдлрд┐рд░ рд╕реЗ рд▓рд┐рдЦрддреЗ рд╣реИрдВ,
defndialect
рд╕рд╛рде
defndialect
рдХреЛ
defndialect
ред рдлрд╝рдВрдХреНрд╢рди рдмреЙрдбреА рдХреЛ рдмрджрд▓рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИред рдФрд░ рдЕрдм рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдЕрд▓рдЧ-рдЕрд▓рдЧ SQL рдЬреЗрдирд░реЗрдЯ рдХрд░рдиреЗ рдХрд╛ рдЕрд╡рд╕рд░ рд╣реИ:
(defndialect quote-name [s] (let [x (name s)] (if (= "*" x) x (str "\"" x "\"")))) ; MySQL (defmethod quote-name ::mysql [s] (let [x (name s)] (if (= "*" x) x (str "`" x "`"))))
рдЕрдВрдд рдореЗрдВ, рд╣рдордиреЗ рджреЗрдЦрд╛ рдХрд┐ рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк
with-db-dialect
fetch-*
рдХреЛ рдХреЙрд▓ рдХрд░рдиреЗ рдХреА рдХреЛрдИ рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ, рдЖрдк рд╣рдорд╛рд░реЗ
fetch-*
рдХреЛ рдлрд┐рд░ рд╕реЗ рд▓рд┐рдЦ рд╕рдХрддреЗ
fetch-*
:
(defn fetch-all [db relation] (jdbc/query db (with-db-dialect db (to-sql-params relation)) :result-set-fn vec)) ; fetch-*
RAW рдЕрдиреБрд░реЛрдз
рдХрднреА-рдХрднреА рдЖрдкрдХреЛ рдмрд╣реБрдд рд╡рд┐рд╢рд┐рд╖реНрдЯ рдкреНрд░рд╢реНрдиреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ - рд╡реЗ рдбреАрдПрд╕рдПрд▓ рдХреЛ рджрд░рдХрд┐рдирд╛рд░ рдХрд░рддреЗ рд╣реБрдП рдПрдХ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЗ рд░реВрдк рдореЗрдВ рд▓рд┐рдЦрдирд╛ рдЖрд╕рд╛рди рд╣реЛрддреЗ рд╣реИрдВред рдХреЛрдИ рд╕рдорд╕реНрдпрд╛ рдирд╣реАрдВ:
(require '[clojure.string :as s]) (defn format-sql [raw-sql args] (let [; :x al (map (comp keyword second) (re-seq #":([\w.-]+)" raw-sql)) ; "?" pq (s/replace raw-sql #":[\w.-]+" "?")] (->Sql pq (map args al)))) ; ... (fetch-all db (format-sql "SELECT * FROM Users WHERE role = :rl AND age < :age" {:rl "admin" :age 18}))
рд╡реИрд╕реЗ, рдЗрд╕ рддрд░рд╣ рд╕реЗ рдЙрддреНрдкрдиреНрди рдХреНрд╡реЗрд░реА рдХрд╛ рдЙрдкрдпреЛрдЧ
UNION ALL
рдореЗрдВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдЬрд┐рд╕реЗ рд╣рдордиреЗ рдереЛрдбрд╝рд╛ рдЕрдзрд┐рдХ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рд╣реИред рджреБрд░реНрднрд╛рдЧреНрдп рд╕реЗ, рд╡реЗ рдЖрдХрд╕реНрдорд┐рдХ рд░реВрдк рд╕реЗ рдкрд░рд┐рд╡рд░реНрддрди рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рдирд╣реАрдВ рд╣реЛрдВрдЧреЗ - рдЗрд╕рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ SQL рдХреЛрдб рдХреЗ рд╕рд╛рде рдПрдХ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдкрд╛рд░реНрд╕ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред рд╕рдорд╛рдзрд╛рди - рдЙрдкрд╢реНрд░реЗрдгрд┐рдпрд╛рдБ:
(defn users-by-role [r] (format-sql "SELECT * FROM Users WHERE role = :r" {:rr})) ; (-> (users-by-role "ADMIN") (order :name) (as-sql)) ; ..? (select (from :x (users-by-role "ADMIN")) (order :name) (as-sql)) ; => #user.Sql{:sql "SELECT * FROM SELECT * FROM Users WHERE role = ? AS `x` ORDER BY `name`", :args ("ADMIN")}
рдЙрдлрд╝, рдЙрддреНрдкрдиреНрди SQL рдореЗрдВ рдкрд░реНрдпрд╛рдкреНрдд рдХреЛрд╖реНрдардХ рдирд╣реАрдВ рд╣реИрдВред рд╣рдо рдУрд╡рд░рд╕рд╛рдЗрдЯ рдХреЛ рд╕рдорд╛рдкреНрдд рдХрд░рддреЗ рд╣реИрдВ, рдпрд╣рд╛рдБ
render-table
рдХрд╛ рд╕рд╣реА рд╕рдВрд╕реНрдХрд░рдг рд╣реИ:
(defn render-table [[alias table]] (if (= alias table) ; , 'AS' table ; - sql - (if (or (instance? Sql table) (instance? Select table)) [(symbol "(") table (symbol ")") 'AS alias] [table 'AS alias]))) ; (select (from :x (users-by-role "ADMIN")) (order :name) (as-sql))
рд╕реНрдерд╛рдпреА рдбреЗрдЯрд╛рдмреЗрд╕ рдХрдиреЗрдХреНрд╢рди
рдмреЗрд╢рдХ, рд╣рд░ рдмрд╛рд░ рдПрдХ рдирдпрд╛ рдХрдиреЗрдХреНрд╢рди рдЦреЛрд▓рдирд╛
fetch-*
рдХреЗ
fetch-*
рдлрд╝рдВрдХреНрд╢рди рдПрдХ рд╡рд┐рдХрд▓реНрдк рдирд╣реАрдВ рд╣реИред рдореИрдХреНрд░реЛ рдлрд┐рд░:
(defn with-connection* [db body-fn] (assert (nil? (jdbc/db-find-connection db))) (with-open [conn (jdbc/get-connection db)] (body-fn (jdbc/add-connection db conn)))) (defmacro with-connection [binding & body] `(with-connection* ~(second binding) (fn [~(first binding)] ~@body)))
рдпрд╣рд╛рдВ рд╣рдо рдЬрд╛рдВрдЪрддреЗ рд╣реИрдВ рдХрд┐ рдЕрднреА рднреА рдХреЛрдИ рдЦреБрд▓рд╛ рдХрдиреЗрдХреНрд╢рди рдирд╣реАрдВ рд╣реИ, рдПрдХ рдирдпрд╛ рдЦреЛрд▓реЗрдВ рдФрд░ рдЗрд╕реЗ рдбреЗрдЯрд╛рдмреЗрд╕ рдорд╛рдкрджрдВрдбреЛрдВ рдХреЗ рд╕рд╛рде рд╢рдмреНрджрдХреЛрд╢ рдореЗрдВ "рд╕рдВрд▓рдЧреНрди" рдХрд░реЗрдВред рдЖрдкрдХреЛ рдЗрд╕реЗ рдЗрд╕ рддрд░рд╣ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:
(def db {...}) (with-connection [c db] ; e `c` `db` + (fetch-all c (select (from :B))) ; ... (fetch-all c (select (from :A))))
рдЗрд╕реА рддрд░рд╣ рд╕реЗ, рдЖрдк рд▓реЗрди-рджреЗрди рдХрд╛ рд╕рдорд░реНрдерди рдЬреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВред
рдПрдХ рдЫреЛрдЯрд╛ рдмреЛрдирд╕ - рдЕрд╕рд╛рдорд╛рдиреНрдп рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рдХреЗ рддрддреНрд╡реЛрдВ рдХреЗ рд╕рд╛рде рдЕрдзрд┐рдХ рдЧрддрд┐рдЬрд╛рд╣рд┐рд░ рд╣реИ, рдкреБрд╕реНрддрдХрд╛рд▓рдп рдЕрддрд┐рд░рд┐рдХреНрдд рд▓рд╛рдЧрддреЛрдВ рдХрд╛ рдкрд░рд┐рдЪрдп рджреЗрддрд╛ рд╣реИ: рдЖрдкрдХреЛ рдЙрдЪреНрдЪрддрдо рд╕реНрддрд░ рдХреЗ рдкреНрд░рддрд┐рдирд┐рдзрд┐рддреНрд╡ рдореЗрдВ рдореВрд▓ рдХреНрд╡реЗрд░реА рдмрдирд╛рдиреЗ рдХреА рдЬрд░реВрд░рдд рд╣реИ, рдЗрд╕реЗ
render-select
рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдкрд░рд┐рд╡рд░реНрддрд┐рдд
render-select
, рдкрд░рд┐рдгрд╛рдо
as-sql
рдорд╛рдзреНрдпрдо рд╕реЗ рдкрд╛рд╕ рдХрд░реЗрдВред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдХрдИ рдХрд╛рд░реНрдпреЛрдВ рдХреЛ
defndialect
рдорд╛рдзреНрдпрдо рд╕реЗ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЬреЛ рдкреНрд░рджрд░реНрд╢рди рдХреЛ рднреА рдирдХрд╛рд░рд╛рддреНрдордХ рд░реВрдк рд╕реЗ рдкреНрд░рднрд╛рд╡рд┐рдд рдХрд░рддрд╛ рд╣реИред "рдЖрдИрдбреА рджреНрд╡рд╛рд░рд╛ рд░рд┐рдХреЙрд░реНрдб рдЦреАрдВрдЪреЛ" рдЬреИрд╕реЗ рд╕рд░рд▓ рдкреНрд░рд╢реНрдиреЛрдВ рдХреЗ рд▓рд┐рдП рдЗрд╕ рддрд░рд╣ рдХреЗ рдСрдкрд░реЗрд╢рди рдХреЛ рджреЛрд╣рд░рд╛рдирд╛ рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рдХрд╖реНрдЯрдкреНрд░рдж рд╣реИред рд╕рдЪ рдореЗрдВ, рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЗ рд╕рдордп рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рдУрд╡рд░рд╣реЗрдб рдмрд╣реБрдд рд╣реА рдорд╣рддреНрд╡рд╣реАрди рд╣реИ ... рд▓реЗрдХрд┐рди рдПрдХ рдордЬрдмреВрдд рдЗрдЪреНрдЫрд╛ рдХреЗ рд╕рд╛рде, рдЖрдк рдФрд░ рднреА рдЕрдзрд┐рдХ рдЧрддрд┐ рдЬреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВред рддреЛ рд╣рдорд╛рд░рд╛ рд▓рдХреНрд╖реНрдп:
; , SQL (defselect get-user-by-id [x] (from :Users) (where (= :id x)))) ; , legacy (defselect get-user-by-id [x] "SELECT * FROM `Users` WHERE `id` = :x") ; (fetch-one db (get-user-by-id 123))
рдПрдХ рд╕рдорд╕реНрдпрд╛ рд╣реИ - рдмреЛрд▓рд┐рдпрд╛рдБред рд╣рдо рдХрд╛рд░реНрдпрдХреНрд░рдо рдХреЗ рд╕рдВрдХрд▓рди рдЪрд░рдг (рд╕реНрдереВрд▓ рдирд┐рдХрд╛рдп) рдореЗрдВ рдХреНрд╡реЗрд░реА рдХреА рдЧрдгрдирд╛ рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ, рдХреНрдпреЛрдВрдХрд┐ рд╣рдореЗрдВ рдирд╣реАрдВ рдкрддрд╛ рд╣реИ рдХрд┐ рдирд┐рд╖реНрдкрд╛рджрди рдХреЗ рджреМрд░рд╛рди рдХреМрди рд╕реА рдмреЛрд▓реА рд╕рдХреНрд░рд┐рдп рд╣реЛрдЧреАред рдЖрдк рд╕рднреА рдЙрдкрд▓рдмреНрдз рдмреЛрд▓рд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП рдХреНрд╡реЗрд░реА рдХреА рдкреВрд░реНрд╡-рдЧрдгрдирд╛ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдЙрдиреНрд╣реЗрдВ рдЧрддрд┐рд╢реАрд▓ рд░реВрдк рд╕реЗ (рд░рдирдЯрд╛рдЗрдо рдореЗрдВ) рдЬреЛрдбрд╝рд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ - рд╕рдмрд╕реЗ рдЕрдзрд┐рдХ рд╕рдВрднрд╛рд╡рдирд╛ рд╣реИ рдХрд┐ рд╣рдо рд╕рд╣реА рдПрдХ рдХреЛ рдпрд╛рдж рдХрд░реЗрдВрдЧреЗ, рдмреБрд░реА рддрд░рд╣ рд╕реЗред
рдПрдХ рд╡реИрдХрд▓реНрдкрд┐рдХ рд╕рдорд╛рдзрд╛рди рд╣реИ рдХрдореНрдкреНрдпреВрдЯреЗрдб рдкреНрд░рд╢реНрдиреЛрдВ рдХреЛ рдХреИрд╢ рдХрд░рдирд╛ред рдпрд╛рдиреА рдЗрд╕ рддрд░рд╣ рдХреЗ рдкреНрд░рддреНрдпреЗрдХ
defselect
рдХреИрд╢ рдХреЛ рд╕рдВрдЪрд┐рдд рдХрд░рддреЗ рд╣реИрдВ - рдПрдХ рд╢рдмреНрджрдХреЛрд╢ "рдмреЛрд▓реА - SqlLike-object"ред рдЗрд╕ рдкреНрд░рдХрд╛рд░, рдкреНрд░рддреНрдпреЗрдХ рдмреЛрд▓реА рдХреЗ рд▓рд┐рдП, рд╣рдо рдкреНрд░рддреНрдпреЗрдХ рдмреЛрд▓реА рдХреЗ рд▓рд┐рдП рдПрдХ рдмрд╛рд░ (рдЬрдЯрд┐рд▓ рдкреНрд░рд╢реНрдиреЛрдВ рдХреЗ рд▓рд┐рдП рдорд╣рдВрдЧрд╛) рд╕рдВрдХрд▓рди рдХрд░рддреЗ рд╣реИрдВред
Sql
рд░рд┐рдХреЙрд░реНрдб рдирд┐рдХрд╛рд▓рдиреЗ рдХреЗ рдмрд╛рдж, рд╣рдо рдХреНрд╖реЗрддреНрд░ рдореЗрдВ рдЖрд╡рд╢реНрдпрдХ рддрд░реНрдХреЛрдВ рдХреЛ рдкреНрд░рддрд┐рд╕реНрдерд╛рдкрд┐рдд рдХрд░рддреЗ рд╣реИрдВ
:args
, рдмрд┐рдирд╛ рдмрджрд▓реЗ
:sql
ред
; - SQL (defrecord LazySelect [content-fn] SqlLike (as-sql [this] (content-fn))) ; (defrecord RenderedSelect [content] SqlLike (as-sql [this] (as-sql content))) ; (defrecord SurrogatedArg [symbol] SqlLike (as-sql [this] (Sql. symbol "?"))) (defn emit-precompiled-select [name args body] (let [; args - sargs (map ->SurrogatedArg args) ; sargs-args (into {} (map vector sargs args))] `(let [sqls# (atom {}) ; ; "" original# (fn ~name ~args (as-sql (select ~@body))) ; , ; compile# (fn [] (apply original# (list ~@sargs)))] (defn ~name ~args (->LazySelect (fn [] (let [; , ; dialect# (current-dialect) cached-sql# (get @sqls# dialect#) ; - sql# (if cached-sql# cached-sql# ; ; , ; - (let [new-sql# (compile#)] (swap! sqls# assoc dialect# new-sql#) new-sql#)) ; args# (:args sql#)] ; (assoc sql# :args (replace ~sargs-args args#))))))))) ; (defn emit-raw-select [name args sql] ; (let [args-map (into {} (map (juxt keyword identity) args))] ; , RenderedSelect `(defn ~name ~args (->RenderedSelect (format-sql ~sql ~args-map))))) (defmacro defselect [name args & body] (if (and (== 1 (count body)) (string? (first body))) (emit-raw-select name args (first body)) (emit-precompiled-select name args body)))
рдирд┐рд╖реНрдХрд░реНрд╖ рдореЗрдВ
рдЖрд▓реЗрдЦ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЛ рд╕рдВрд╢реЛрдзрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЛ рдкреНрд░рднрд╛рд╡рд┐рдд рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ: рд░рд┐рдХреЙрд░реНрдб рдбрд╛рд▓реЗрдВ, рд╣рдЯрд╛рдПрдВ, рдЕрдкрдбреЗрдЯ рдХрд░реЗрдВред рдбреАрдбреАрдПрд▓, рд▓реЗрдирджреЗрди, рдФрд░ рдмрд╣реБрдд рдХреБрдЫ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреЛрдИ рдЙрдкрдХрд░рдг рдирд╣реАрдВ рд╣реИрдВред рд▓реЗрдХрд┐рди рдирдИ рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдХреЛ рдЬреЛрдбрд╝рдирд╛ рдХрд╛рдлреА рдЖрд╕рд╛рди рд╣реИ, рдЕрдХреНрд╕рд░ рдореМрдЬреВрджрд╛ рдХреЛрдб рдХреЛ рд╕рдВрд╢реЛрдзрд┐рдд рдХрд┐рдП рдмрд┐рдирд╛ рднреАред рдкреНрд░рд╕реНрддрд╛рд╡рд┐рдд рд╡рд┐рдзрд┐ рдХрдИ рдореЗрдВ рд╕реЗ рдПрдХ рд╣реИ, рджреЛрд╖реЛрдВ рдХреЗ рдмрд┐рдирд╛ рдирд╣реАрдВ, рд▓реЗрдХрд┐рди рдпрд╣ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдЬреАрд╡рди рдХрд╛ рд╣рдХрджрд╛рд░ рд╣реИред рдЕрдВрдд рдореЗрдВ, рдореИрдВ рдкреВрд░реНрдг рд╕рдВрд╕реНрдХрд░рдг рдХреЗ рдХреЛрдб рдХреЗ рд▓рд┐рдП рдПрдХ рд▓рд┐рдВрдХ рдЫреЛрдбрд╝рддрд╛ рд╣реВрдВ , рдЬрд┐рд╕рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдпрд╣ рд▓реЗрдЦ рд▓рд┐рдЦрд╛ рдЧрдпрд╛ рдерд╛ред