{"id":204992,"date":"2013-12-13T12:04:02","date_gmt":"2013-12-13T08:04:02","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=204992"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=204992","title":{"rendered":"<span class=\"post_title\">\u041f\u0438\u0448\u0435\u043c \u0441\u0432\u043e\u0439 DSL \u043d\u0430 Clojure \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0411\u0414<\/span>"},"content":{"rendered":"<div class=\"content html_format\">   \t<img decoding=\"async\" src=\"http:\/\/habr.habrastorage.org\/post_images\/fea\/6af\/72b\/fea6af72b09f9ded1aa29426d1c429e8.png\" align=\"left\"\/><br \/>  \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043d\u0430\u043f\u0438\u0448\u0435\u043c Clojure-\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0440\u0435\u043b\u044f\u0446\u0438\u043e\u043d\u043d\u044b\u043c\u0438 \u0411\u0414. \u0417\u0430\u043e\u0434\u043d\u043e \u043f\u043e\u0442\u0440\u0435\u043d\u0438\u0440\u0443\u0435\u043c\u0441\u044f \u0432 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u043c\u0430\u043a\u0440\u043e\u0441\u043e\u0432, \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u044b \u0438 \u043c\u0443\u043b\u044c\u0442\u0438\u043c\u0435\u0442\u043e\u0434\u044b. \u0412\u0435\u0434\u044c \u043d\u0435\u0442\u0443 \u043b\u0443\u0447\u0448\u0435\u0433\u043e \u0441\u043f\u043e\u0441\u043e\u0431\u0430 \u0443\u0437\u043d\u0430\u0442\u044c \u044f\u0437\u044b\u043a, \u043d\u0435\u0436\u0435\u043b\u0438 \u0447\u0442\u043e-\u0442\u043e \u043d\u0430 \u043d\u0435\u043c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c. \u041d\u0443\u2026 \u0438\u043b\u0438 \u043f\u043e\u0447\u0438\u0442\u0430\u0442\u044c, \u043a\u0430\u043a \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u043a\u0442\u043e-\u0442\u043e \u0434\u0440\u0443\u0433\u043e\u0439.<br \/>  <a name=\"habracut\"><\/a>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u0417\u0430\u0447\u0435\u043c?<\/b><\/p>\n<div class=\"spoiler_text\">\u0412 \u0441\u0432\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u043c\u043d\u0435 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u043b\u0430\u0441\u044c \u0442\u0430\u043a\u0430\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u043b\u0438\u0447\u043d\u044b\u0445 \u043d\u0443\u0436\u0434. \u041d\u0430 \u0442\u043e\u0442 \u043c\u043e\u043c\u0435\u043d\u0442 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043b\u043e \u0434\u0432\u0430 \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0435\u043d\u043d\u044b\u0445 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u2014 ClojureQL \u0438 Korma. \u041f\u043e \u0442\u0435\u043c \u0438\u043b\u0438 \u0438\u043d\u044b\u043c \u043f\u0440\u0438\u0447\u0438\u043d\u0430\u043c \u043e\u043d\u0438 \u043c\u043d\u0435 \u043d\u0435 \u043f\u043e\u043d\u0440\u0430\u0432\u0438\u043b\u0438\u0441\u044c (\u0434\u0430 \u0434\u0430, \u0444\u0430\u0442\u0430\u043b\u044c\u043d\u044b\u0439 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u043a), \u0431\u044b\u043b\u043e \u0440\u0435\u0448\u0435\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u0432\u043e\u0439 \u0432\u0435\u043b\u043e\u0441\u0438\u043f\u0435\u0434. \u0412\u0435\u043b\u043e\u0441\u0438\u043f\u0435\u0434 \u0432\u043f\u043e\u043b\u043d\u0435 \u0440\u0430\u0431\u043e\u0447\u0438\u0439, \u044f \u0434\u043e\u0432\u043e\u043b\u0435\u043d. \u0418\u0437 \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u043e\u0442\u043b\u0438\u0447\u0438\u0439 \u2014 \u0432\u044b\u0448\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0435\u043c\u043e\u0441\u0442\u044c, \u0443\u043f\u043e\u0440 \u0434\u0435\u043b\u0430\u043b\u0441\u044f \u043d\u0430 \u043b\u0435\u0433\u043a\u043e\u0441\u0442\u044c \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u043e\u0432\u044b\u0445 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432 \u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0439, \u0431\u044b\u043b\u0430 \u0432\u0430\u0436\u043d\u0430 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u043f\u043e\u0434\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0438 \u0432\u0441\u0442\u0430\u0432\u043e\u043a \u0438\u0437 \u0433\u043e\u043b\u043e\u0433\u043e SQL.<\/p>\n<p>  \u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043e\u0431\u0449\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u044d\u0442\u043e\u0433\u043e \u0432\u0435\u043b\u043e\u0441\u0438\u043f\u0435\u0434\u0430, \u043f\u0440\u0430\u0432\u0434\u0430, \u0432 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0443\u043f\u0440\u043e\u0449\u0435\u043d\u043d\u043e\u0439 \u0444\u043e\u0440\u043c\u0435. \u041d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0444\u0438\u0447 \u043d\u0435\u0442\u0443, \u043a\u043e\u0434 \u043e\u0431\u044b\u0447\u043d\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u043b\u0441\u044f \u0432 \u0438\u043d\u043e\u0439 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438, \u0437\u0430 \u0431\u043e\u0440\u0442\u043e\u043c \u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u043c\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u044b\u0445 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 API. \u041d\u043e, \u0432 \u0446\u0435\u043b\u043e\u043c, \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043d\u044b\u0435 \u0438\u0434\u0435\u0438 \u043e\u043f\u0438\u0441\u0430\u043d\u044b \u0442\u043e\u0447\u043d\u043e. \u041d\u0430\u0434\u0435\u044e\u0441\u044c, \u043a\u043e\u043c\u0443-\u043d\u0438\u0431\u0443\u0434\u044c \u0441\u0442\u0430\u0442\u044c\u044f \u043e\u043a\u0430\u0436\u0435\u0442\u0441\u044f \u043f\u043e\u043b\u0435\u0437\u043d\u043e\u0439.  <\/div>\n<\/div>\n<p>  <\/p>\n<h4>\u0422\u0430\u043a \u0430 \u0447\u0442\u043e \u043c\u044b \u043f\u0438\u0448\u0435\u043c?<\/h4>\n<p>  \u0421\u043e\u0437\u0434\u0430\u0435\u043c DSL (<b>\u043d\u0435<\/b> ORM). \u0412 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 ORM:<br \/>   \u2014 \u043d\u0438\u043a\u0430\u043a\u0438\u0445 \u00ab\u0443\u043c\u043d\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432\u00bb \u2014 \u0442\u043e\u043b\u044c\u043a\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0438 \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0435 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0434\u0430\u043d\u043d\u044b\u0445 (\u0432\u043a\u043b\u044e\u0447\u0430\u044f records);<br \/>   \u2014 \u043d\u0438\u043a\u0430\u043a\u0438\u0445 \u00ab\u043b\u0435\u043d\u0438\u0432\u044b\u0445\u00bb \u0441\u0432\u044f\u0437\u0435\u0439, \u043c\u0430\u0433\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u043f\u043e\u0434\u0433\u0440\u0443\u0437\u043a\u0438 \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u0438 \u043f\u0440\u043e\u0447\u0438\u0445 \u00ab\u0433\u0430\u0434\u043e\u0441\u0442\u0435\u0439\u00bb;<br \/>   \u2014 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u0447\u0435\u0442\u043a\u043e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u0440\u0435\u043c\u044f \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u043e\u0432\u0435\u043d\u0438\u044f \u043f\u043e\u0431\u043e\u0447\u043d\u044b\u0445 \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432 \u2014 \u043e\u043d\u0438 \u0434\u043e\u043b\u0436\u043d\u044b \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u0441\u0442\u0440\u043e\u0433\u043e \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u0445 \u043c\u0435\u0441\u0442\u0430\u0445.<\/p>\n<p>  \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0435\u0449\u0435 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439:<br \/>   \u2014 \u0441\u0445\u043e\u0436\u0435\u0441\u0442\u044c \u0441 SQL;<br \/>   \u2014 \u043f\u0440\u043e\u0437\u0440\u0430\u0447\u043d\u043e\u0441\u0442\u044c, \u0447\u0435\u043c \u043c\u0435\u043d\u044c\u0448\u0435 \u00ab\u043c\u0430\u0433\u0438\u0438\u00bb \u2014 \u0442\u0435\u043c \u043b\u0443\u0447\u0448\u0435;<br \/>   \u2014 \u043d\u0438\u043a\u0430\u043a\u043e\u0439 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432, \u0441\u0445\u0435\u043c \u0438 \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u2014 \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u043d\u0430 \u0441\u043e\u0432\u0435\u0441\u0442\u0438 \u0411\u0414;<br \/>   \u2014 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u043a\u0432\u043e\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u0432 \u0438 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432;<br \/>   \u2014 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u0435 \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0439 \u0431\u0430\u0437\u044b (\u043d\u043e \u0431\u0435\u0437 \u0444\u0430\u043d\u0430\u0442\u0438\u0437\u043c\u0430);<br \/>   \u2014 \u0438\u043d\u043e\u0433\u0434\u0430 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043f\u0438\u0441\u0430\u0442\u044c \u0411\u0414-\u0437\u0430\u0432\u0438\u0441\u044b\u043c\u044b\u0439 \u043a\u043e\u0434 (\u0445\u0440\u0430\u043d\u0438\u043c\u043a\u0438, \u0442\u0440\u0438\u0433\u0433\u0435\u0440\u044b \u0438 \u0442.\u043f.).<\/p>\n<p>  \u0427\u0442\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u0434 \u00ab\u043c\u0430\u043b\u043e \u043c\u0430\u0433\u0438\u0438\u00bb? \u0413\u0440\u0443\u0431\u043e \u0433\u043e\u0432\u043e\u0440\u044f, \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0435 <b>\u043d\u0435 \u0441\u043b\u0435\u0434\u0443\u0435\u0442<\/b> \u0437\u0430\u043d\u0438\u043c\u0430\u0442\u044c\u0441\u044f \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432, \u0434\u0430 \u0438 \u043b\u044e\u0431\u043e\u0439 \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0439 \u0434\u0435\u044f\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c\u044e. \u0422\u0435\u043e\u0440\u0435\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u044d\u0442\u043e, \u0431\u044b\u0442\u044c \u043c\u043e\u0436\u0435\u0442, \u0438 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e (\u043d\u0443 \u0447\u0443\u0442\u044c-\u0447\u0443\u0442\u044c) \u0440\u0430\u0437\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0411\u0414, \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u0434\u0435\u043b\u0430 \u043e\u0431\u044b\u0447\u043d\u043e \u0443\u0445\u0443\u0434\u0448\u0430\u044e\u0442\u0441\u044f. \u0412\u0435\u0434\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0411\u0414 \u0438 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442 (\u0438\u0437\u0440\u0435\u0434\u043a\u0430), \u043e\u0431\u043b\u0430\u0434\u0430\u044e\u0442 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u044b\u043c\u0438 \u0437\u043d\u0430\u043d\u0438\u044f\u043c\u0438, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043d\u0443\u0436\u043d\u0443\u044e \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044e. \u041f\u043b\u043e\u0445\u043e\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442: \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043f\u0438\u0448\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441, \u0437\u0430\u0442\u0435\u043c \u043e\u0447\u0435\u043d\u044c \u0442\u0449\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0438\u0437\u0443\u0447\u0430\u0435\u0442 \u043b\u043e\u0433\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0434\u0430\u0431\u044b \u0432\u044b\u044f\u0441\u043d\u0438\u0442\u044c, \u043a\u0430\u043a\u043e\u0439 \u0436\u0435 SQL \u043d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435 \u043f\u043e\u0441\u044b\u043b\u0430\u0435\u0442\u0441\u044f \u0432 \u0411\u0414. \u041f\u0435\u0440\u0435\u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u043b\u043e\u0433\u0438 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u043e, \u0432\u0435\u0434\u044c \u043f\u043e\u0441\u043b\u0435 \u043d\u043e\u0432\u043e\u0433\u043e \u0440\u0435\u043b\u0438\u0437\u0430 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u043c\u043e\u0436\u0435\u0442 \u043d\u0435\u043e\u0436\u0438\u0434\u0430\u043d\u043d\u043e \u0441\u0442\u0430\u0442\u044c \u00ab\u0443\u043c\u043d\u0435\u0435\u00bb!<\/p>\n<p>  \u0418\u0442\u0430\u043a, \u043d\u0430\u0448 DSL \u043f\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044f\u043c \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e <s>\u0433\u043b\u0443\u043f\u044b\u043c<\/s> \u043f\u0440\u043e\u0437\u0440\u0430\u0447\u043d\u044b\u043c \u2014 \u0441\u0435\u043c\u0430\u043d\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043c\u044b \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u0441 \u0433\u043e\u043b\u044b\u043c SQL, \u043d\u043e \u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441\u043e\u043c Clojure. \u0427\u0442\u043e-\u0442\u043e \u0432\u0440\u043e\u0434\u0435 \u0437\u0430\u043f\u0438\u0441\u0438 SQL \u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u043e\u043c S-\u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439 \u0441 \u0443\u0447\u0435\u0442\u043e\u043c \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0438 \u043d\u0430\u0448\u0435\u0433\u043e \u044f\u0437\u044b\u043a\u0430. \u0412\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0432\u0441\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a:<\/p>\n<pre><code>(select   (fields [:name :role_name])   (from :Users)   (join-inner :Roles (== :Users.role_id :Roles.id))   (where (= :Roles.name &quot;admin&quot;))   (order :Users.name)   (limit 100)) <\/code><\/pre>\n<p>  \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0440\u043e\u0434\u0438\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441:<\/p>\n<pre><code class=\"sql\">SELECT `name`, `role_name` FROM `Users` INNER JOIN `Roles` ON `Users`.`role_id` = `Roles`.`id` WHERE `Roles`.`name` = ? ORDER BY `Users`.`name` LIMIT ? <\/code><\/pre>\n<p>  \u0412\u0441\u0435 \u0438\u043c\u0435\u043d\u0430 \u043c\u044b \u044d\u043a\u0440\u0430\u043d\u0438\u0440\u0443\u0435\u043c \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043e\u0431\u0440\u0430\u0442\u043d\u044b\u0445 \u043a\u0430\u0432\u044b\u0447\u0435\u043a. \u041f\u043e-\u0445\u043e\u0440\u043e\u0448\u0435\u043c\u0443 \u043d\u0430\u0434\u043e \u0431\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u0432\u043e\u0439\u043d\u044b\u0435 \u043a\u0430\u0432\u044b\u0447\u043a\u0438 (\u0430 \u0435\u0449\u0435 \u043b\u0443\u0447\u0448\u0435 \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c \u0442\u0438\u043f \u0411\u0414), \u043d\u043e \u0432 \u0446\u0435\u043b\u044f\u0445 \u0447\u0438\u0442\u0430\u0431\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0432 \u043f\u0440\u0438\u043c\u0435\u0440\u0430\u0445 \u0431\u0443\u0434\u0435\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f MySQL-\u0441\u0442\u0438\u043b\u0435\u043c. \u041a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u044b \u0437\u0430\u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u043d\u0430 <code>?<\/code> \u2014 jdbc-\u0434\u0440\u0430\u0439\u0432\u0435\u0440 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0439 \u0411\u0414 \u0431\u0443\u0434\u0435\u0442 \u0441\u0430\u043c \u0437\u0430\u043d\u0438\u043c\u0430\u0442\u044c\u0441\u044f \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0435\u0439 \u0438 \u044d\u043a\u0440\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432.<\/p>\n<p>  \u041d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435\u043c SELECT \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0443 \u043d\u0430\u0441 \u0431\u0443\u0434\u0443\u0442 \u0437\u0430\u043d\u0438\u043c\u0430\u0442\u044c\u0441\u044f \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438: <code>fetch-all<\/code>, <code>fetch-one<\/code>, <code>with-fetch<\/code>. \u0412\u0441\u0435 \u043e\u043d\u0438 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u044e\u0442 \u043d\u0430 \u0432\u0445\u043e\u0434 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043a \u0411\u0414 \u0438 \u0437\u0430\u043f\u0440\u043e\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c:<\/p>\n<pre><code>(def db   {:classname &quot;com.mysql.jdbc.Driver&quot;    :subprotocol &quot;mysql&quot;    :user &quot;test&quot;    :password &quot;test&quot;    :subname &quot;\/\/localhost\/test&quot;})  ; \u0432\u044b\u0442\u0430\u0441\u043a\u0438\u0432\u0430\u0435\u043c \u0440\u043e\u0432\u043d\u043e 1 \u0437\u0430\u043f\u0438\u0441\u044c \u0438\u0437 \u0442\u0430\u0431\u043b\u0438\u0446\u044b Users (fetch-one db   (select     (from :Users)     (where (== :id 123))))  ; \u0432\u0441\u0435 \u0437\u0430\u043f\u0438\u0441\u0438 \u0438\u0437 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0432 \u0432\u0438\u0434\u0435 \u0432\u0435\u043a\u0442\u043e\u0440\u0430 (fetch-all db   (select (from :Users)))  (with-fetch db [rows (select (from :Users))]   ; \u0442\u0443\u0442 \u043c\u044b \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u0441 *\u043b\u0435\u043d\u0438\u0432\u043e\u0439* \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c\u044e `rows`   (doseq [r rows]     (print &quot;&gt;&quot; r))) <\/code><\/pre>\n<h4>\u0413\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c SQL<\/h4>\n<p>  \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c\u0441\u044f, \u043a\u0430\u043a \u0431\u0443\u0434\u0435\u043c \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0432\u043d\u0443\u0442\u0440\u0438 \u043d\u0430\u0448\u0435\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438.<\/p>\n<pre><code>(def raw-select   ['SELECT :name :role_name      ['FROM :Users ['JOIN :Roles ['ON :Users.role_id :Roles_id]]]      ['WHERE ['LIKE :Users.name &quot;And%&quot;]      ['LIMIT 100]]]) <\/code><\/pre>\n<p>  \u0412 \u044d\u0442\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043c\u044b \u0438\u043c\u0435\u0435\u043c \u0434\u0435\u0440\u0435\u0432\u043e \u0438\u0437 \u0432\u0435\u043a\u0442\u043e\u0440\u043e\u0432, \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432 \u0438 \u043a\u043b\u044e\u0447\u0435\u0439. \u041f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432 \u0431\u0443\u0434\u0435\u043c \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0430\u0442\u044c \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u0441\u043b\u043e\u0432\u0430 SQL, \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043a\u043b\u044e\u0447\u0435\u0439 \u2014 \u0438\u043c\u0435\u043d\u0430 \u0442\u0430\u0431\u043b\u0438\u0446 \u0438 \u043f\u043e\u043b\u0435\u0439, \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f (\u0441\u0442\u0440\u043e\u043a\u0438, \u0447\u0438\u0441\u043b\u0430, \u0434\u0430\u0442\u044b \u0438 \u043f\u0440\u043e\u0447\u0435\u0435) \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u00ab\u043a\u0430\u043a \u0435\u0441\u0442\u044c\u00bb. \u0421\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u043c \u0432 \u0432\u0438\u0434\u0435 \u043f\u0430\u0440\u044b: SQL \u043a\u043e\u0434 (\u0441\u0442\u0440\u043e\u043a\u0430) \u0438 \u0432\u0435\u043a\u0442\u043e\u0440 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432. \u0417\u0430\u0432\u043e\u0434\u0438\u043c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0442\u0438\u043f:<\/p>\n<pre><code>(defrecord Sql [sql args])  ;; \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043f\u043e\u0441\u043b\u0435 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u0438 \u0431\u0443\u0434\u0443\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a: (Sql. &quot;SELECT * FROM `Users` WHERE `id` = ?&quot; [123]) <\/code><\/pre>\n<p>  \u042d\u0442\u043e \u043d\u0438\u0436\u043d\u0435\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0432 \u043d\u0430\u0448\u0435\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0435. \u0420\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0438\u0437 \u043e\u0434\u043d\u043e\u0433\u043e \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0432 \u0434\u0440\u0443\u0433\u043e\u0435. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0443\u0436\u0435\u043d \u043d\u0435\u043a\u0438\u0439 <i>\u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0439<\/i> \u0441\u043f\u043e\u0441\u043e\u0431 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u044b\u0432\u0430\u0442\u044c <i>\u043b\u044e\u0431\u0443\u044e<\/i> \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c \u0432 \u0437\u0430\u043f\u0438\u0441\u044c <code>Sql<\/code>. \u041e\u0442\u043b\u0438\u0447\u043d\u043e \u043f\u043e\u0434\u043e\u0439\u0434\u0443\u0442 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u044b:<\/p>\n<pre><code>(defprotocol SqlLike   (as-sql [this]))  ; \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f (defn quote-name   [s]   (let [x (name s)]     (if (= &quot;*&quot; x)       x       (str \\` x \\`))))  (extend-protocol SqlLike    ; \u0434\u043b\u044f \u043b\u044e\u0431\u043e\u0433\u043e `x` (= (as-sql (as-sql x)) (as-sql x))   Sql   (as-sql [this] this)    ; \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0441\u0447\u0438\u0442\u0430\u0435\u043c \u0432\u0441\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438 \u0434\u043b\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432   Object   (as-sql [this] (Sql. &quot;?&quot; [this]))    ; \u044d\u043a\u0440\u0430\u043d\u0438\u0440\u0443\u0435\u043c \u0438\u043c\u0435\u043d\u0430 \u0442\u0430\u0431\u043b\u0438\u0446 \u0438 \u0441\u0442\u043e\u043b\u0431\u0446\u043e\u0432   clojure.lang.Keyword   (as-sql [this] (Sql. (quote-name this) nil))    ; \u0441\u0438\u043c\u0432\u043e\u043b\u0430\u043c\u0438 \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0430\u0435\u043c \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u0441\u043b\u043e\u0432\u0430 SQL   clojure.lang.Symbol   (as-sql [this] (Sql. (name this) nil))    ; \u0434\u043b\u044f nil \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0435 \u043a\u043b\u044e\u0447\u0435\u0432\u043e\u0435 \u0441\u043b\u043e\u0432\u043e   nil   (as-sql [this] (Sql. &quot;NULL&quot; nil))) <\/code><\/pre>\n<p>  \u0412\u043c\u0435\u0441\u0442\u043e \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u043e\u0432 \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0431\u044b \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430\u0431\u043e\u0440\u043e\u043c <code>if<\/code>-\u043e\u0432, \u0438\u043b\u0438 \u0432\u043e\u043e\u0431\u0449\u0435 pattern matching. \u041d\u043e \u0443 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u043e\u0432 \u0435\u0441\u0442\u044c \u043d\u0435\u043e\u0441\u043f\u043e\u0440\u0438\u043c\u044b\u0439 \u043f\u043b\u044e\u0441: \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u043c\u043e\u0433\u0443\u0442 <i>\u0441\u0430\u043c\u0438<\/i> \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0434\u043b\u044f <i>\u043b\u044e\u0431\u044b\u0445<\/i> \u0442\u0438\u043f\u043e\u0432. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043a\u0442\u043e-\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u0445\u043e\u0442\u0435\u0442\u044c \u0430\u0432\u0442\u043e\u043c\u0430\u0433\u0438\u0447\u0435\u0441\u043a\u0438 \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0438\u0437 \u0441\u0441\u044b\u043b\u043e\u043a:<\/p>\n<pre><code>(extend-protocol SqlLike   clojure.lang.ARef   (as-sql [this] (as-sql @this)))  ; \u0442\u0435\u043f\u0435\u0440\u044c \u0432\u043c\u0435\u0441\u0442\u043e \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442 \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c ; \u0441\u0441\u044b\u043b\u043a\u0438 (ref, agent, var, atom) (def a (atom 123)) (assert   (=     (as-sql a)     (as-sql @a)     (Sql. &quot;?&quot; [123]))) <\/code><\/pre>\n<p>  \u0420\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u043d\u0430\u0448 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b \u0434\u043b\u044f \u0432\u0435\u043a\u0442\u043e\u0440\u043e\u0432 \u0438 \u0441\u043f\u0438\u0441\u043a\u043e\u0432:<\/p>\n<pre><code>; \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f, \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u0435\u0442 2 sql-\u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0432 \u043e\u0434\u0438\u043d (defn- join-sqls   ([] (Sql. &quot;&quot; nil))   ([^Sql s1 ^Sql s2]     (Sql. (str (.sql s1) &quot; &quot; (.sql s2)) (concat (.args s1) (.args s2)))))  (extend-protocol SqlLike   clojure.lang.Sequential   (as-sql [this]     (reduce join-sqls (map as-sql this)))) <\/code><\/pre>\n<p>  \u0421 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044c\u044e \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0430 \u0442\u0443\u0442 \u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u0445\u043e\u0440\u043e\u0448\u043e, \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043a\u043e\u0434 \u0438 \u043f\u043e\u0431\u044b\u0441\u0442\u0440\u0435\u0435. \u0417\u0430\u0442\u043e \u0442\u0435\u043f\u0435\u0440\u044c:<\/p>\n<pre><code>(as-sql ['SELECT '* ['FROM :Users] ['WHERE :id '= 1 'AND :name 'IS 'NOT nil]]) ; =&gt; #user.Sql{:sql &quot;SELECT * FROM `Users` WHERE `id` = ? AND `name` IS NOT NULL&quot; :args (1)} <\/code><\/pre>\n<p>  \u041e\u0442\u043b\u0438\u0447\u043d\u043e! \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0435\u0449\u0435 \u043f\u0430\u0440\u043e\u0447\u043a\u0443 \u0444\u0443\u043d\u043a\u0446\u0438\u0439\u2026<\/p>\n<pre><code>(require '[clojure.java.jdbc :as jdbc])  (defn- to-sql-params   [relation]   (let [{s :sql p :args} (as-sql relation)]     (vec (cons s p))))  (defn fetch-all   [db relation]     (jdbc\/query      db      (to-sql-params relation)      :result-set-fn vec))  ; \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c `fetch-one` <\/code><\/pre>\n<p>  \u0420\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u0441 JDBC \u0443\u0442\u043e\u043c\u0438\u0442\u0438\u043b\u044c\u043d\u043e, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0445\u0438\u0442\u0440\u0438\u043c \u2014 \u0432\u0441\u044e \u0433\u0440\u044f\u0437\u043d\u0443\u044e \u0440\u0430\u0431\u043e\u0442\u0443 \u0437\u0430 \u043d\u0430\u0441 \u0434\u0435\u043b\u0430\u0435\u0442 <code>clojure.java.jdbc<\/code>. \u041d\u0430\u043a\u043e\u043d\u0435\u0446 \u0443 \u043d\u0430\u0441 \u0443\u0436\u0435 \u0435\u0441\u0442\u044c \u0432\u043f\u043e\u043b\u043d\u0435 \u043f\u0440\u0438\u0435\u043c\u043b\u0435\u043c\u044b\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b, \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u043e\u0439 \u0434\u0430\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f:<\/p>\n<pre><code>; \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043a \u0411\u0414 (def db   {:classname &quot;com.mysql.jdbc.Driver&quot;    :subprotocol &quot;mysql&quot;    :user &quot;test&quot;    :password &quot;test&quot;    :subname &quot;\/\/localhost\/test&quot;})  ; \u0434\u0435\u043b\u0430\u0435\u043c \u0437\u0430\u043f\u0440\u043e\u0441 \u043a \u0411\u0414 (fetch-all   db   (as-sql '[SELECT * FROM :users ORDER BY :name])) <\/code><\/pre>\n<p>  \u0410\u0445 \u0434\u0430, \u043c\u044b \u0436\u0435 \u0437\u0430\u0431\u044b\u043b\u0438 \u043f\u0440\u043e <code>with-fetch<\/code>. \u0420\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c:<\/p>\n<pre><code>(defmacro with-fetch   [db [v rel :as vr] & body]   `(let [params# (to-sql-params ~rel)          rsf# (fn [~v] ~@body)]     (jdbc\/query       ~db       params#       :result-set-fn rsf#  ; \u0432\u0435\u0441\u044c RS \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u044e rsf#       :row-fn identity)))  ; \u0441\u0442\u0440\u043e\u043a\u0438 \u043d\u0438\u043a\u0430\u043a \u043d\u0435 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c <\/code><\/pre>\n<h4>\u041d\u0430\u0440\u0430\u0449\u0438\u0432\u0430\u0435\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0438\u0442\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u043e<\/h4>\n<p>  \u0423 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0433\u043e \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0435\u0441\u0442\u044c \u0441\u0435\u0440\u044a\u0435\u0437\u043d\u044b\u0435 \u043c\u0438\u043d\u0443\u0441\u044b \u2014 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0441\u043b\u043e\u0436\u043d\u043e \u043d\u0430\u0440\u0430\u0449\u0438\u0432\u0430\u0442\u044c <i>\u0438\u0442\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u043e<\/i>. \u0414\u043e\u043f\u0443\u0441\u0442\u0438\u043c, \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0434\u0435\u0440\u0435\u0432\u043e \u0434\u043b\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u0430 <code>SELECT FROM `Users` LIMIT 10<\/code>, \u0430 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u0432 \u043d\u0435\u0433\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u0435\u043a\u0446\u0438\u044e <code>WHERE<\/code>. \u0412 \u043e\u0431\u0449\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u0434\u043b\u044f \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u0437\u0430\u043d\u0438\u043c\u0430\u0442\u044c\u0441\u044f \u0440\u0430\u0437\u0431\u043e\u0440\u043e\u043c \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441\u0430 SQL (\u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c AST-\u0434\u0435\u0440\u0435\u0432\u043e), \u0447\u0435\u0433\u043e, \u043f\u043e \u043f\u0440\u0430\u0432\u0434\u0435 \u0433\u043e\u0432\u043e\u0440\u044f, \u043e\u0447\u0435\u043d\u044c \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c.<\/p>\n<p>  \u0417\u0430\u0447\u0435\u043c \u043d\u0430\u043c \u00ab\u0438\u0442\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u043e \u043d\u0430\u0440\u0430\u0449\u0438\u0432\u0430\u0442\u044c\u00bb \u0437\u0430\u043f\u0440\u043e\u0441\u044b? \u041d\u0443, \u0432\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u044d\u0442\u043e \u043f\u043e\u043b\u0435\u0437\u043d\u0430\u044f \u043e\u043f\u0446\u0438\u044f \u0441\u0430\u043c\u0430 \u043f\u043e \u0441\u0435\u0431\u0435. \u041f\u0440\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u0447\u0430\u0441\u0442\u0435\u043d\u044c\u043a\u043e \u043c\u044b \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u043d\u0435 \u0437\u043d\u0430\u0435\u043c, \u043a\u0430\u043a\u0438\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0431\u0443\u0434\u0435\u043c \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c. \u041f\u0440\u0438\u043c\u0435\u0440: \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u0442\u0440\u043e\u0438\u043c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u044b\u0435 \u0443\u0441\u043b\u043e\u0432\u0438\u044f \u0434\u043b\u044f \u0441\u0435\u043a\u0446\u0438\u0439 <code>WHERE<\/code> \u0438 ORDER BY \u0432 \u0430\u0434\u043c\u0438\u043d\u043a\u0435.<\/p>\n<p>  \u041d\u043e \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u0432\u0430\u0436\u043d\u0435\u0435 \u0442\u043e, \u0447\u0442\u043e \u044d\u0442\u043e \u0445\u043e\u0440\u043e\u0448\u0430\u044f \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0430 \u043f\u0440\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c \u043d\u0430 Clojure. \u041c\u044b \u0440\u0430\u0437\u0431\u0438\u0432\u0430\u0435\u043c \u0440\u0430\u0431\u043e\u0442\u0443 \u043d\u0430 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u043a\u0443\u0441\u043e\u0447\u043a\u043e\u0432, \u0438\u0442\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u043e \u0434\u0435\u043b\u0430\u044e\u0449\u0438\u0445 \u0441\u0432\u043e\u044e \u0440\u0430\u0431\u043e\u0442\u0443. \u041a\u0430\u0436\u0434\u044b\u0439 \u0442\u0430\u043a\u043e\u0439 \u043a\u0438\u0440\u043f\u0438\u0447\u0438\u043a (\u0447\u0438\u0441\u0442\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f) \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0430 \u0432\u0445\u043e\u0434 \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u00ab\u043f\u043e\u0434\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0439\u00bb \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442. \u041a\u0438\u0440\u043f\u0438\u0447\u0438\u043a\u0438 \u043b\u0435\u0433\u043a\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c. \u0410 \u043f\u043e\u0434 \u043a\u043e\u043d\u0435\u0446 \u0442\u0430\u043a\u0438\u0435 \u043a\u0443\u0441\u043e\u0447\u043a\u0438 \u043b\u0435\u0433\u043a\u043e \u0441\u043e\u0431\u0438\u0440\u0430\u044e\u0442\u0441\u044f \u0432\u043c\u0435\u0441\u0442\u0435.<\/p>\n<p>  \u0417\u0430\u043f\u0440\u043e\u0441\u044b \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0432 \u0432\u0438\u0434\u0435 \u0445\u0435\u0448-\u0442\u0430\u0431\u043b\u0438\u0446\u044b. \u041f\u0440\u0438\u043c\u0435\u0440:<\/p>\n<pre><code>(def some-query-example   {    ; \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 &quot;\u0430\u043b\u0438\u0430\u0441 \u0442\u0430\u0431\u043b\u0438\u0446\u044b - \u0438\u043c\u044f \u0442\u0430\u043b\u0438\u0446\u044b&quot;    :tables {:r :Roles, :u :Users},     ; \u0441\u043f\u0438\u0441\u043e\u043a [\u0430\u043b\u0438\u0430\u0441 \u0442\u0430\u0431\u043b\u0438\u0446\u044b, \u0442\u0438\u043f \u0434\u0436\u043e\u0438\u043d\u0430, \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0441\u0435\u043a\u0446\u0438\u0438 ON]    ; \u043f\u0435\u0440\u0432\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 -- [\u0438\u0441\u0445\u043e\u0434\u043d\u0430\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u0430, nil, nil]    ; \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0441\u043f\u0438\u0441\u043e\u043a, \u0442.\u043a. \u043d\u0430\u043c \u0432\u0430\u0436\u0435\u043d \u043f\u043e\u0440\u044f\u0434\u043e\u043a join'\u043e\u0432    :joins      [[:u nil nil]       [:r :inner ['= :Users.role_id :Roles.id]]]     ; ast-\u0434\u0435\u0440\u0435\u0432\u043e \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f    :where [:= :u.name &quot;Ivan&quot;],     ; \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 &quot;\u0430\u043b\u0438\u0430\u0441 \u0441\u0442\u043e\u043b\u0431\u0446\u0430 - \u0438\u043c\u044f \u0441\u0442\u043e\u043b\u0431\u0446\u0430&quot;    :fields {:name :name, :role_name :role_name},     ; \u043f\u0440\u043e\u0441\u0442\u043e \u0447\u0438\u0441\u043b\u0430    :offset 1000,    :limit 100,     ; order, group, having, etc...    }) <\/code><\/pre>\n<p>  \u0414\u043b\u044f \u0441\u0435\u043a\u0446\u0438\u0439 <code>WHERE<\/code>, <code>ORDER BY<\/code> \u0438 \u0442.\u043f. \u043c\u044b \u0445\u0440\u0430\u043d\u0438\u043c AST-\u0434\u0435\u0440\u0435\u0432\u043e \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u2014 \u0442\u0430\u043a \u043f\u0440\u043e\u0449\u0435. \u0414\u043b\u044f \u0441\u043f\u0438\u0441\u043a\u0430 \u0442\u0430\u0431\u043b\u0438\u0446 \u0438 \u043f\u043e\u043b\u0435\u0439 \u043c\u044b \u0445\u0440\u0430\u043d\u0438\u043c \u0441\u043b\u043e\u0432\u0430\u0440\u0438, \u043a\u043b\u044e\u0447\u0438 \u2014 \u0438\u043c\u0435\u043d\u0430 \u0430\u043b\u0438\u0430\u0441\u043e\u0432, \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u2014 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0438\u043b\u0438 \u0438\u043c\u0435\u043d\u0430 \u0442\u0430\u0431\u043b\u0438\u0446. \u0412 \u0440\u0430\u043c\u043a\u0430\u0445 \u0442\u0430\u043a\u043e\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438:<\/p>\n<pre><code>; \u0434\u043b\u044f `limit` & `offset` \u0442\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d\u043e (defn limit   [relation v]   (assoc relation :limit v))  ; *\u043f\u043e\u043a\u0430* \u0441\u043e\u0439\u0434\u0443\u0442 \u0438 \u0442\u0430\u043a\u0438\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 (defn fields   [query fd]   (assoc query :fields fd))  (defn where   [query wh]   (assoc query :where wh))  ; helper-\u0444\u0443\u043d\u043a\u0446\u0438\u044f (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)))  ;; \u0434\u043b\u044f \u0434\u0440\u0443\u0433\u0438\u0445 join-\u043e\u0432 (left, right, full) \u043d\u0443\u0436\u043d\u044b \u043c\u0430\u043a\u0440\u043e\u0441\u044b - \u043f\u043e\u043a\u0430 \u043e\u043f\u0443\u0441\u0442\u0438\u043c <\/code><\/pre>\n<p>  \u0418\u0442\u0430\u043a, \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u043c\u043d\u043e\u0433\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u0439 (<code>where<\/code>, <code>fields<\/code>, <code>from<\/code>, <code>join<\/code>, <code>limit<\/code> \u0438 \u0434\u0440\u0443\u0433\u0438\u0435), \u0443\u043c\u0435\u044e\u0449\u0438\u0445 \u00ab\u043f\u043e\u0434\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c\u00bb \u0437\u0430\u043f\u0440\u043e\u0441\u044b. \u0422\u043e\u0447\u043a\u0430 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u2014 \u043f\u0443\u0441\u0442\u043e\u0439 \u0437\u0430\u043f\u0440\u043e\u0441.<\/p>\n<pre><code>(def empty-select {}) <\/code><\/pre>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c:<\/p>\n<pre><code>(-&gt; empty-select   (fields [:name :role_name])   (from :Users)   (limit 100)) <\/code><\/pre>\n<p>  \u042d\u0442\u043e\u0442 \u043a\u043e\u0434 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u043c\u0430\u043a\u0440\u043e\u0441 <a href=\"http:\/\/clojuredocs.org\/clojure_core\/clojure.core\/-%3E\">-&gt;<\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0430\u0437\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0432\u043e \u0447\u0442\u043e-\u0442\u043e \u0432\u0440\u043e\u0434\u0435:<\/p>\n<pre><code>(limit   (from     (fields       empty-select       [:name :role_name])     :Users)   100) <\/code><\/pre>\n<p>  \u0414\u043b\u044f \u043a\u0440\u0430\u0441\u043e\u0442\u044b \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u0441\u0432\u043e\u0439 \u043c\u0430\u043a\u0440\u043e\u0441 <code>select<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u0435\u0434\u0435\u0442 \u0441\u0435\u0431\u044f \u043f\u043e\u0434\u043e\u0431\u043d\u043e <code>-&gt;<\/code>:<\/p>\n<pre><code>(defmacro select   [& body]    `(-&gt; empty-select ~@body)) <\/code><\/pre>\n<p>  \u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u043d\u0430\u0443\u0447\u0438\u0442\u044c \u043d\u0430\u0448\u0443 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0434\u043d\u043e \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0432 \u0434\u0440\u0443\u0433\u043e\u0435.<\/p>\n<pre><code>; \u043f\u0443\u0441\u0442\u043e\u0439 SQL, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 nil \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u0442\u0441\u044f \u0432 &quot;NULL&quot; (def NONE (Sql. &quot;&quot; nil))  ; \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u0444\u0443\u043a\u043d\u0446\u0438\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442\u0441\u044f \u0442\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d\u043e (defn render-limit [s]   (if-let [l (:limit s)]     ['LIMIT l]     NONE))  (defn render-fields [s] '*)  ; \u043f\u043e\u043a\u0430 \u0431\u0443\u0434\u0435\u043c \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u0432\u0441\u0435 \u0441\u0442\u043e\u043b\u0431\u0446\u044b  ; \u044d\u0442\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0447\u0443\u0442\u044c \u043f\u043e\u0437\u0436\u0435 (defn render-where [s] NONE) (defn render-order [s] NONE) (defn render-expression [s] NONE)  ; \u0430 \u044d\u0442\u0438 \u0432\u044b\u0445\u043e\u0434\u044f\u0442 \u0437\u0430 \u0440\u0430\u043c\u043a\u0438 \u0441\u0442\u0430\u0442\u044c\u0438 (defn render-group [s] NONE) (defn render-having [s] NONE) (defn render-offset [s] NONE)  ; \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f (defn render-table   [[alias table]]   (if (= alias table)     ; \u0435\u0441\u043b\u0438 \u0430\u043b\u0438\u0430\u0441 \u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u0430 \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u044e\u0442, \u0442\u043e \u043d\u0435 \u0432\u044b\u0432\u043e\u0434\u0438\u043c 'AS'     table     [table 'AS alias]))  (defn render-join-type   [jt]   (get     {nil (symbol &quot;,&quot;)      :cross '[CROSS JOIN],      :left '[LEFT OUTER JOIN],      :right '[RIGHT OUTER JOIN],      :inner '[INNER JOIN],      :full '[FULL JOIN],      } jt jt))  ; \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0441\u043b\u043e\u0436\u043d\u044b\u0435 (defn render-from   [{:keys [tables joins]}]   ; \u0441\u0435\u043a\u0446\u0438\u0438 FROM \u043c\u043e\u0436\u0435\u0442 \u0438 \u043d\u0435 \u0431\u044b\u0442\u044c!   (if (not (empty? joins))     ['FROM      ; \u043f\u0435\u0440\u0432\u044b\u0439 \u0434\u0436\u043e\u0438\u043d      (let [[a jn] (first joins)            t (tables a)]        ; \u043f\u0435\u0440\u0432\u044b\u0439 \u0434\u0436\u043e\u0438\u043d \u0434\u043e\u043b\u0436\u0435\u043d \u0434\u0435\u043b\u0430\u0442\u044c\u0441\u044f \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 `(from ..)`        (assert (nil? jn))        (render-table [a t]))      ; \u043f\u0435\u0440\u0435\u0431\u0438\u0440\u0430\u0435\u043c \u043e\u0441\u0442\u0430\u0432\u0448\u0438\u0435\u0441\u044f \u0434\u0436\u043e\u0438\u043d\u044b      (for [[a jn c] (rest joins)            :let [t (tables a)]]        [(render-join-type jn) ; \u0441\u0432\u044f\u0437\u043a\u0430 JOIN XX \u0438\u043b\u0438 \u0437\u0430\u043f\u044f\u0442\u0430\u044f         (render-table [a t])  ; \u0438\u043c\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0438 \u0430\u043b\u0438\u0430\u0441         (if c ['ON (render-expression c)] NONE) ; \u0441\u0435\u043a\u0446\u0438\u044f '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])]) <\/code><\/pre>\n<p>  \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u043c\u043e\u0433\u0443\u0442 \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0435 \u0437\u043d\u0430\u0442\u044c \u043f\u0440\u043e \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b <code>SqlLike<\/code> \u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u044e <code>as-sql<\/code>. \u0425\u043e\u0440\u043e\u0448\u0430\u044f \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0430. \u0414\u043b\u044f \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f, \u0432 Java \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b \u0447\u0430\u0441\u0442\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0442 API \u043c\u043e\u0434\u0443\u043b\u044f\/\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438. \u0412 Clojure \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u044b \u043e\u0431\u044b\u0447\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u044e\u0442\u0441\u044f \u0434\u043b\u044f \u0441\u0430\u043c\u044b\u0445 \u043d\u0438\u0437\u043a\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u044b\u0445 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439, \u043d\u0435\u043a\u043e\u0435\u0433\u043e \u0431\u0430\u0437\u0438\u0441\u0430, \u043d\u0430\u0434 \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0443\u0436\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043d\u0430\u0431\u043e\u0440 helper-\u0444\u0443\u043d\u043a\u0446\u0438\u0439. \u0418 \u0432\u043e\u0442 \u0443\u0436\u0435 \u044d\u0442\u0438 helper-\u044b \u043f\u0440\u0435\u0434\u043ec\u0442\u0430\u0432\u043b\u044f\u044e\u0442 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0439 API \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438. \u041f\u0440\u043e\u0431\u0443\u0435\u043c \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0437\u0430\u043f\u0440\u043e\u0441:<\/p>\n<pre><code>(fetch-all db   (render-select     (select       (from :Users)       (limit 10))) <\/code><\/pre>\n<p>  \u0413\u043e\u0442\u043e\u0432\u043e! \u041f\u0440\u0430\u0432\u0434\u0430 \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c <code>render-select<\/code> \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u0443\u0442\u043e\u043c\u0438\u0442\u0435\u043b\u044c\u043d\u043e. \u0418\u0441\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c:<\/p>\n<pre><code>(declare render-select)  ; \u0432\u0441\u0435 \u043f\u043e\u043b\u044f \u043e\u0431\u044a\u044f\u0432\u043b\u044f\u0442\u044c \u043d\u0435 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e ; record \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0443 \u043a\u043b\u044e\u0447\u0435\u0439, \u043d\u0435 \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u044b\u0445 \u043f\u0440\u0438 \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u0438\u0438 \u0442\u0438\u043f\u0430 (defrecord Select [fields where order joins tables offet limit]   SqlLike   (as-sql [this] (as-sql (render-select this))))  (def empty-select (map-&gt;Select {})) <\/code><\/pre>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 <code>(as-sql (select ...))<\/code> \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0438 <code>render-select<\/code>:<\/p>\n<pre><code>(fetch-all db   (select     (from :Users)     (limit 10)))  ; \u0435\u0441\u043b\u0438 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c SQL \u0431\u0435\u0437 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u0430 (as-sql   (select    (from :Table)    (limit 10)))  ; \u0438\u043b\u0438 \u0434\u0430\u0436\u0435 \u0442\u0430\u043a (select  (from :Table)  (limit 10)  (as-sql)) <\/code><\/pre>\n<h4>\u041f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439<\/h4>\n<p>  \u041f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c \u043a \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>where<\/code>. \u041c\u044b \u0445\u043e\u0442\u0438\u043c \u0438\u043c\u0435\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0435\u0435 \u0442\u0430\u043a:<\/p>\n<pre><code>(select  (from :Table)  (where (and (&gt; :x 1) (== :y &quot;z&quot;)))) <\/code><\/pre>\n<p>  \u041e\u0447\u0435\u0432\u0438\u0434\u043d\u043e, \u0447\u0442\u043e \u043d\u0435\u043b\u044c\u0437\u044f \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0442\u044c <code>(&gt; :x 1)<\/code> \u0432 \u043c\u043e\u043c\u0435\u043d\u0442 \u0432\u044b\u0437\u043e\u0432\u0430 <code>where<\/code> \u2014 \u043d\u0443\u0436\u0435\u043d \u043c\u0430\u043a\u0440\u043e\u0441. \u041f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u043e\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0435\u043c \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432 \u0432\u0438\u0434\u0435 AST-\u0434\u0435\u0440\u0435\u0432\u0430: \u0443\u0437\u043b\u044b \u2014 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u044b, \u043b\u0438\u0441\u0442\u044c\u044f \u2014 \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u044b \u0438 \u043f\u043e\u043b\u044f. \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e <code>where*<\/code>:<\/p>\n<pre><code>; \u0441\u043a\u043b\u0435\u0438\u0432\u0430\u0435\u043c 2 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0432\u043c\u0435\u0441\u0442\u0435 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 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 '[&gt; 1 2] '[&lt; &quot;a&quot; &quot;b&quot;]) ; =&gt; '[and [&gt; 1 2] [&lt; &quot;a&quot; &quot;b&quot;]])  (conj-expression '[and [&gt; 1 [+ 2 3]] [= :x :y]] '[&lt;&gt; &quot;a&quot; &quot;b&quot;]) ; =&gt; '[and [&gt; 1 [+ 2 3]] [= :x :y] [&lt;&gt; &quot;a&quot; &quot;b&quot;]]  (defn where*   [query expr]     (assoc query :where (conj-expression (:where query) expr))) <\/code><\/pre>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u0438\u0448\u043b\u0430 \u043f\u043e\u0440\u0430 \u0434\u043b\u044f <code>render-where<\/code>:<\/p>\n<pre><code>; \u0432\u0437\u0430\u0438\u043c\u043d\u043e\u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0432\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 (declare render-operator) (declare render-expression)  ; \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0438\u043b\u0438 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440? (defn- function-symbol? [s]   (re-matches #&quot;\\w+&quot; (name s)))  ; \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u0443\u0435\u043c \u0432\u044b\u0437\u043e\u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0438\u043b\u0438 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0430 (defn render-operator   [op & args]   (let [ra (map render-expression args)         lb (symbol &quot;(&quot;)         rb (symbol &quot;)&quot;)]     (if (function-symbol? op)       ; \u0444\u0443\u043d\u043a\u0446\u0438\u044f (count, max, ...)       [op lb (interpose (symbol &quot;,&quot;) ra) rb]       ; \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 (+, *, ...)       [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)) <\/code><\/pre>\n<p>  \u041e\u0442\u043b\u0438\u0447\u043d\u043e, \u0442\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u0435\u0439\u0448\u0438\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f:<\/p>\n<pre><code>(select   (from :Users)   (where* ['= :id 1])   (as-sql)) ; =&gt; (Sql. &quot;SELECT * FROM `Users` WHERE ( `id` = ? )&quot; [1]) <\/code><\/pre>\n<p>  \u041f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u043d\u0435\u043a\u0440\u0430\u0441\u0438\u0432\u043e, \u043f\u043e\u043f\u0440\u0430\u0432\u0438\u043c \u044d\u0442\u043e \u043d\u0435\u0441\u043b\u043e\u0436\u043d\u044b\u043c \u043c\u0430\u043a\u0440\u043e\u0441\u043e\u043c:<\/p>\n<pre><code>(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))) <\/code><\/pre>\n<p>  \u0417\u0430\u043c\u0435\u043d\u044f\u0435\u043c \u0432\u0441\u0435 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 (\u0441\u043f\u0438\u0441\u043a\u0438) \u043d\u0430 \u0432\u0435\u043a\u0442\u043e\u0440\u0430. \u041e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u043a\u0430\u043a \u0435\u0441\u0442\u044c. \u041c\u044b \u043f\u0440\u043e\u043f\u0443\u0441\u0442\u0438\u043b\u0438 \u0432\u0430\u0436\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u2014 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u044b \u0432 Clojure \u0438 SQL \u043d\u0430\u0437\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u043f\u043e-\u0440\u0430\u0437\u043d\u043e\u043c\u0443, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 <code>&lt;&gt<\/code> \u0438 <code>not=<\/code>. \u0412\u043e\u043f\u0440\u043e\u0441 \u0444\u0438\u043b\u043e\u0441\u043e\u0444\u0441\u043a\u0438\u0439, \u043a\u0430\u043a\u043e\u0439 \u0436\u0435 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u043b\u0443\u0447\u0448\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c. \u0421 \u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b, \u043c\u044b \u0440\u0435\u0448\u0438\u043b\u0438 \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u00ab\u0433\u043b\u0443\u043f\u043e\u0439\u00bb, \u0441 \u0434\u0440\u0443\u0433\u043e\u0439 \u2014 \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u043f\u0440\u0438\u044f\u0442\u043d\u0435\u0435 \u0432\u0438\u0434\u0435\u0442\u044c \u00ab\u0440\u043e\u0434\u043d\u044b\u0435\u00bb \u0434\u043b\u044f Clojure \u0444\u0443\u043d\u043a\u0446\u0438\u0438. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0438\u043c \u043e\u0431\u0430 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430:<\/p>\n<pre><code>(defn- canonize-operator-symbol   [op]   (get '{not= &lt;&gt;, == =} op op))  ; \u043f\u0435\u0440\u0435\u043f\u0438\u0448\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e (defn prepare-expression   [e]   (if (seq? e)     `(vector        (quote ~(canonize-operator-symbol (first e)))        ~@(map prepare-expression (rest e)))     e)) <\/code><\/pre>\n<p>  \u0425\u043e\u0440\u043e\u0448\u043e, \u043f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u043c\u0430\u043a\u0440\u043e\u0441\u0430 <code>where<\/code> \u043c\u043e\u0436\u043d\u043e \u043f\u0438\u0441\u0430\u0442\u044c \u043e\u0431\u0430 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430, \u043d\u043e \u0432\u043d\u0443\u0442\u0440\u0438 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0431\u0443\u0434\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u0438\u043d. \u0422\u043e \u0447\u0442\u043e \u043d\u0430\u0434\u043e. \u0423 \u043d\u0430\u0441 \u043e\u0441\u0442\u0430\u043b\u0441\u044f \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0434\u043e\u043b\u0436\u043e\u043a \u2014 \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u0434\u0436\u043e\u0438\u043d\u044b.<\/p>\n<pre><code>(defmacro join-left   ([q table cond] `(let [t# ~table] (join-left ~q t# t# ~cond)))   ([q table alias cond] (join* ~q :cross ~table ~alias ~(prepare-expression cond)))) ; \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e \u0434\u043b\u044f \u0434\u0440\u0443\u0433\u0438\u0445 \u0434\u0436\u043e\u0438\u043d\u043e\u0432, \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043b\u044e\u0447... <\/code><\/pre>\n<p>  \u041f\u0438\u0441\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u0445 \u043c\u0430\u043a\u0440\u043e\u0441\u043e\u0432 \u2014 \u043d\u0435\u0431\u043b\u0430\u0433\u043e\u0440\u043e\u0434\u043d\u043e\u0435 \u0434\u0435\u043b\u043e:<\/p>\n<pre><code>; \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u043e\u0447\u0435\u043d\u044c \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0439 \u043c\u0430\u043a\u0440\u043e\u0441 `do-template` (use 'clojure.template)  ; \u044d\u0442\u043e\u0442 \u043a\u043e\u0434 \u0440\u0430\u0437\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0432 5 \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u0438\u0439 \u043c\u0430\u043a\u0440\u043e\u0441\u043e\u0432 (do-template   [join-name join-key]  ; \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0434\u043b\u044f \u0448\u0430\u0431\u043b\u043e\u043d\u0430    ; \u0441\u0430\u043c \u0448\u0430\u0431\u043b\u043e\u043d   (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)))))    ; \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432   join-inner :inner,   join :inner,   join-right :right,   join-left :left,   join-full :full) <\/code><\/pre>\n<h4>\u0411\u043e\u043b\u044c\u0448\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439<\/h4>\n<p>  \u041f\u043e\u043a\u0430 \u043c\u044b \u0443\u043c\u0435\u0435\u043c \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u043e\u0441\u0442\u0435\u0439\u0448\u0438\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b. \u0421\u0434\u0435\u043b\u0430\u0435\u043c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439 \u0432 \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0438 \u0441\u0442\u043e\u043b\u0431\u0446\u043e\u0432.<\/p>\n<pre><code>; \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u043c `f` \u043a \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c `m` (\u043d\u0435 \u043a\u043b\u044e\u0447\u0430\u043c) (defn- map-vals   [f m]   (into (if (map? m) (empty m) {}) (for [[k v] m] [k (f v)])))  ; \u0441\u0447\u0435\u0442\u0447\u0438\u043a \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0445 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u0432 (def surrogate-alias-counter (atom 0))  ; \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u044b \u0432\u0438\u0434\u0430 :__00001234 (defn generate-surrogate-alias   []   (let [k (swap! surrogate-alias-counter #(-&gt; % inc (mod 1000000)))]     (keyword (format &quot;__%08d&quot; k))))  ; \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u043c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u043e\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0432 &quot;\u0430\u043b\u0438\u0430\u0441&quot; (defn as-alias   [n]   (cond     (keyword? n) n               ; \u0438\u043c\u044f \u0441\u0442\u043e\u043b\u0431\u0446\u0430\/\u0442\u0430\u0431\u043b\u0438\u0446\u044b \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u043a\u0430\u043a \u0435\u0441\u0442\u044c     (string? n) (keyword n)      ; \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e \u0434\u043b\u044f \u0441\u0442\u0440\u043e\u043a     :else (generate-surrogate-alias)))  ; \u0434\u043b\u044f \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u0441\u0443\u0440\u0440\u043e\u0433\u0430\u0442\u043d\u044b\u0439 \u0430\u043b\u0438\u0430\u0441  ; \u0441\u043f\u0438\u0441\u043e\u043a \u0441\u0442\u043e\u043b\u0431\u0446\u043e\u0432 \u0434\u043b\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u0430 -- \u0441\u043b\u043e\u0432\u0430\u0440\u044c &quot;\u0430\u043b\u0438\u0430\u0441 - \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435&quot; \u0438\u043b\u0438 \u0432\u0435\u043a\u0442\u043e\u0440 \u0441\u0442\u043e\u043b\u0431\u0446\u043e\u0432 (defn- prepare-fields   [fs]   (if (map? fs)     (map-vals prepare-expression fs)     (into {} (map (juxt as-alias prepare-expression) fs))))  (defn fields*   [query fd]   (assoc query :fields fd))  (defmacro fields   [query fd]   `(fields* ~query ~(prepare-fields fd)))  (defn render-field   [[alias nm]]   (if (= alias nm)     nm  ; \u043f\u0440\u043e\u0441\u0442\u043e \u0438\u043c\u044f \u0441\u0442\u043e\u043b\u0431\u0446\u0430     [(render-expression nm) 'AS alias]))  (defn render-fields   [{:keys [fields]}]   (if (or (nil? fields) (= fields :*))     '*     (interpose (symbol &quot;,&quot;) (map render-field fields)))) <\/code><\/pre>\n<p>  \u041d\u0435\u043f\u043b\u043e\u0445\u043e. \u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0430\u043a:<\/p>\n<pre><code>(select   (fields {:n :name, :a :age})  ; \u0430\u043b\u0438\u0430\u0441\u044b \u0434\u043b\u044f \u0441\u0442\u043e\u043b\u0431\u0446\u043e\u0432   (from :users))  ; \u0438\u043b\u0438 \u0442\u0430\u043a (select   (fields {:cnt (count :*), :max-age (max :age)})   (from :users))  ; \u0438\u043b\u0438 \u0434\u0430\u0436\u0435 \u0442\u0430\u043a (select   (fields [(count :*)])  (from :users)) <\/code><\/pre>\n<p>  \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0443. \u0423\u0436\u0435 \u043f\u0440\u0438\u0432\u044b\u0447\u043d\u044b\u0439 \u043f\u043e\u0440\u044f\u0434\u043e\u043a \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439: \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e <code>order*<\/code> \u0438 \u043c\u0430\u043a\u0440\u043e\u0441 <code>order<\/code>, \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c <code>render-order<\/code>:<\/p>\n<pre><code>(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 [[c d]]             [(render-expression c)              (get {nil [] :asc 'ASC :desc 'DESC} d d)])]     (if order       ['[ORDER BY] (interpose (symbol &quot;,&quot;) (map f order))]       []))) <\/code><\/pre>\n<p>  \u041f\u043e\u044f\u0432\u0438\u043b\u0430\u0441\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u044b\u0431\u043e\u0440\u043a\u0443 \u0432 \u043d\u0430\u0448\u0438\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u0445, \u0432 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435 \u043f\u043e \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u043e\u043c\u0443 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044e:<\/p>\n<pre><code>(select   (from :User)   (order (+ :message_cnt :post_cnt))) <\/code><\/pre>\n<p>  \u0410\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u044b\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c \u043c\u043e\u0436\u0435\u043c \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u043e\u043a, \u043f\u043e\u0434\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0438 \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0433\u043e\u2026 \u0412\u043e\u0442 \u0442\u0430\u043a, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0434\u043b\u044f <code>UNION ALL<\/code>:<\/p>\n<pre><code>; \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f-\u0440\u0435\u043d\u0434\u0435\u0440 (defn render-union-all   [{ss :selects}]   (interpose ['UNION 'ALL] (map render-select ss)))  ; \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0442\u0438\u043f, \u043f\u0440\u043e\u0441\u0442\u043e \u0445\u0440\u0430\u043d\u0438\u043c \u0441\u043f\u0438\u0441\u043e\u043a \u0432\u0441\u0435\u0445 \u0441\u0435\u043b\u0435\u043a\u0442\u043e\u0432 (defrecord UnionAll [selects]   SqlLike   (as-sql [this] (as-sql (render-union-all this))))  ; \u0442\u0443\u0442 \u043d\u0430\u043c *\u043d\u0435* \u043d\u0443\u0436\u043d\u0430 \u043f\u0430\u0440\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044f-\u043c\u0430\u043a\u0440\u043e\u0441 (defn union-all   [& ss]   (-&gt;UnionAll ss))  ;; \u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f ... (as-sql   (union-all     (select (from :Users) (fields [:email]))     (select (from :Accounts) (fields [:email])))) <\/code><\/pre>\n<h4>\u041f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0411\u0414 \u2014 \u0434\u0438\u0430\u043b\u0435\u043a\u0442\u044b<\/h4>\n<p>  \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0431\u0430\u0437 \u0434\u0430\u043d\u043d\u044b\u0445. \u0418\u0434\u0435\u044f \u043f\u0440\u043e\u0441\u0442\u0430: \u0440\u044f\u0434 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0432 \u043d\u0430\u0448\u0435\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0435 \u043c\u043e\u0436\u0435\u0442 \u043c\u0435\u043d\u044f\u0442\u044c \u0441\u0432\u043e\u0435 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a\u0443\u044e \u0431\u0430\u0437\u0443 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c. \u041e\u0440\u0433\u0430\u043d\u0438\u0437\u0443\u0435\u043c \u0434\u0440\u0435\u0432\u043e\u0432\u0438\u0434\u043d\u0443\u044e \u0438\u0435\u0440\u0430\u0440\u0445\u0438\u044e \u0434\u0438\u0430\u043b\u0435\u043a\u0442\u043e\u0432:<\/p>\n<pre><code>; \u0441\u0430\u043c\u044b\u0439 \u043e\u0431\u0449\u0438\u0439 \u0434\u0438\u0430\u043b\u0435\u043a\u0442 (def ^:const default-dialect ::sql92)  ; \u0442\u0443\u0442 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0434\u0438\u0430\u043b\u0435\u043a\u0442 \u0434\u043b\u044f \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u0441 \u0411\u0414 (def ^:dynamic *dialect* nil)  ; \u0430 \u044d\u0442\u043e \u0438\u0435\u0440\u0430\u0440\u0445\u0438\u044f \u0434\u0438\u0430\u043b\u0435\u043a\u0442\u043e\u0432 (def dialects-hierarchy (make-hierarchy))  ; \u0444\u0443\u043d\u043a\u0446\u0438\u044f, \u0447\u0442\u043e\u0431\u044b \u0440\u0435\u0433\u0435\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u0438\u0430\u043b\u0435\u043a\u0442\u044b \u0431\u044b\u043b\u043e \u0443\u0434\u043e\u0431\u043d\u0435\u0435 (defn register-dialect   ([dialect parent]     (alter-var-root #'dialects-hierarchy derive dialect parent))   ; \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0434\u0438\u0430\u043b\u0435\u043a\u0442\u044b \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u044e\u0442\u0441\u044f \u043e\u0442 ::sql92   ([dialect]     (register-dialect dialect default-dialect)))  ; \u043f\u0440\u0438\u043c\u0435\u0440 (register-dialect ::pgsql) (register-dialect ::pgsql92 ::pgsql)  ; postgresql \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c \u0441\u0432\u043e\u0438 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u044b ; \u043c\u043e\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c ad-hoc \u0434\u0438\u0430\u043b\u0435\u043a\u0442\u044b \u0434\u043b\u044f \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0445 \u0431\u0430\u0437  (register-dialect ::my-custom-db-with-extra-functions ::pgsql92) <\/code><\/pre>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043c\u0430\u043a\u0440\u043e\u0441 <code>defndialect<\/code>:<\/p>\n<pre><code>; \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u0434\u0438\u0430\u043b\u0435\u043a\u0442 ; \u0438\u0433\u043d\u043e\u0440\u0438\u0440\u0443\u0435\u043c \u0432\u0441\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b (defn current-dialect   [& _]   (or *dialect* default-dialect))  ; \u043c\u0430\u043a\u0440\u043e\u0441 \u0434\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f &quot;\u043e\u0431\u044b\u0447\u043d\u044b\u0445&quot; \u0444\u0443\u043d\u043a\u0446\u0438\u0439 (defmacro defndialect   [name & args-and-body]   `(do      ; \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u043c\u0443\u043b\u044c\u0442\u0438\u043c\u0435\u0442\u043e\u0434      (defmulti ~name current-dialect :hierarchy #'dialects-hierarchy)      ; \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0434\u043b\u044f \u0434\u0438\u0430\u043b\u0435\u043a\u0442\u0430 `sql92`      (defmethod ~name default-dialect ~@args-and-body))) <\/code><\/pre>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0443\u0436\u043d\u043e \u043d\u0435 \u0437\u0430\u0431\u044b\u0442\u044c \u0437\u0430\u043d\u0435\u0441\u0442\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0434\u0438\u0430\u043b\u0435\u043a\u0442\u0430 \u0432 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e <code>*dialect*<\/code>:<\/p>\n<pre><code>(defmacro with-db-dialect   [db & body]   ; \u0434\u0438\u0430\u043b\u0435\u043a\u0442 \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u043f\u0438\u0441\u0430\u0442\u044c \u0432 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043a \u0411\u0414   `(binding [*dialect* (:dialect ~db)]     ~@body)) <\/code><\/pre>\n<p>  \u041e\u0442\u043b\u0438\u0447\u043d\u043e. \u041e\u0441\u0442\u0430\u043b\u0441\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0448\u0430\u0433: \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0432\u0441\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0434\u043b\u044f \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430, \u0437\u0430\u043c\u0435\u043d\u044f\u044f <code>defn<\/code> \u043d\u0430 <code>defndialect<\/code>. \u0422\u0435\u043b\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u043c\u0435\u043d\u044f\u0442\u044c \u043d\u0435 \u043d\u0430\u0434\u043e. \u0418 \u0442\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0441 \u043f\u043e\u044f\u0432\u0438\u043b\u0430\u0441\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0440\u0430\u0437\u043d\u044b\u0439 SQL \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0431\u0430\u0437\u044b:<\/p>\n<pre><code>(defndialect quote-name   [s]   (let [x (name s)]     (if (= &quot;*&quot; x) x (str &quot;\\&quot;&quot; x &quot;\\&quot;&quot;))))  ; MySQL \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u043e\u0431\u0440\u0430\u0442\u043d\u044b\u0435 \u043a\u0430\u0432\u044b\u0447\u043a\u0438 (defmethod quote-name ::mysql   [s]   (let [x (name s)]     (if (= &quot;*&quot; x) x (str &quot;`&quot; x &quot;`&quot;)))) <\/code><\/pre>\n<p>  \u041d\u0430\u043f\u043e\u0441\u043b\u0435\u0434\u043e\u043a \u0437\u0430\u043c\u0435\u0447\u0430\u0435\u043c, \u0447\u0442\u043e \u0432\u043e\u0432\u0441\u0435 \u043d\u0435\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c <code>with-db-dialect<\/code> \u0432\u0440\u0443\u0447\u043d\u0443\u044e, \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u0430\u0442\u044c \u043d\u0430\u0448\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>fetch-*<\/code>:<\/p>\n<pre><code>(defn fetch-all   [db relation]     (jdbc\/query      db      (with-db-dialect db (to-sql-params relation))      :result-set-fn vec)) ; \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 fetch-* <\/code><\/pre>\n<h4>RAW \u0437\u0430\u043f\u0440\u043e\u0441\u044b<\/h4>\n<p>  \u0418\u043d\u043e\u0433\u0434\u0430 \u043d\u0443\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u2014 \u0438\u0445 \u043f\u0440\u043e\u0449\u0435 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0432 \u0432\u0438\u0434\u0435 \u0441\u0442\u0440\u043e\u043a\u0438, \u043c\u0438\u043d\u0443\u044f DSL. \u041d\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430:<\/p>\n<pre><code>(require '[clojure.string :as s])  (defn format-sql   [raw-sql args]     (let [; \u043d\u0430\u0445\u043e\u0434\u0438\u043c \u0432\u0441\u0435 \u043f\u043b\u0435\u0439\u0441\u0445\u043e\u043b\u0434\u0435\u0440\u044b \u0432\u0438\u0434\u0430 :x           al (map                (comp keyword second)                (re-seq #&quot;:([\\w.-]+)&quot; raw-sql))           ; \u0437\u0430\u043c\u0435\u043d\u044f\u0435\u043c \u0432\u0441\u0435 \u043f\u043b\u0435\u0439\u0441\u0445\u043e\u043b\u0434\u0435\u0440\u044b \u043d\u0430 &quot;?&quot; \t  pq (s\/replace raw-sql #&quot;:[\\w.-]+&quot; &quot;?&quot;)]       (-&gt;Sql pq (map args al))))  ; \u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f... (fetch-all db   (format-sql     &quot;SELECT * FROM Users WHERE role = :rl AND age &lt; :age&quot;     {:rl &quot;admin&quot; :age 18})) <\/code><\/pre>\n<p>  \u041a\u0441\u0442\u0430\u0442\u0438, \u0441\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432 <code>UNION ALL<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043b\u0438 \u0447\u0443\u0442\u044c \u0432\u044b\u0448\u0435. \u041a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u0438\u043d\u043a\u0440\u0435\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d\u043e \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u0438\u0445 \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f \u2014 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0431\u044b \u043f\u0430\u0440\u0441\u0438\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443 \u0441 SQL-\u043a\u043e\u0434\u043e\u043c. \u041e\u0431\u0445\u043e\u0434\u043d\u043e\u0439 \u043f\u0443\u0442\u044c \u2014 \u043f\u043e\u0434\u0437\u0430\u043f\u0440\u043e\u0441\u044b:<\/p>\n<pre><code>(defn users-by-role   [r]   (format-sql &quot;SELECT * FROM Users WHERE role = :r&quot; {:r r}))  ; \u0432\u043e\u0442 \u0442\u0430\u043a \u043d\u0435\u043b\u044c\u0437\u044f (-&gt;   (users-by-role &quot;ADMIN&quot;)   (order :name)   (as-sql))  ; \u0430 \u0432\u043e\u0442 \u0442\u0430\u043a \u043c\u043e\u0436\u043d\u043e..? (select   (from :x (users-by-role &quot;ADMIN&quot;))   (order :name)   (as-sql)) ; =&gt; #user.Sql{:sql &quot;SELECT * FROM SELECT * FROM Users WHERE role = ? AS `x` ORDER BY `name`&quot;, :args (&quot;ADMIN&quot;)} <\/code><\/pre>\n<p>  \u0423\u043f\u0441, \u0432 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u043c SQL \u043d\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442 \u043a\u0440\u0443\u0433\u043b\u044b\u0445 \u0441\u043a\u043e\u0431\u043e\u0447\u0435\u043a. \u0423\u0441\u0442\u0440\u0430\u043d\u044f\u0435\u043c \u043e\u043f\u043b\u043e\u0448\u043d\u043e\u0441\u0442\u044c, \u0432\u043e\u0442 \u0438\u0441\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f <code>render-table<\/code>:<\/p>\n<pre><code>(defn render-table   [[alias table]]   (if (= alias table)     ; \u0435\u0441\u043b\u0438 \u0430\u043b\u0438\u0430\u0441 \u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u0430 \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u044e\u0442, \u0442\u043e \u043d\u0435 \u0432\u044b\u0432\u043e\u0434\u0438\u043c 'AS'     table     ; \u0435\u0441\u043b\u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u0430 - \u044d\u0442\u043e sql - \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0441\u043a\u043e\u0431\u043e\u0447\u043a\u0438     (if (or (instance? Sql table) (instance? Select table))       [(symbol &quot;(&quot;) table (symbol &quot;)&quot;) 'AS alias]       [table 'AS alias])))  ; \u0432\u043e\u0442 \u0442\u0435\u043f\u0435\u0440\u044c \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043a\u0430\u043a \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u043e (select   (from :x (users-by-role &quot;ADMIN&quot;))   (order :name)   (as-sql)) <\/code><\/pre>\n<h4>\u041f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0441 \u0411\u0414<\/h4>\n<p>  \u0420\u0430\u0437\u0443\u043c\u0435\u0435\u0442\u0441\u044f, \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0442\u044c \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u043d\u043e\u0432\u043e\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0432\u043d\u0443\u0442\u0440\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 <code>fetch-*<\/code> \u043d\u0435 \u0432\u0430\u0440\u0438\u0430\u043d\u0442. \u0421\u043d\u043e\u0432\u0430 \u043c\u0430\u043a\u0440\u043e\u0441:<\/p>\n<pre><code>(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))) <\/code><\/pre>\n<p>  \u0422\u0443\u0442 \u043c\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0447\u0442\u043e \u043e\u0442\u043a\u0440\u044b\u0442\u043e\u0433\u043e \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u0435\u0449\u0435 \u043d\u0435\u0442\u0443, \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u043c \u043d\u043e\u0432\u043e\u0435 \u0438 \u00ab\u043f\u0440\u0438\u043a\u0440\u0435\u043f\u043b\u044f\u0435\u043c\u00bb \u043a \u0441\u043b\u043e\u0432\u0430\u0440\u044e \u0441 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438 \u0411\u0414. \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0443\u0436\u043d\u043e \u0442\u0430\u043a:<\/p>\n<pre><code>(def db {...})  (with-connection [c db]   ; \u0432 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440e `c` \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0438\u0437 `db` + \u043e\u0442\u043a\u0440\u044b\u0442\u043e\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435   (fetch-all c (select (from :B)))   ; ...   (fetch-all c (select (from :A)))) <\/code><\/pre>\n<p>  \u0410\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u044b\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0439.<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0431\u043e\u043d\u0443\u0441 &#8212; \u0431\u043e\u043b\u044c\u0448\u0435 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438 \u0441 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438 \u043d\u0435\u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f<\/b><\/p>\n<div class=\"spoiler_text\">\u041e\u0447\u0435\u0432\u0438\u0434\u043d\u043e, \u0447\u0442\u043e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0432\u043d\u043e\u0441\u0438\u0442 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0440\u0430\u0441\u0445\u043e\u0434\u044b: \u043d\u0443\u0436\u043d\u043e \u0441\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u0432 \u0441\u0430\u043c\u043e\u043c \u0432\u044b\u0441\u043e\u043a\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u043e\u043c \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0438, \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 <code>render-select<\/code>, \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043f\u0440\u043e\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0447\u0435\u0440\u0435\u0437 <code>as-sql<\/code>. \u0412 \u0434\u043e\u0431\u0430\u0432\u043e\u043a \u043a\u043e \u0432\u0441\u0435\u043c\u0443, \u043c\u043d\u043e\u0433\u0438\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0443 \u043d\u0430\u0441 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u044b \u0447\u0435\u0440\u0435\u0437 <code>defndialect<\/code>, \u0447\u0442\u043e \u0442\u043e\u0436\u0435 \u043e\u0442\u0440\u0438\u0446\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0441\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438. \u041e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u043e\u0431\u0438\u0434\u043d\u043e \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u0442\u044c \u0442\u0430\u043a\u0438\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u043f\u0440\u043e\u0441\u0442\u0435\u0439\u0448\u0438\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0432\u0440\u043e\u0434\u0435 \u00ab\u0432\u044b\u0442\u0430\u0449\u0438\u0442\u044c \u0437\u0430\u043f\u0438\u0441\u044c \u043f\u043e id\u00bb. \u041f\u043e \u043f\u0440\u0430\u0432\u0434\u0435 \u0433\u043e\u0432\u043e\u0440\u044f, \u043e\u0432\u0435\u0440\u0445\u0435\u0434 \u0441\u043e\u0432\u0441\u0435\u043c \u043d\u0435\u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043f\u043e \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044e \u0441\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0435\u043c \u0440\u0430\u0431\u043e\u0442\u044b \u0411\u0414\u2026 \u041d\u043e \u043f\u0440\u0438 \u0441\u0438\u043b\u044c\u043d\u043e\u043c \u0436\u0435\u043b\u0430\u043d\u0438\u0438 \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0435\u0449\u0435 \u0431\u043e\u043b\u044c\u0448\u0435 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438. \u0418\u0442\u0430\u043a, \u043d\u0430\u0448\u0430 \u0446\u0435\u043b\u044c:<\/p>\n<pre><code>; \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u043c\u0430\u043a\u0440\u043e\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u0443\u0435\u0442 SQL \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u0438\u043d \u0440\u0430\u0437 (defselect get-user-by-id [x]   (from :Users)   (where (= :id x))))  ; \u0438\u043b\u0438 \u0442\u0430\u043a, \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u0443\u0434\u043e\u0431\u043d\u043e \u043e\u0444\u043e\u0440\u043c\u043b\u044f\u0442\u044c legacy \u0437\u0430\u043f\u0440\u043e\u0441\u044b (defselect get-user-by-id [x]   &quot;SELECT * FROM `Users` WHERE `id` = :x&quot;)  ; \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c (fetch-one db (get-user-by-id 123)) <\/code><\/pre>\n<p>  \u0415\u0441\u0442\u044c \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u043a\u0430 \u2014 \u0434\u0438\u0430\u043b\u0435\u043a\u0442\u044b. \u041c\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u043c \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u044d\u0442\u0430\u043f\u0435 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u0438 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b (\u0432 \u0442\u0435\u043b\u0435 \u043c\u0430\u043a\u0440\u043e\u0441\u0430), \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043d\u0435 \u0437\u043d\u0430\u0435\u043c \u043a\u0430\u043a\u043e\u0439 \u0436\u0435 \u0434\u0438\u0430\u043b\u0435\u043a\u0442 \u0431\u0443\u0434\u0435\u0442 \u0430\u043a\u0442\u0438\u0432\u0435\u043d \u043f\u0440\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438. \u041c\u043e\u0436\u043d\u043e \u043f\u0440\u0435\u0434\u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441 \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0445 \u0434\u0438\u0430\u043b\u0435\u043a\u0442\u043e\u0432, \u043d\u043e \u043e\u043d\u0438 \u0432\u0435\u0434\u044c \u043c\u043e\u0433\u0443\u0442 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438 (\u0432 \u0440\u0430\u043d\u0442\u0430\u0439\u043c\u0435) \u2014 \u0441\u043a\u043e\u0440\u0435\u0435 \u0432\u0441\u0435\u0433\u043e \u043c\u044b \u043f\u0440\u043e\u043f\u0443\u0441\u0442\u0438\u043c \u043d\u0443\u0436\u043d\u044b\u0439, \u043f\u043b\u043e\u0445\u043e.<\/p>\n<p>  \u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u2014 \u043a\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b. \u0422.\u0435. \u043a\u0430\u0436\u0434\u044b\u0439 \u0442\u0430\u043a\u043e\u0439 <code>defselect<\/code> \u0445\u0440\u0430\u043d\u0438\u0442 \u0432 \u0441\u0435\u0431\u0435 \u043a\u0435\u0448 \u2014 \u0441\u043b\u043e\u0432\u0430\u0440\u044c \u00ab\u0434\u0438\u0430\u043b\u0435\u043a\u0442 \u2014 SqlLike-\u043e\u0431\u044a\u0435\u043a\u0442\u00bb. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0434\u0438\u0430\u043b\u0435\u043a\u0442\u0430 \u043c\u044b \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u044e (\u043f\u043e\u0442\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u0434\u043e\u0440\u043e\u0433\u0443\u044e \u0434\u043b\u044f \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432) \u043e\u0434\u0438\u043d \u0440\u0430\u0437 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0434\u0438\u0430\u043b\u0435\u043a\u0442\u0430. \u041f\u043e\u0441\u043b\u0435 \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u0438 <code>Sql<\/code> \u043c\u044b \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u043e\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u043d\u0443\u0436\u043d\u044b\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b \u0432 \u043f\u043e\u043b\u0435 <code>:args<\/code>, \u043d\u0438\u043a\u0430\u043a \u043d\u0435 \u0438\u0437\u043c\u0435\u043d\u044f\u044f <code>:sql<\/code>. <\/p>\n<pre><code>; \u043b\u0435\u043d\u0438\u0432\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 - \u043f\u0440\u043e\u0441\u0442\u043e \u0445\u0440\u0430\u043d\u0438\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0434\u043b\u044f \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f SQL \u043a\u043e\u0434\u0430 (defrecord LazySelect [content-fn]   SqlLike   (as-sql [this] (content-fn)))  ; \u0443\u0436\u0435 \u0433\u043e\u0442\u043e\u0432\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u0432 \u0432\u0438\u0434\u0435 \u0441\u0442\u0440\u043e\u043a\u0438 (defrecord RenderedSelect [content]   SqlLike   (as-sql [this] (as-sql content)))  ; \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0442\u0438\u043f (defrecord SurrogatedArg [symbol]   SqlLike   (as-sql [this] (Sql. symbol &quot;?&quot;)))  (defn emit-precompiled-select   [name args body]    (let [; \u0442\u0443\u0442 args - \u0438\u043c\u0435\u043d\u0430 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438         sargs (map -&gt;SurrogatedArg args)         ; \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0441\u0443\u0440\u0440\u043e\u0433\u0430\u0442\u043d\u044b\u0445 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0432 \u0441\u0438\u043c\u0432\u043e\u043b\u044b         sargs-args (into {} (map vector sargs args))]      `(let [sqls# (atom {})  ; \u0442\u0443\u0442 \u0445\u0440\u0430\u043d\u0438\u043c \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b             ; &quot;\u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u0430\u044f&quot; \u0444\u0443\u043d\u043a\u0446\u0438\u044f            original# (fn ~name ~args (as-sql (select ~@body)))             ; \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e,            ; \u043d\u043e \u0441 \u0441\u0443\u0440\u0440\u043e\u0433\u0430\u0442\u043d\u044b\u043c\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438            compile# (fn [] (apply original# (list ~@sargs)))]         (defn ~name ~args          (-&gt;LazySelect           (fn []             (let [; \u0431\u0435\u0440\u0435\u043c \u0434\u0438\u0430\u043b\u0435\u043a\u0442, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0435\u0441\u0442\u044c \u043b\u0438                   ; \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441                   dialect# (current-dialect)                   cached-sql# (get @sqls# dialect#)                    ; \u0435\u0441\u043b\u0438 \u043d\u0435\u0442 - \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u043d\u043e\u0432\u044b\u0439                   sql# (if cached-sql#                          cached-sql#                           ; \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u044f \u0443\u043f\u0440\u043e\u0449\u0435\u043d\u0430                          ; \u0437\u0430\u043f\u0440\u043e\u0441 \u043c\u043e\u0436\u0435\u0442 \u0441\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437,                          ; \u043d\u043e \u043d\u0430\u043c \u044d\u0442\u043e \u043d\u0435 \u0441\u0442\u0440\u0430\u0448\u043d\u043e - \u0438\u0433\u043d\u043e\u0440\u0438\u0440\u0443\u0435\u043c                          (let [new-sql# (compile#)]                            (swap! sqls# assoc dialect# new-sql#)                            new-sql#))                    ; \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u043c \u0432\u0435\u043a\u0442\u043e\u0440 \u0441 \u0441\u0443\u0440\u0440\u043e\u0433\u0430\u0442\u043d\u044b\u043c\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438                   args# (:args sql#)]                ; \u0437\u0430\u043c\u0435\u043d\u044f\u0435\u043c \u0441\u0443\u0440\u0440\u043e\u0433\u0430\u0442\u043d\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043d\u0430 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0435               (assoc sql# :args (replace ~sargs-args args#)))))))))  ; \u0437\u0430\u043f\u0440\u043e\u0441 \u0437\u0430\u0434\u0430\u043d \u0432 \u0432\u0438\u0434\u0435 \u0441\u0442\u0440\u043e\u043a\u0438 (defn emit-raw-select   [name args sql]   ; \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u0441\u043f\u0438\u0441\u043e\u043a \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432   (let [args-map (into {} (map (juxt keyword identity) args))]     ; \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e, \u043f\u043e\u0440\u043e\u0436\u0434\u0430\u044e\u0449\u0443\u044e RenderedSelect     `(defn ~name ~args        (-&gt;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))) <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<h4>\u0412 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0435<\/h4>\n<p>  \u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u043d\u0435 \u0437\u0430\u0442\u0440\u043e\u043d\u0443\u0442\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0434\u043b\u044f \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0411\u0414: \u0432\u0441\u0442\u0430\u0432\u043a\u0430, \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435, \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0437\u0430\u043f\u0438\u0441\u0435\u0439. \u041d\u0435\u0442\u0443 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 DDL, \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f\u043c\u0438 \u0434\u0430 \u0438 \u043c\u043d\u043e\u0433\u043e \u0447\u0435\u0433\u043e \u0435\u0449\u0435. \u0417\u0430\u0442\u043e \u043d\u043e\u0432\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043b\u0435\u0433\u043a\u043e, \u0447\u0430\u0441\u0442\u043e \u0434\u0430\u0436\u0435 \u0431\u0435\u0437 \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0433\u043e \u043a\u043e\u0434\u0430. \u041f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u2014 \u043e\u0434\u0438\u043d \u0438\u0437 \u043c\u043d\u043e\u0433\u0438\u0445, \u043d\u0435 \u0431\u0435\u0437 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0432, \u043d\u043e \u0432\u043f\u043e\u043b\u043d\u0435 \u0438\u043c\u0435\u044e\u0449\u0438\u0439 \u043f\u0440\u0430\u0432\u043e \u043d\u0430 \u0436\u0438\u043d\u044c. \u041d\u0430\u043f\u043e\u0441\u043b\u0435\u0434\u043e\u043a \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 <a href=\"https:\/\/github.com\/anjensan\/azql\">\u043a\u043e\u0434 \u043f\u043e\u043b\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438<\/a>, \u043f\u043e \u043c\u043e\u0442\u0438\u0432\u0430\u043c \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0438 \u0431\u044b\u043b\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0430 \u044d\u0442\u0430 \u0441\u0442\u0430\u0442\u044c\u044f.    \t<\/p>\n<div class=\"clear\"><\/div>\n<\/p><\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"http:\/\/habrahabr.ru\/post\/204992\/\"> http:\/\/habrahabr.ru\/post\/204992\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div class=\"content html_format\">   \t<img decoding=\"async\" src=\"http:\/\/habr.habrastorage.org\/post_images\/fea\/6af\/72b\/fea6af72b09f9ded1aa29426d1c429e8.png\" align=\"left\"\/><br \/>  \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043d\u0430\u043f\u0438\u0448\u0435\u043c Clojure-\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0440\u0435\u043b\u044f\u0446\u0438\u043e\u043d\u043d\u044b\u043c\u0438 \u0411\u0414. \u0417\u0430\u043e\u0434\u043d\u043e \u043f\u043e\u0442\u0440\u0435\u043d\u0438\u0440\u0443\u0435\u043c\u0441\u044f \u0432 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u043c\u0430\u043a\u0440\u043e\u0441\u043e\u0432, \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u044b \u0438 \u043c\u0443\u043b\u044c\u0442\u0438\u043c\u0435\u0442\u043e\u0434\u044b. \u0412\u0435\u0434\u044c \u043d\u0435\u0442\u0443 \u043b\u0443\u0447\u0448\u0435\u0433\u043e \u0441\u043f\u043e\u0441\u043e\u0431\u0430 \u0443\u0437\u043d\u0430\u0442\u044c \u044f\u0437\u044b\u043a, \u043d\u0435\u0436\u0435\u043b\u0438 \u0447\u0442\u043e-\u0442\u043e \u043d\u0430 \u043d\u0435\u043c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c. \u041d\u0443\u2026 \u0438\u043b\u0438 \u043f\u043e\u0447\u0438\u0442\u0430\u0442\u044c, \u043a\u0430\u043a \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u043a\u0442\u043e-\u0442\u043e \u0434\u0440\u0443\u0433\u043e\u0439.  <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-204992","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/204992","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=204992"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/204992\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=204992"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=204992"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=204992"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}