npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@amsom-habitat/nest-oracle

v2.0.0

Published

Oracle pour NestJS : pool Knex tracé, vues typées, fonctions stockées (binds natifs, CLOB/BLOB, contrat { data }), erreurs ORA- → HTTP.

Readme

@amsom-habitat/nest-oracle

Oracle pour NestJS : un pool Knex partagé et tracé, la lecture typée des vues, l'appel des fonctions stockées et la traduction des erreurs ORA- en HTTP.

// app.module.ts (global par défaut ; le module initialise le client Oracle et ferme le pool à l'arrêt)
OracleModule.forRoot();

// lecture
const VIEW = view('AHVWS_CALLY_X', { schema: { booleans: ['EST_ACTIF'] }, keys });
constructor(@InjectKnex() private readonly db: Knex) {}
return VIEW.rows(await this.db(VIEW.name).select('*'));

// écriture
const { data } = await this.oracle.callFunction<Suivi>('AHWS_X', [id, pec]);
await this.oracle.callFunction('AHWS_MAIL', [id], { returns: 'clob' });

Options (forRoot / forRootAsync)

Validées au démarrage : une valeur invalide ou manquante arrête l'application avec un message explicite.

| Option | Défaut | |---|---| | connection.{user,password,connectString} | ORACLE_USER, ORACLE_PASSWORD, ORACLE_CONNECT_STRING (obligatoires) | | pool.min / pool.max | ORACLE_POOL_MIN (2) / ORACLE_POOL_MAX (10) | | pool.acquireTimeoutMs | 60 000 | | client.mode | 'thick' (échec bloquant) ; 'thin' n'initialise rien | | client.libDir | ORACLE_CLIENT_LIB_DIR, sinon /opt/oracle/instantclient | | functions.maxOutputBytes | 32 767 (plafond d'un VARCHAR2 PL/SQL) | | functions.callTimeoutMs | aucun | | functions.mapError | oracleErrorToHttpException | | tracing.includeBindings | false (les valeurs bindées ne partent pas dans les traces) | | tracing.maxBindingsLength | 2 000 | | isGlobal | true |

Fonctions stockées : le contrat { data }

callFunction(name, params, { returns }) exécute BEGIN :result := name(:p0, …); END; en autoCommit : toute atomicité se fait en PL/SQL, dans une seule fonction. Le nom est validé comme identifiant Oracle, les paramètres sont bindés (jamais concaténés) :

  • boolean → 1/0, undefined → null, Date en natif ;
  • Buffer ou { type: 'blob', value } → BLOB, { type: 'clob', value } → CLOB ;
  • tout autre objet est refusé (OracleDriverError) au lieu d'être écrit en [object Object] : un tableau ou un objet passe par toJsonParam(valeur) (JSON ; absent, {} et [] → NULL).

C'est la seule normalisation des valeurs envoyées à Oracle : le corps d'une requête reste brut jusque-là. Inutile de convertir null en '' : Oracle ne distingue pas la chaîne vide de NULL.

Le retour est un succès si et seulement si le JSON rendu porte une clé data. Sinon, OracleCallError (payload : corps parsé ou texte, raw : texte brut). Un échec du driver, y compris pour emprunter une connexion, lève OracleDriverError (cause : l'erreur d'origine). Les deux passent par mapError.

Un retour de plus de maxOutputBytes octets est signalé comme tel (500), sans être confondu avec un paramètre invalide : appeler avec { returns: 'clob' }.

Erreurs ORA- → HTTP

oracleErrorToHttp(err) (aussi utilisé par le filtre d'exceptions du socle) :

| Code | HTTP | Message | |---|---|---| | ORA-20000 à ORA-20999 (RAISE_APPLICATION_ERROR) | 400 | message métier, première ligne | | ORA-00001 (unicité) | 409 | message Oracle | | 1722, 1858, 1843, 1400, 1407, 6502, 12899 | 400 | Paramètre invalide | | autre ORA- | 500 | Erreur interne du serveur | | pas de code ORA- | null | à traiter par l'appelant |

oracleErrorToHttpException (le mapError par défaut) : OracleCallError → OracleCallException, 400 dont le filtre de nest-socle renvoie le texte de la fonction tel quel ({"error": …}, ce que lisent les fronts) ; OracleDriverError → le statut ci-dessus, 500 à défaut.

Typage des vues

view(name, { schema, keys }) déclare une vue (le pendant de l'entité Doctrine v1) et l'inscrit dans declaredViews(), avec le fichier qui la déclare (origin, lu par /coverage).

  • row(r) : clés camelCase (columnToKey : ID_CONTRAT → idContrat), ou la table keys (colonne → clé, ordonnée), qui écarte aussi les colonnes non listées ;
  • rows(rs) : idem, puis dédoublonnage par id (première occurrence), comme l'identity map de Doctrine.

Le schema liste des noms de colonnes Oracle bruts ; une colonne déclarée dans deux listes est une erreur de déclaration.

| Liste | Conversion (parité PHP/Doctrine) | |---|---| | booleans | (bool) : '' et '0' faux, le reste vrai, null conservé | | integers | (int) : préfixe numérique ('12abc' → 12, '1e3' → 1000, 'abc' → 0) | | decimals | floatval après '.' → '' et ',' → '.' : '1.234,56' → 1234.56, mais '12.5' → 125 | | stringOrNumbers | is_numeric ? nombre : chaîne | | strings | chaîne | | json | JSON décodé, null si illisible | | jsonOmittedIfNull | comme json, mais la clé est omise si null (propriété v1 array non nullable) |

Écriture : toOracleColumnValue(schema, column, value) applique la conversion inverse (booléen → 0/1, JSON sérialisé, (int) PHP).

Fragments SQL (identifiants validés) : formattedDate(db, column, format = ORACLE_DATE_FORMAT) (TO_CHAR, DD/MM/RR comme oci8), unixTimestamp(db, column) (AH_TIMESTAMP, fonction maison), unaccentSql(column) (TRANSLATE sans accents), et removeAccents(text) côté JS.

@amsom-habitat/nest-oracle/casing expose columnToKey sans dépendance Nest ni Knex (générateur).

Migration 1.x → 2.0

| 1.x | 2.0 | |---|---| | initialiserClientOracle() dans main.ts | supprimé : OracleModule initialise le client (client) | | OracleModule.forRoot({ connexion, pool, mapError }) | forRoot({ connection, pool, functions: { mapError } }) | | OracleClobService.callFunction(n, p) | OracleService.callFunction(n, p, { returns: 'clob' }) | | callFunction(n, p): Promise<unknown> | callFunction<T>(n, p?, options?): Promise<{ data: T }> | | vue(nom, { typage, cles }) / Vue | view(name, { schema, keys }) / OracleView | | .ligne() / .lignes() / .nom / .typage / .origine | .row() / .rows() / .name / .schema / .origin | | Ligne, Cles | Row (Record<string, unknown>), KeyMap | | vuesDeclarees() | declaredViews() | | dateFormatee, dateTimestamp | formattedDate, unixTimestamp | | oracleUnaccent | unaccentSql | | FORMAT_DATE_ORACLE | ORACLE_DATE_FORMAT | | toCamel(row) | columnToKey(column) (aussi via /casing) | | versOracle (nest-rest) | toOracleColumnValue | | omitNullJson(row, champs) | inchangé, ou schema.jsonOmittedIfNull | | KnexModule, KNEX_TOKEN, creerKnex, tracerKnex, OracleFunctionCalling, fromOraclePool, fromKnex, ConnectionProvider, LoggerLike, mapRows, mapRowsCles, toCles, dedupById, toOracleJson, oracleValue, toOracleScalar, cleanOraMessage | retirés de l'API publique |