   [^Cluster cluster]
   (.close cluster))
 
-(defmacro prepared
-  "Same as cassaforte.policies/forcing-prepared-statements. Kept for backwards
-   compatibility."
-  [& body]
+(defmacro prepare
+  "Prepare a single statement, return prepared statement"
+  [body]
   `(binding [hayt/*prepared-statement* true
              hayt/*param-stack*        (atom [])]
-     (do ~@body)))
+     (do ~body)))
 
 (defmacro with-fetch-size
   "Temporarily alters fetch size."

  ([^String string-query]
     (set-statement-options- (SimpleStatement. string-query))))

(defn ^PreparedStatement prepare
  "Prepares the provided query on C* server for futher execution.

   This assumes that query is valid. Returns the prepared statement corresponding to the query."
  ([^Session session ^String query]
     (.prepare ^Session session query)))

(defn render-query
  "Renders compiled query"
  [query-params]
  (let [renderer (if hayt/*prepared-statement*
                   hayt/->prepared
                   hayt/->raw)]
    (renderer query-params)))

(defn compile-query
  "Compiles query from given `builder` and `query-params`"
  [query-params builder]
  (apply builder (flatten query-params)))

(defn as-prepared
  "Helper method to create prepared query from `query` string with `?` placeholders and values
   to be bound to the query."
  [query & values]
  (vector query values))

(defn- ^Statement statement-for
  [^Session session query prepared?]
  (if prepared?
    (if (coll? query)
      (build-statement (prepare session (first query))
                       (second query))
      (throw (IllegalArgumentException.
              "Query is meant to be executed as prepared, but no values were supplied.")))
    (build-statement query)))

(defn ^ResultSetFuture execute-async
  "Executes a pre-built query and returns a future.

           ^ResultSetFuture fut (.executeAsync session statement)]
       (future (conv/to-clj (.getUninterruptibly fut))))))

(defprotocol Execute
  (execute [query session]))

(extend-protocol Execute
  String
  (execute [query ^Session session]
    (execute (SimpleStatement. query) session))

  clojure.lang.PersistentVector
  (execute [[^String query _] ^Session session]
    ;; Works only in combination with (prepare ...)
    (.prepare session query))

  BoundStatement
  (execute [bound-statement ^Session session]
    (-> session
        (.executeAsync bound-statement)
        (.getUninterruptibly)
        (conv/to-clj)))
  SimpleStatement
  (execute [simple-statement ^Session session]
    (-> session
        (.executeAsync simple-statement)
        (.getUninterruptibly)
        (conv/to-clj))))

(comment
  (defn execute
    "Executes a pre-built query.

   Options
     * prepared - whether the query should or should not be executed as prepared, always passed
       explicitly, because `execute` is considered to be a low-level function."
    ([^Session session query]
       (execute session query {}))
    ([^Session session query {:keys [fetch-size]}]
       (let [^Statement statement (statement-for session query prepared)
             _                    (when fetch-size
                                    (.setFetchSize statement fetch-size))
             ^ResultSetFuture fut (.executeAsync session statement)
             res                  (.getUninterruptibly fut)]
         (conv/to-clj res)))))

(defn ^String export-schema
  "Exports the schema as a string"
