<?php
namespace nur\m;

use nur\m\base\QueryException;

/**
 * Interface IQuery: une requête vers une base de données
 *
 * c'est aussi une instance de {@link IRowIterator} permettant de faciliter le
 * parcours du résultat.
 */
interface IQuery extends IRowIterator {
  /** mettre à jour l'incarnation courante */
  function setIncarnation(IRowIncarnation $incarnation): IQuery;

  #############################################################################

  /**
   * commencer une requête de sélection de lignes. les éventuelles précédentes
   * requêtes et bindings sont effacés
   */
  function select(?string $sql=null, ?array $filter=null): IQuery;

  /**
   * commencer une requête de modification de lignes. les éventuelles
   * précédentes requêtes et bindings sont effacés
   */
  function update(?string $sql=null, ?array $filter=null, $row=null, ?array &$results=null): IQuery;

  /**
   * commencer une requête de création de nouvelles lignes. les éventuelles
   * précédentes requêtes et bindings sont effacés
   */
  function insert(?string $sql=null, $row=null, ?array &$results=null): IQuery;

  /**
   * exécuter la requête qui a été construite, et retourner un itérateur sur le
   * résultat:
   * - une requête de type select retourne une liste de lignes
   * - une requête de type update retourne une liste de tableaux ["num_rows"]
   * - une requête de type insert retourne une liste de tableaux ["insert_id"]
   *
   * puis, si la requête est de type {@link insert()} et {@link update()} alors
   * $commit indique s'il faut valider la transaction après avoir exécuté la
   * requête
   */
  function execute(bool $commit=false): IRowIterator;

  /**
   * exécuter la requête qui a été construite, et retourner un itérateur sur le
   * résultat:
   * - une requête de type select retourne une liste de lignes
   * - une requête de type update retourne une liste de tableaux ["num_rows"]
   * - une requête de type insert retourne une liste de tableaux ["insert_id"]
   *
   * si $filter, $row ou $results ne sont pas null, les bindings sont mis à jour
   * avant que la requête soit lancée. ils doivent avoir exactement la même
   * structure que les bindings qui ont été utilisés pour construire la requête.
   */
  function execute2(?array $filter=null, $row=null, ?array &$results=null): IRowIterator;

  /** XXX faire la recherche, retourner true s'il y a un unique résultat */
  function search(?array $filter): bool;
  /** XXX retourner l'unique résultat de la méthode search() */
  function getRow();

  /**
   * Démarrer une transaction si nécessaire. Si on est dans une transaction,
   * cette méthode est un NOP.
   *
   * En principe, une transaction est automatiquement démarrée quand c'est
   * nécessaire, cette méthode ne sera donc généralement utile que dans des cas
   * particuliers (comme par exemple un SELECT qui verrouille des lignes)
   *
   * @throws QueryException
   */
  function beginTransaction(): IQuery;

  /** valider la transaction */
  function commit(): IQuery;

  /** annuler la transaction */
  function rollback(): IQuery;
}