1. Куча / Говнокод #9545

    +133

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    20. 20
    21. 21
    22. 22
    23. 23
    24. 24
    (require 'clsql)
    
    (clsql:file-enable-sql-reader-syntax)
    
    (clsql:connect
     '("localhost" "database" "user" "password")
     :database-type :mysql)
    
    (defun how-many-goods-do-you-have (year month)
      (declare
       (type (integer 2000 2011) year)
       (type (integer 1 12) month))
      (clsql:select [item_id] [sale_date]
    		:from "table"
    		:where [or
    		[is [null [sale_date]]]
    		[< [sale_date]
    		(clsql:sql 'str_to_date\(
    			   (format
    			    nil
    			    "~a-~2,'0d-00"
    			    year month)
    			   '|, '%Y-%m-%d')|
    			   )]]))

    Эксперименты :)

    Запостил: wvxvw, 26 Февраля 2012

    Комментарии (14) RSS

    • Задумка понятна, исполнение немного хромает :)
      Для Clojure уже есть неплохой ништяк для этого:
      http://sqlkorma.com/
      Ответить
      • Тут исполнение даже так себе ничего хромает :) вместо
        where 'yyyy-mm-dd' < some_field
        получили
        where str_to_date('yyyy-mm-dd','%y-%m-%d') < some_field
        Ответить
        • на мой взгляд, оба случая недостаточно "lispish", я бы предпочёл что-то типа этого:
          (clsql:select "table"
            (clsql:where [< (clsql:to-date "yyyy-mm-dd") some-field]))
          to-date, вероятно, должен зависеть от диалекта sql
          Ответить
          • Там даже to-date никакой не нужен, это ж просто строка. Это объективное ориентирование подводит: сохранял же дату, вот с датой и нужно сравнить :) В итоге переписалось как-то так (это не вся функция, да и рабочей никогда не была, просто эксперименты какие-то старые, нужно было что-то с clsql сделать, решил найти, и нашел :)

            (defun how-many-goods-do-you-have (year month)
              (declare
               (type (integer 2000 2012) year)
               (type (integer 1 12) month))
              (let ((search-date
            	 (format nil "~a-~2,'0d-00"
            	   year month)))
                (clsql:select [item_id] [sale_date] [acquisition_date]
            		  :from "table"
            		  :where
            		  [and
            		  [<= [acquisition_date] search-date]
            		  [or
            		  [is [null [sale_date]]]
            		  [> [sale_date] search-date]]])))
            Ответить
            • а как вложеные селекты?

              как-то для лиспа это неправильно, если селект не есть (select (from ...) (where ...) ...), потому что концепцию ломает.

              да и опять же: я бы разделил генерацию запросов от их исполнения. это здесь очень похоже не делается.

              ЗЫ с одной сторны. с другой, а на кой фиг? народ знает SQL и есть внешние тулзы для работы с ним - самый логичный и гибкий вариант это оставить запросы строками. и с нестандартизироваными хинтами граблей потом тоже не будет.
              Ответить
              • бенефиты у генераторов запросов одни и теже: потенциально большая переносимость между диалектами + более тесная интеграция с языком и проверки на этапе компиляции + дополнительная возможность абстракции (легко можно собирать запросы по частям в рантайме)
                Ответить
              • Не, запрос генерируется отдельно, или можно отдельно, если хочется. (clsql:sql ...) собственно это и делает. Просто внутри конкретной функции он сразу и создается и отсылается. Смысл дополнительного синтаксиса - ну я не знаю, возможно есть смысл, если оно динамически создается, чтобы случайно не создать чего-то непредвиденное. Там еще есть какой-то ОРМ и всякое такое, на что я никогда даже не смотрел :) Может там и менеджеры какие-то хитрые есть. Просто никогда не нужно было.
                Вложенные селекты - интересно :) Не знаю, никогда не нужно было, я только для каких-то совсем примитивных вещей использовал. Но как видно из примера выше - запихать любую строку можно в селект, ну ток выглядит страшновато :)
                Ответить
    • Люди, а что это за ЯП? Просто первый раз вижу такой синтаксис, молодой.)))
      Ответить
      • Common Lisp.
        Искренне Ваш, КО.
        Ответить
      • Тут может квадратные скобки могли смутить - это не типичный для CL синтаксис - такой вот ридер-макрос решили в clsql сделать. Зачем - я так толком никогда и не смотрел, возможно чтобы за регистром символов следить, или чтобы кодировка в Лиспе совпадала с кодировкой в базе - не знаю. А может просто так :)
        Ответить
        • Судя по всему, там происходит генерация ссылок на таблицы/поля таблиц + всяческая нормализация
          clsql-6.1.1/sql/syntax.lisp
          (defmacro file-enable-sql-reader-syntax ()
            "Turns on the SQL reader syntax for the rest of the file.
          The CL spec says that when finished loading a file the original
          *readtable* is restored.  clhs COMPILE-FILE"
            '(eval-when (:compile-toplevel :load-toplevel :execute)
              (setf *readtable* (copy-readtable))
              (set-macro-character *sql-macro-open-char* #'sql-reader-open)
              (set-macro-character *sql-macro-close-char* (get-macro-character #\)))))
          ;; ...
          (defun sql-reader-open (stream char)
            (declare (ignore char))
            (let ((sqllist (read-delimited-list #\] stream t)))
              (unless *read-suppress*
                (handler-case
                    (cond ((string= (write-to-string (car sqllist)) "||")
                           (cons (sql-operator 'concat-op) (cdr sqllist)))
                          ((and (= (length sqllist) 1) (eql (car sqllist) '*))
                           (apply #'generate-sql-reference sqllist))
                          ((sql-operator (car sqllist))
                           (cons (sql-operator (car sqllist)) (cdr sqllist)))
                          (t (apply #'generate-sql-reference sqllist)))
                  (sql-user-error (c)
                    (error 'sql-user-error
                           :message (format nil "Error ~A occured while attempting to parse '~A' at file position ~A"
                                            (sql-user-error-message c) sqllist (file-position stream))))))))
          Ответить
          • А, ну собственно, по большей части похоже, что сделано для того, чтобы не пересекались уже определенные функции с ихними, типа [*] не совпадал с #'*.
            Ответить
    • Экскременты:)
      Ответить

    Добавить комментарий