Как получить дату, хранящуюся в базе данных в виде строки в Clojure? - PullRequest
0 голосов
/ 09 февраля 2019

Когда я получаю значения из базы данных Postgres с помощью clojure.java.jdbc, я получаю

{:id 1, :name "example", :created_at #object[java.time.LocalDateTime 0x15e0aadc "2019-02-08T12:52:11.438633"]}

, когда хочу

{:id 1, :name "example", :created_at :created_at "2019-02-08T12:52:11.438633"]}

Я хочу, чтобы дата возвращалась в формате JSON и использовалась JavaScript.Второй пример не может быть идеальным форматом для этого, и поэтому я открыт для других, но объект Java не будет работать.

Я попробовал пару подходов, но компилятор выдал ряд'непревзойденные круглые скобки' ошибки в результате объекта date #.

Мысли о том, как это сделать?Я делаю что-то с исходным запросом SQL, я делаю что-то с возвращенными данными или что-то еще?

Ответы [ 2 ]

0 голосов
/ 09 февраля 2019

Я пытался воссоздать ваш результат с H2 db, но он дает мне результат Clojure #inst вместо ссылки на объект.


ОК, здесь проблема.Как говорится в вашей распечатке, у вас есть java.time.LocalDateTime (Clojure #inst - это java.util.Date объект).

Если вам нужна строковая версия, все, что вам нужно сделать, это вызвать функцию-член toString на нем:

  (let [ldt (LocalDateTime/parse "2019-02-01T00:00:00" )]

    (.toString ldt) => <#java.lang.String "2019-02-01T00:00">

Однако у вас нет информации о часовом поясе.Итак, вы, вероятно, хотите ZonedDateTime. МЫ ПРИМЕРИМ ЗОНУ ВРЕМЕННОГО ВРЕМЕНИ НИЖЕ (проверьте конфигурацию вашего сервера БД):

  (let [jud      (Date.)
        ldt      (LocalDateTime/parse "2019-02-01T00:00:00")
        zdt      (.atZone ldt (ZoneId/of "UTC"))  ; *** big assumption here! ***
        inst     (.toInstant zdt)
        inst-str (.toString inst) ]

    ; a Clojure #inst is just a java.util.Date object
    jud      =>  #inst "2019-02-09T19:38:30.088-00:00"   

    ; a ZonedDateTime can print in 2 ways
    zdt              => #object[java.time.ZonedDateTime 0x780af31 "2019-02-01T00:00Z[UTC]"]
    (.toString zdt)  => "2019-02-01T00:00Z[UTC]"

    ; a java.time.Instant also prints in 2 ways:
    instant          => #object[java.time.Instant 0x48301adb "2019-02-01T00:00:00Z"]
    instant-str      => "2019-02-01T00:00:00Z"

Обратите внимание, что ZDT имеет суффикс, такой как [UTC], прикрепленный к концу, поэтому выВозможно, вы захотите преобразовать его в Instant и затем использовать метод .toString, чтобы получить более простое строковое представление (ISO-8601).


Если вы не возражаете против использования внешней библиотеки дляЧтобы сделать это проще, библиотека tupelo.java-time имеет очень удобную вспомогательную функцию:

(ns xyz
  (require [tupelo.java-time :as tjt] ... ))

(tjt/string-date-time-iso zdt) => "2019-02-01T00:00:00Z"

Доступно много других вспомогательных функций.Пожалуйста, смотрите API Docs и модульные тесты для примеров .


Обновление

Я наконец-то исправил установку Postgres (имелсбросить пароль, чтобы заставить работать Hikari).Вот мой тестовый код:

(ns tst.demo.jdbc-pool
  (:use demo.core tupelo.core tupelo.test)
  (:require
    [clojure.java.jdbc :as jdbc]
    [hikari-cp.core :as pool]
    [tupelo.java-time :as tjt] ) )

(def datasource-options-pg
  {:adapter       "postgresql"
   :database-name "alan"
   :server-name   "localhost"
   :port-number   5433
   :username      "alan"
   :password      "secret" } )

(def ^:dynamic db-conn nil)

(defn with-connection-pool
  "Creates and uses a connection for test function"
  [tst-fn]
  (let [datasource (pool/make-datasource datasource-options-pg)]
    (binding [db-conn {:datasource datasource}]
      (tst-fn)
      (pool/close-datasource datasource)))) ; close the connection - also closes/destroys the in-memory database

(use-fixtures
  :once with-connection-pool) ; use the same db connection pool for all tests

Все вышеперечисленное - просто конфигурация.Вот модульный тест, который проверяет поведение:

(dotest
  (jdbc/db-do-commands db-conn ["drop table if exists langs"])
  (jdbc/db-do-commands db-conn
    [(jdbc/create-table-ddl :langs [[:id :serial]
                                    [:lang "varchar not null"]
                                    [:creation :timestamptz]])])
  (jdbc/insert-multi! db-conn :langs
    [{:lang "Clojure" :creation (tjt/iso-str->timestamp "2008-01-01T12:34:56Z")}
     {:lang "Java"    :creation (tjt/iso-str->timestamp "1995-06-01T07:08:09Z")}])

  (let [result (jdbc/query db-conn ["select * from langs"])]
    (is=  (vec result)
      [{:id       1, :lang "Clojure",
        :creation #inst "2008-01-01T12:34:56.000000000-00:00"}
       {:id       2, :lang "Java",
        :creation #inst "1995-06-01T07:08:09.000000000-00:00"}])))

Итак, вы можете видеть, что я все еще получаю результат java.util.Date, который Clojure печатает с форматированием #inst.Я не уверен, как вы получаете JDBC для вывода в формате LocalDateTime.

0 голосов
/ 09 февраля 2019

Я полагаю, что cheshire.core / encode даст вам хороший JSON с этой карты.

Подробнее о Чешире можно узнать на https://github.com/dakrone/cheshire

...