/*
 * Seagull: A SQLite helper library
 * Copyright (C) Seagull Developers
 *
 * Seagull is the legal property of its developers, whose names are too
 * numerous to list here. Please refer to the AUTHORS file distributed with
 * this source distribution
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by the
 * Free Software Foundation; either version 2.1 of the License, or (at your
 * option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, see <https://www.gnu.org/licenses/>.
 */

#if !defined(SEAGULL_GLOBAL_HEADER_INSIDE) && !defined(SEAGULL_COMPILATION)
# error "only <seagull.h> may be included directly"
#endif

#ifndef SEAGULL_STATEMENT_H
#define SEAGULL_STATEMENT_H

#include <glib.h>
#include <gio/gio.h>

#include "seagulltypes.h"
#include "seagullversion.h"

G_BEGIN_DECLS

#define SEAGULL_STATEMENT_ERROR seagull_statement_error_quark()

/**
 * SeagullStatementError:
 * @SEAGULL_STATEMENT_ERROR_NO_DB_PROVIDED: The db property was not specified.
 * @SEAGULL_STATEMENT_ERROR_NO_SQL_PROVIDED: The sql property was not
 *  specified.
 * @SEAGULL_STATEMENT_ERROR_PREPARATION_FAILED: The statement failed to
 *  prepare.
 * @SEAGULL_STATEMENT_ERROR_MORE_THAN_ONE_STATEMENT: More than one SQL
 *  statement was provided.
 * @SEAGULL_STATEMENT_ERROR_BIND_PARAMETER_NOT_FOUND: The named column was not
 *  found.
 * @SEAGULL_STATEMENT_ERROR_BIND_FAILED: Binding a parameter failed.
 * @SEAGULL_STATEMENT_ERROR_CLEAR_BINDINGS_FAILED: Clearing the bindings
 *  failed.
 * @SEAGULL_STATEMENT_ERROR_RESET_FAILED: Resetting the statement failed.
 * @SEAGULL_STATEMENT_ERROR_STEP_FAILED: Stepping the statement failed.
 * @SEAGULL_STATEMENT_ERROR_WRONG_COLUMN_TYPE: The requested column was not of
 *  the requested type.
 *
 * Error codes returned by statements.
 *
 * Since: 0.3
 */
typedef enum {
	SEAGULL_STATEMENT_ERROR_NO_DB_PROVIDED SEAGULL_AVAILABLE_ENUMERATOR_IN_0_3,
	SEAGULL_STATEMENT_ERROR_NO_SQL_PROVIDED SEAGULL_AVAILABLE_ENUMERATOR_IN_0_3,
	SEAGULL_STATEMENT_ERROR_PREPARATION_FAILED SEAGULL_AVAILABLE_ENUMERATOR_IN_0_3,
	SEAGULL_STATEMENT_ERROR_MORE_THAN_ONE_STATEMENT SEAGULL_AVAILABLE_ENUMERATOR_IN_0_3,
	SEAGULL_STATEMENT_ERROR_BIND_PARAMETER_NOT_FOUND SEAGULL_AVAILABLE_ENUMERATOR_IN_0_3,
	SEAGULL_STATEMENT_ERROR_BIND_FAILED SEAGULL_AVAILABLE_ENUMERATOR_IN_0_3,
	SEAGULL_STATEMENT_ERROR_CLEAR_BINDINGS_FAILED SEAGULL_AVAILABLE_ENUMERATOR_IN_0_3,
	SEAGULL_STATEMENT_ERROR_RESET_FAILED SEAGULL_AVAILABLE_ENUMERATOR_IN_0_3,
	SEAGULL_STATEMENT_ERROR_STEP_FAILED SEAGULL_AVAILABLE_ENUMERATOR_IN_0_3,
	SEAGULL_STATEMENT_ERROR_WRONG_COLUMN_TYPE SEAGULL_AVAILABLE_ENUMERATOR_IN_0_3,
	/**
	 * SEAGULL_STATEMENT_ERROR_BIND_OBJECT_PROPERTY_UNKNOWN_TYPE:
	 *
	 * A property was found for the given parameter, but the value type is
	 * unknown.
	 *
	 * Since: 0.4
	 */
	SEAGULL_STATEMENT_ERROR_BIND_OBJECT_PROPERTY_UNKNOWN_TYPE SEAGULL_AVAILABLE_ENUMERATOR_IN_0_4,
	/**
	 * SEAGULL_STATEMENT_ERROR_COLUMN_OBJECT_PROPERTY_UNKNOWN_TYPE:
	 *
	 * A property was found for the given column, but the value type is
	 * unknown.
	 *
	 * Since: 0.4
	 */
	SEAGULL_STATEMENT_ERROR_COLUMN_OBJECT_PROPERTY_UNKNOWN_TYPE SEAGULL_AVAILABLE_ENUMERATOR_IN_0_4,
	/**
	 * SEAGULL_STATEMENT_ERROR_FAILED_TO_LOAD_RESOURCE:
	 *
	 * The given resource was not able to be loaded.
	 *
	 * Since: 0.4
	 */
	SEAGULL_STATEMENT_ERROR_FAILED_TO_LOAD_RESOURCE SEAGULL_AVAILABLE_ENUMERATOR_IN_0_4,
} SeagullStatementError;

/**
 * seagull_statement_error_quark:
 *
 * The error domain to identify errors with statements.
 *
 * Returns: The error domain.
 *
 * Since: 0.3
 */
SEAGULL_AVAILABLE_IN_0_3
GQuark seagull_statement_error_quark(void);

#define SEAGULL_TYPE_STATEMENT (seagull_statement_get_type())

/**
 * SeagullStatement:
 *
 * A wrapper around sqlite3_stmt to make it easier to work with named
 * parameters.
 *
 * Since: 0.3
 */
SEAGULL_AVAILABLE_IN_0_3
G_DECLARE_FINAL_TYPE(SeagullStatement, seagull_statement, SEAGULL, STATEMENT,
                     GObject)

/**
 * seagull_statement_bind_boolean:
 * @name: the name of the parameter
 * @value: the value
 * @error: (out) (nullable): a return address for a #GError
 *
 * Binds a boolean to the named parameter.
 *
 * @name must be the exact name as specified in the query.
 *
 * Returns: true on success; otherwise false with error set.
 *
 * Since: 0.6
 */
SEAGULL_AVAILABLE_IN_0_6
gboolean seagull_statement_bind_boolean(SeagullStatement *statement, const char *name, gboolean value, GError **error);

/**
 * seagull_statement_bind_bytes:
 * @name: the name of the parameter
 * @value: (transfer none) (nullable): the value
 * @error: (out) (nullable): a return address for a #GError
 *
 * Binds a [type@GLib.Bytes] to the named parameter.
 *
 * @name must be the exact name as specified in the query.
 *
 * Returns: true on success.
 *
 * Since: 0.6
 */
SEAGULL_AVAILABLE_IN_0_6
gboolean seagull_statement_bind_bytes(SeagullStatement *statement, const char *name, GBytes *value, GError **error);

/**
 * seagull_statement_bind_date_time:
 * @name: the name of the parameter
 * @value: (transfer none): the value
 * @error: (out) (nullable): a return address for a #GError
 *
 * Binds a [type@GLib.DateTime] to the named parameter.
 *
 * The date time will be bound as an ISO-8601 string.
 *
 * @name must be the exact name as specified in the query.
 *
 * Returns: true on success; otherwise false with error set.
 *
 * Since: 0.5
 */
SEAGULL_AVAILABLE_IN_0_5
gboolean seagull_statement_bind_date_time(SeagullStatement *statement, const char *name, GDateTime *value, GError **error);

/**
 * seagull_statement_bind_double:
 * @name: the name of the parameter
 * @value: the value
 * @error: (out) (nullable): a return address for a #GError
 *
 * Binds a double value to the named parameter.
 *
 * @name must be the exact name as specified in the query.
 *
 * Returns: true on success; otherwise false with error set.
 *
 * Since: 0.3
 */
SEAGULL_AVAILABLE_IN_0_3
gboolean seagull_statement_bind_double(SeagullStatement *statement, const char *name, double value, GError **error);

/**
 * seagull_statement_bind_enum:
 * @name: the name of the parameter
 * @value: the value
 * @error: (out) (nullable): a return address for a #GError
 *
 * Binds an enum value to the named parameter.
 *
 * @name must be the exact name as specified in the query.
 *
 * Returns: true on success; otherwise false with error set.
 *
 * Since: 0.5
 */
SEAGULL_AVAILABLE_IN_0_5
gboolean seagull_statement_bind_enum(SeagullStatement *stmt, const char *name, int value, GError **error);

/**
 * seagull_statement_bind_error:
 * @name: the name of the parameter
 * @value: (transfer none) (nullable): the value
 * @error: (out) (nullable): a return address for a #GError
 *
 * Binds a [type@GLib.Error] value to the named parameter.
 *
 * The error will be encoded as a [type@GLib.Variant] with a format of `(sis)`
 * and is expecting to be bound to a bytes column. The domain is stored as a
 * string in the event the quark hasn't been created before it was needed.
 *
 * @name must be the exact name as specified in the query.
 *
 * Returns: true on success; otherwise false with error set.
 *
 * Since: 0.7
 */
SEAGULL_AVAILABLE_IN_0_7
gboolean seagull_statement_bind_error(SeagullStatement *statement, const char *name, GError *value, GError **error);

/**
 * seagull_statement_bind_flags:
 * @name: the name of the parameter
 * @value: the value
 * @error: (out) (nullable): a return address for a #GError
 *
 * Binds a flags value to the named parameter.
 *
 * @name must be the exact name as specified in the query.
 *
 * Returns: true on success; otherwise false with error set.
 *
 * Since: 0.5
 */
SEAGULL_AVAILABLE_IN_0_5
gboolean seagull_statement_bind_flags(SeagullStatement *stmt, const char *name, guint value, GError **error);

/**
 * seagull_statement_bind_int:
 * @name: the name of the parameter
 * @value: the value
 * @error: (out) (nullable): a return address for a #GError
 *
 * Binds an integer value to the named parameter.
 *
 * @name must be the exact name as specified in the query.
 *
 * Returns: true on success; otherwise false with error set.
 *
 * Since: 0.3
 */
SEAGULL_AVAILABLE_IN_0_3
gboolean seagull_statement_bind_int(SeagullStatement *statement, const char *name, int value, GError **error);

/**
 * seagull_statement_bind_int64:
 * @name: the name of the parameter
 * @value: the value
 * @error: (out) (nullable): a return address for a #GError
 *
 * Binds an int64 value to the named parameter.
 *
 * @name must be the exact name as specified in the query.
 *
 * Returns: true on success; otherwise false with error set.
 *
 * Since: 0.7
 */
SEAGULL_AVAILABLE_IN_0_7
gboolean seagull_statement_bind_int64(SeagullStatement *statement, const char *name, gint64 value, GError **error);

/**
 * seagull_statement_bind_null:
 * @name: the name of the parameter
 * @error: (out) (nullable): a return address for a #GError
 *
 * Binds a NULL value to the named parameter.
 *
 * @name must be the exact name as specified in the query.
 *
 * Returns: true on success; otherwise false with error set.
 *
 * Since: 0.3
 */
SEAGULL_AVAILABLE_IN_0_3
gboolean seagull_statement_bind_null(SeagullStatement *statement, const char *name, GError **error);

/**
 * seagull_statement_bind_object:
 * @prefix: (nullable): an optional prefix
 * @obj: the object
 * @error: (out) (nullable): a return address for a #GError
 *
 * Binds an object to the query.
 *
 * The parameters of the statement will be walked and if a property matching
 * the name of a parameter is found, then the parameter will be bound to the
 * value of that property.
 *
 * If parameters have conflicting names, you can pass a prefix to make sure the
 * correct ones are bound. Note that the prefix needs to look like a valid SQL
 * column name, so no spaces or dashes. See the following example.
 *
 * ```c
 * stmt = seagull_statement_new("INSERT INTO messages(id, author) "
 *                              "VALUES(:msg-id, :author-id)");
 * seagull_statement_bind_object(stmt, "msg_", message, &error);
 * seagull_statement_bind_object(stmt, "author_", author, &error);
 * ```
 *
 * This will look for properties named `id` on both the message and author
 * instances.
 *
 * Note that if a prefix is provided, it will be required for all parameters.
 * See the following example
 *
 * ```c
 * stmt = seagull_statement_new("INSERT INTO messages(id, author) "
 *                              "VALUES(:id, :author-id)");
 * // This bind doesn't match anything as there are no parameters with a msg-
 * // prefix.
 * seagull_statement_bind_object(stmt, "msg_", message, &error);
 *
 * // By not using a prefix, the :id parameter will get match to message:id.
 * seagull_statement_bind_object(stmt, NULL, message, &error);
 *
 * // Using a prefix with the author will only match the author-id parameter
 * // and leave the id parameter to the previously bound value.
 * seagull_statement_bind_object(stmt, "author_", author, &error);
 * ```
 *
 * Returns: true on success; otherwise false with error set.
 */
SEAGULL_AVAILABLE_IN_0_4
gboolean seagull_statement_bind_object(SeagullStatement *statement, const char *prefix, GObject *obj, GError **error);

/**
 * seagull_statement_bind_text:
 * @name: the name of the parameter
 * @value: (nullable): the value
 * @len: the length of the value in bytes, or -1 for NULL terminated
 * @destroy_notify: (nullable): a function to be called to free the value
 * @error: (out) (nullable): a return address for a #GError
 *
 * Binds a text value to the named parameter.
 *
 * @name must be the exact name as specified in the query.
 *
 * Returns: true on success; otherwise false with error set.
 *
 * Since: 0.3
 */
SEAGULL_AVAILABLE_IN_0_3
gboolean seagull_statement_bind_text(SeagullStatement *statement, const char *name, const char *value, int len, GDestroyNotify destroy_notify, GError **error);

/**
 * seagull_statement_bind_time_zone:
 * @name: the name of the parameter
 * @time_zone: (nullable): the value
 * @error: (out) (nullable): a return address for a #GError
 *
 * Binds a [struct@GLib.TimeZone] to a statement.
 *
 * The results of [method@GLib.TimeZone.get_identifier] is what will actually
 * be stored, so this will only work with a text column.
 *
 * @name must be the exact name as specified in the query.
 *
 * Returns: true on success; otherwise false with error set.
 *
 * Since: 0.6
 */
SEAGULL_AVAILABLE_IN_0_6
gboolean seagull_statement_bind_time_zone(SeagullStatement *statement, const char *name, GTimeZone *time_zone, GError **error);

/**
 * seagull_statement_bind_uint:
 * @name: the name of the parameter
 * @value: the value
 * @error: (out) (nullable): a return address for a #GError
 *
 * Binds an unsigned integer value to the named parameter.
 *
 * @name must be the exact name as specified in the query.
 *
 * Returns: true on success; otherwise false with error set.
 *
 * Since: 0.8
 */
SEAGULL_AVAILABLE_IN_0_8
gboolean seagull_statement_bind_uint(SeagullStatement *statement, const char *name, guint value, GError **error);

/**
 * seagull_statement_bind_uint64:
 * @name: the name of the parameter
 * @value: the value
 * @error: (out) (nullable): a return address for a #GError
 *
 * Binds an unsigned int64 value to the named parameter.
 *
 * @name must be the exact name as specified in the query.
 *
 * Returns: true on success; otherwise false with error set.
 *
 * Since: 0.8
 */
SEAGULL_AVAILABLE_IN_0_8
gboolean seagull_statement_bind_uint64(SeagullStatement *statement, const char *name, guint64 value, GError **error);

/**
 * seagull_statement_clear_bindings:
 * @error: (out) (nullable): a return address for a #GError
 *
 * Clears all of the bindings.
 *
 * Returns: true on success.
 *
 * Since: 0.3
 */
SEAGULL_AVAILABLE_IN_0_3
gboolean seagull_statement_clear_bindings(SeagullStatement *statement, GError **error);

/**
 * seagull_statement_column_boolean:
 * @name: the name of the column
 * @error: (out) (nullable): a return address for a #GError
 *
 * Gets the value of a column from the current result of a statement.
 *
 * @name must be the exact name or alias of the column as specified in the
 * query.
 *
 * Returns: The value on success; or error will be set on failure.
 *
 * Since: 0.6
 */
SEAGULL_AVAILABLE_IN_0_6
gboolean seagull_statement_column_boolean(SeagullStatement *statement, const char *name, GError **error);

/**
 * seagull_statement_column_bytes:
 * @name: the name of the column
 * @error: (out) (nullable): a return address for a #GError
 *
 * Gets the value of a column from the current result of a statement as a
 * [type@GLib.Bytes].
 *
 * @name must be the exact name or alias of the column as specified in the
 * query.
 *
 * Returns: (transfer full) (nullable): A new bytes object if found.
 *
 * Since: 0.6
 */
SEAGULL_AVAILABLE_IN_0_6
GBytes *seagull_statement_column_bytes(SeagullStatement *statement, const char *name, GError **error);

/**
 * seagull_statement_column_date_time:
 * @name: the name of the column
 * @error: (out) (nullable): a return address for a #GError
 *
 * Gets the value of a column from the current result of a statement.
 *
 * @name must be the exact name or alias of the column as specified in the
 * query.
 *
 * Returns: (transfer full) (nullable): The value on success or NULL on error
 *          with error set.
 *
 * Since: 0.6
 */
SEAGULL_AVAILABLE_IN_0_6
GDateTime *seagull_statement_column_date_time(SeagullStatement *statement, const char *name, GError **error);

/**
 * seagull_statement_column_double:
 * @name: the name of the column
 * @error: (out) (nullable): a return address for a #GError
 *
 * Gets the value of a column from the current result of a statement.
 *
 * @name must be the exact name or alias of the column as specified in the
 * query.
 *
 * Returns: The value on success or 0 on error with error set.
 *
 * Since: 0.3
 */
SEAGULL_AVAILABLE_IN_0_3
double seagull_statement_column_double(SeagullStatement *statement, const char *name, GError **error);

/**
 * seagull_statement_column_enum:
 * @name: the name of the column
 * @error: (out) (nullable): a return address for a #GError
 *
 * Gets the value of a column from the current result of a statement.
 *
 * @name must be the exact name or alias of the column as specified in the
 * query.
 *
 * Returns: The value on success or 0 on error with error set.
 *
 * Since: 0.5
 */
SEAGULL_AVAILABLE_IN_0_5
int seagull_statement_column_enum(SeagullStatement *statement, const char *name, GError **error);

/**
 * seagull_statement_column_error:
 * @name: the name of the column
 * @error: (out) (nullable): a return address for a #GError
 *
 * Gets the error value of a column from the current result of a statement.
 *
 * @name must be the exact name or alias of the column as specified in the
 * query.
 *
 * The column must be of the bytes type and have a serialized GVariant with a
 * format of `(sis)`.
 *
 * Returns: (transfer full) (nullable): The error on success or %NULL on error
 *          with error set.
 *
 * Since: 0.7
 */
SEAGULL_AVAILABLE_IN_0_7
GError *seagull_statement_column_error(SeagullStatement *statement, const char *name, GError **error);

/**
 * seagull_statement_column_flags:
 * @name: the name of the column
 * @error: (out) (nullable): a return address for a #GError
 *
 * Gets the value of a column from the current result of a statement.
 *
 * @name must be the exact name or alias of the column as specified in the
 * query.
 *
 * Returns: The value on success or 0 on error with error set.
 *
 * Since: 0.5
 */
SEAGULL_AVAILABLE_IN_0_5
guint seagull_statement_column_flags(SeagullStatement *statement, const char *name, GError **error);

/**
 * seagull_statement_column_int:
 * @name: the name of the column
 * @error: (out) (nullable): a return address for a #GError
 *
 * Gets the value of a column from the current result of a statement.
 *
 * @name must be the exact name or alias of the column as specified in the
 * query.
 *
 * Returns: The value on success or 0 on error with error set.
 *
 * Since: 0.3
 */
SEAGULL_AVAILABLE_IN_0_3
int seagull_statement_column_int(SeagullStatement *statement, const char *name, GError **error);

/**
 * seagull_statement_column_int64:
 * @name: the name of the column
 * @error: (out) (nullable): a return address for a #GError
 *
 * Gets the value of a column from the current result of a statement.
 *
 * @name must be the exact name or alias of the column as specified in the
 * query.
 *
 * Returns: The value on success or 0 on error with error set.
 *
 * Since: 0.7
 */
SEAGULL_AVAILABLE_IN_0_7
gint64 seagull_statement_column_int64(SeagullStatement *statement, const char *name, GError **error);

/**
 * seagull_statement_column_object:
 * @prefix: (nullable): an optional prefix
 * @obj: the object
 * @error: (out) (nullable): a return address for a #GError
 *
 * Updates the properties of any object based on the current result of a
 * statement.
 *
 * This will look for columns with the same name of the properties in @obj, and
 * if found, set the property in @obj to the return value. This is a helper
 * around manually calling [method@Statement.column_double],
 * [method@Statement.column_int], [method@Statement.column_text], etc.
 *
 * @prefix may be used to limit what columns to look for. Note that you most
 * likely will need to use the SQL `AS` keyword to make the column names have
 * the prefix like the following example.
 *
 * ```c
 * sql = "SELECT id AS message_id, content AS message_content "
 *       "FROM messages WHERE conversion_id=:conversation-id "
 *       "ORDER BY created_timestamp DESC LIMIT 10";
 * stmt = seagull_statement_new(db, SQL, NULL);
 * seagull_statement_bind_string(stmt, "conversation-id", "some-random-id", -1,
 *                               NULL, NULL);
 * seagull_statement_step(stmt, NULL);
 * message = new_message();
 * seagull_statement_column_object(stmt, "message_", message, NULL);
 * ```
 *
 * Note that the object must exist for this to work, so if the object has a
 * construct only property you can pull that out ahead of time and create the
 * object and then call this function. See the following example.
 *
 * ```c
 * sql = "SELECT id, title AS conversation_title, topic AS conversation_topic "
 *       "FROM conversations WHERE account_id=:account-id";
 * stmt = seagull_statement_new(db, sql, NULL);
 * seagull_statement_bind_string(stmt, "account-id", "some-account-id", -1,
 *                               NULL, NULL);
 * seagull_statement_step(stmt, NULL);
 * conversation_id = seagull_statement_column_string(stmt, "id", NULL);
 * conversation = conversation_new(conversation_id);
 * seagull_statement_column_object(stmt, "conversation_", conversation, NULL);
 * ```
 *
 * Note that true will be returned even if no properties in @obj have been
 * updated.
 *
 * Returns: true on success; or false on error with error set.
 *
 * Since: 0.3
 */
SEAGULL_AVAILABLE_IN_0_3
gboolean seagull_statement_column_object(SeagullStatement *statement, const char *prefix, GObject *obj, GError **error);

/**
 * seagull_statement_column_text:
 * @name: the name of the column
 * @error: (out) (nullable): a return address for a #GError
 *
 * Gets the value of a column from the current result of a statement.
 *
 * @name must be the exact name or alias of the column as specified in the
 * query.
 *
 * Returns: (nullable): The value on success or null on error with error set.
 *
 * Since: 0.3
 */
SEAGULL_AVAILABLE_IN_0_3
const char *seagull_statement_column_text(SeagullStatement *statement, const char *name, GError **error);

/**
 * seagull_statement_column_time_zone:
 * @name: the name of the column
 * @error: (out) (nullable): a return address for a #GError
 *
 * Gets the value of a column from the current result of a statement.
 *
 * This uses [ctor@GLib.TimeZone.new_identifier] internally, so the column must
 * be a text column.
 *
 * @name must be the exact name or alias of the column as specified in the
 * query.
 *
 * Returns: (transfer full) (nullable): The value on success or null on error
 *          with error set.
 *
 * Since: 0.6
 */
SEAGULL_AVAILABLE_IN_0_6
GTimeZone *seagull_statement_column_time_zone(SeagullStatement *statement, const char *name, GError **error);

/**
 * seagull_statement_column_uint:
 * @name: the name of the column
 * @error: (out) (nullable): a return address for a #GError
 *
 * Gets the value of a column from the current result of a statement.
 *
 * @name must be the exact name or alias of the column as specified in the
 * query.
 *
 * Returns: The value on success or 0 on error with error set.
 *
 * Since: 0.8
 */
SEAGULL_AVAILABLE_IN_0_8
guint seagull_statement_column_uint(SeagullStatement *statement, const char *name, GError **error);

/**
 * seagull_statement_column_uint64:
 * @name: the name of the column
 * @error: (out) (nullable): a return address for a #GError
 *
 * Gets the value of a column from the current result of a statement.
 *
 * @name must be the exact name or alias of the column as specified in the
 * query.
 *
 * Returns: The value on success or 0 on error with error set.
 *
 * Since: 0.8
 */
SEAGULL_AVAILABLE_IN_0_8
guint64 seagull_statement_column_uint64(SeagullStatement *statement, const char *name, GError **error);

/**
 * seagull_statement_get_db:
 *
 * Gets the database.
 *
 * Returns: (transfer none): The database.
 *
 * Since: 0.3
 */
SEAGULL_AVAILABLE_IN_0_3
SeagullSqlite3 *seagull_statement_get_db(SeagullStatement *statement);

/**
 * seagull_statement_get_expanded_sql:
 *
 * Gets the SQL statement with parameters expanded.
 *
 * If all parameters have not yet been bound, they will appears as their names.
 *
 * Returns: (transfer full): The expanded SQL statement which should be freed
 *          by calling [func@free].
 *
 * Since: 0.3
 */
SEAGULL_AVAILABLE_IN_0_3
char *seagull_statement_get_expanded_sql(SeagullStatement *statement);

/**
 * seagull_statement_get_sql:
 *
 * Gets the SQL statement.
 *
 * Returns: (transfer none): The SQL statement.
 *
 * Since: 0.3
 */
SEAGULL_AVAILABLE_IN_0_3
const char *seagull_statement_get_sql(SeagullStatement *statement);

/**
 * seagull_statement_get_stmt:
 *
 * Gets the underlying SQLite3 statement.
 *
 * Returns: (transfer none): The statement.
 *
 * Since: 0.3
 */
SEAGULL_AVAILABLE_IN_0_3
SeagullSqlite3Stmt *seagull_statement_get_stmt(SeagullStatement *statement);

/**
 * seagull_statement_new:
 * @db: the database instance
 * @sql: the SQL statement
 * @error: (out) (nullable): a return address for a #GError
 *
 * Creates a new prepared statement.
 *
 * Returns: (transfer full): The new instance.
 *
 * Since: 0.3
 */
SEAGULL_AVAILABLE_IN_0_3
SeagullStatement *seagull_statement_new(SeagullSqlite3 *db, const char *sql, GError **error);

/**
 * seagull_statement_new_from_resource:
 * @db: the database instance
 * @path: the base path of the resource to use
 * @error: (out) (nullable): a return address for a #GError
 *
 * Creates a new prepared statement from a resource.
 *
 * Returns: (transfer full): The new instance.
 *
 * Since: 0.4
 */
SEAGULL_AVAILABLE_IN_0_4
SeagullStatement *seagull_statement_new_from_resource(SeagullSqlite3 *db, const char *path, GError **error);

/**
 * seagull_statement_reset:
 * @error: (out) (nullable): a return address for a #GError
 *
 * Resets the statement to its initial state.
 *
 * This does not clear any bindings, use [method@Statement.clear_bindings] to
 * do that.
 *
 * Returns: true on success; other false with @error set.
 *
 * Since: 0.3
 */
SEAGULL_AVAILABLE_IN_0_3
gboolean seagull_statement_reset(SeagullStatement *statement, GError **error);

/**
 * seagull_statement_step:
 * @error: (out) (nullable): a return address for a #GError
 *
 * Evaluates the statement.
 *
 * If there is no data to read, %false will be returned, but @error will not be
 * set.
 *
 * Returns: true if there is data to read.
 *
 * Since: 0.3
 */
SEAGULL_AVAILABLE_IN_0_3
gboolean seagull_statement_step(SeagullStatement *statement, GError **error);

G_END_DECLS

#endif /* SEAGULL_STATEMENT_H */
