"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var session_exports = {};
__export(session_exports, {
  NodeMsSqlPreparedQuery: () => NodeMsSqlPreparedQuery,
  NodeMsSqlSession: () => NodeMsSqlSession,
  NodeMsSqlTransaction: () => NodeMsSqlTransaction
});
module.exports = __toCommonJS(session_exports);
var import_mssql = __toESM(require("mssql"), 1);
var import_node_events = require("node:events");
var import_entity = require("../entity.cjs");
var import_logger = require("../logger.cjs");
var import_session = require("../mssql-core/session.cjs");
var import_sql = require("../sql/sql.cjs");
var import_utils = require("../utils.cjs");
var import_pool = require("./pool.cjs");
class NodeMsSqlPreparedQuery extends import_session.PreparedQuery {
  constructor(client, queryString, params, logger, fields, customResultMapper) {
    super();
    this.client = client;
    this.params = params;
    this.logger = logger;
    this.fields = fields;
    this.customResultMapper = customResultMapper;
    this.rawQuery = {
      sql: queryString,
      parameters: params
    };
  }
  static [import_entity.entityKind] = "NodeMsSqlPreparedQuery";
  rawQuery;
  async execute(placeholderValues = {}) {
    const params = (0, import_sql.fillPlaceholders)(this.params, placeholderValues);
    this.logger.logQuery(this.rawQuery.sql, params);
    const {
      fields,
      client,
      rawQuery,
      joinsNotNullableMap,
      customResultMapper
    } = this;
    let queryClient = client;
    if ((0, import_entity.is)(client, import_pool.AutoPool)) {
      queryClient = await client.$instance();
    }
    const request = queryClient.request();
    for (const [index, param] of params.entries()) {
      request.input(`par${index}`, param);
    }
    if (!fields && !customResultMapper) {
      return request.query(rawQuery.sql);
    }
    request.arrayRowMode = true;
    const rows = await request.query(rawQuery.sql);
    if (customResultMapper) {
      return customResultMapper(rows.recordset);
    }
    return rows.recordset.map((row) => (0, import_utils.mapResultRow)(fields, row, joinsNotNullableMap));
  }
  async *iterator(placeholderValues = {}) {
    const params = (0, import_sql.fillPlaceholders)(this.params, placeholderValues);
    const {
      fields,
      rawQuery,
      joinsNotNullableMap,
      client,
      customResultMapper
    } = this;
    let queryClient = client;
    if ((0, import_entity.is)(client, import_pool.AutoPool)) {
      queryClient = await client.$instance();
    }
    const request = queryClient.request();
    request.stream = true;
    const hasRowsMapper = Boolean(fields || customResultMapper);
    if (hasRowsMapper) {
      request.arrayRowMode = true;
    }
    for (const [index, param] of params.entries()) {
      request.input(`par${index}`, param);
    }
    const stream = request.toReadableStream();
    request.query(rawQuery.sql);
    function dataListener() {
      stream.pause();
    }
    stream.on("data", dataListener);
    try {
      const onEnd = (0, import_node_events.once)(stream, "end");
      const onError = (0, import_node_events.once)(stream, "error");
      while (true) {
        stream.resume();
        const row = await Promise.race([
          onEnd,
          onError,
          new Promise((resolve) => stream.once("data", resolve))
        ]);
        if (row === void 0 || Array.isArray(row) && row.length === 0) {
          break;
        } else if (row instanceof Error) {
          throw row;
        } else {
          if (hasRowsMapper) {
            if (customResultMapper) {
              const mappedRow = customResultMapper([row]);
              yield Array.isArray(mappedRow) ? mappedRow[0] : mappedRow;
            } else {
              yield (0, import_utils.mapResultRow)(
                fields,
                row,
                joinsNotNullableMap
              );
            }
          } else {
            yield row;
          }
        }
      }
    } finally {
      stream.off("data", dataListener);
      request.cancel();
    }
  }
}
class NodeMsSqlSession extends import_session.MsSqlSession {
  constructor(client, dialect, schema, options) {
    super(dialect);
    this.client = client;
    this.schema = schema;
    this.options = options;
    this.logger = options.logger ?? new import_logger.NoopLogger();
  }
  static [import_entity.entityKind] = "NodeMsSqlSession";
  logger;
  prepareQuery(query, fields, customResultMapper) {
    return new NodeMsSqlPreparedQuery(
      this.client,
      query.sql,
      query.params,
      this.logger,
      fields,
      customResultMapper
    );
  }
  /**
   * @internal
   * What is its purpose?
   */
  async query(query, params) {
    this.logger.logQuery(query, params);
    let queryClient = this.client;
    if ((0, import_entity.is)(this.client, import_pool.AutoPool)) {
      queryClient = await this.client.$instance();
    }
    const request = queryClient.request();
    request.arrayRowMode = true;
    for (const [index, param] of params.entries()) {
      request.input(`par${index}`, param);
    }
    return request.query(query);
  }
  async all(query) {
    const querySql = this.dialect.sqlToQuery(query);
    this.logger.logQuery(querySql.sql, querySql.params);
    return await this.query(querySql.sql, querySql.params).then(
      (result) => result.recordset
    );
  }
  async transaction(transaction, config) {
    const mssqlTransaction = this.client.transaction();
    const session = new NodeMsSqlSession(
      mssqlTransaction,
      this.dialect,
      this.schema,
      this.options
    );
    const tx = new NodeMsSqlTransaction(
      this.dialect,
      session,
      this.schema,
      0
    );
    await mssqlTransaction.begin(
      config?.isolationLevel ? isolationLevelMap[config.isolationLevel] : void 0
    );
    try {
      const result = await transaction(tx);
      await mssqlTransaction.commit();
      return result;
    } catch (err) {
      await mssqlTransaction.rollback();
      throw err;
    }
  }
}
class NodeMsSqlTransaction extends import_session.MsSqlTransaction {
  static [import_entity.entityKind] = "NodeMsSqlTransaction";
  async transaction(transaction) {
    const savepointName = `sp${this.nestedIndex + 1}`;
    const tx = new NodeMsSqlTransaction(
      this.dialect,
      this.session,
      this.schema,
      this.nestedIndex + 1
    );
    await tx.execute(import_sql.sql.raw(`save transaction ${savepointName}`));
    try {
      const result = await transaction(tx);
      return result;
    } catch (err) {
      await tx.execute(import_sql.sql.raw(`rollback transaction ${savepointName}`));
      throw err;
    }
  }
}
const isolationLevelMap = {
  "read uncommitted": import_mssql.default.ISOLATION_LEVEL.READ_UNCOMMITTED,
  "read committed": import_mssql.default.ISOLATION_LEVEL.READ_COMMITTED,
  "repeatable read": import_mssql.default.ISOLATION_LEVEL.REPEATABLE_READ,
  serializable: import_mssql.default.ISOLATION_LEVEL.SERIALIZABLE,
  snapshot: import_mssql.default.ISOLATION_LEVEL.SNAPSHOT
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  NodeMsSqlPreparedQuery,
  NodeMsSqlSession,
  NodeMsSqlTransaction
});
//# sourceMappingURL=session.cjs.map