Connection¶
Defining the connection object¶
When you define the connection object, you extend your database connection class; that class receives one generic argument with a unique name for the database in your system.
import { PostgreSqlConnection } from "ts-sql-query/connections/PostgreSqlConnection";
class DBConnection extends PostgreSqlConnection<'DBConnection'> { }
Allowing empty string¶
By default empty string as treated as null, if you want to allow sending and receiving empty strings to the database set the allowEmptyString
property in the connection to true.
import { PostgreSqlConnection } from "ts-sql-query/connections/PostgreSqlConnection";
class DBConnection extends PostgreSqlConnection<'DBConnection'> {
allowEmptyString = true
}
Recommendation: Set this flag at the beginning of the project or create a derivated connection if you require to do it. Changing this flag changes the way SQL queries are constructed when you use the methods that the name ends in 'IfValue'.
Insensitive strategies¶
By default, when you specify that you want to perform an insensitive operation (like startsWithInsensitive
) the operation is performed calling the function lower
on the affected parts. But, another way to perform it is changing the collation of the text by one insensitive. If you set the insensitiveCollation in the connection, the provided collate will be used instead of calling the lower
function.
Providing the collation allows you to perform more advanced insensitive operations like case insensitive and accent insensitive, or even more in some languages (like manage some letter composition alternatives). Some databases offer general collations that are case insensitive and accent insensitive. But it is expected you want to use a collation specific to the language used by the user.
import { PostgreSqlConnection } from "ts-sql-query/connections/PostgreSqlConnection";
class DBConnection extends PostgreSqlConnection<'DBConnection'> {
insesitiveCollation = 'insensitive'
}
Useful collations per database:
The following collations are case insensitive and accent insensitive:
- PostgreSQL: Starting from PostgreSQL 12 you can create custom non-deterministic collates from ICU database (previously it was OS dependant) with specific rules.
- For a general collation case insensitive and accent insensitive, you can create the collation with:
CREATE COLLATION insensitive (
provider = 'icu',
locale = 'und@colStrength=primary', -- or 'und-u-ks-level1'
deterministic = false
)
-
- For a collation specific for one language (in this example: Spanish) case insensitive and accent insensitive, you create the collation using:
CREATE COLLATION es_insensitive (
provider = 'icu',
locale = 'es@colStrength=primary', -- or 'es-u-ks-level1'
deterministic = false
)
-
- For more information, visit this blog post
- Execute
SELECT * FROM pg_collation
to list the already created collations
- MySQL/MariaDB:
utf8_general_ci
for utf8 charsetutf16_unicode_ci
for utf16 charsetutf8_spanish_ci
for utf8 charset with spanish rules- Execute
SHOW COLLATION
to list the supported collations in your database; all locations ended with_ci
are case insensitive and accent insensitive.
- SQL Server:
Latin1_General_CI_AI
for a general case insensitive and accent insensitive for Latin alphabet-based languagesModern_Spanish_CI_AI
for a specific case insensitive and accent insensitive for the Spanish language only- Execute
SELECT * FROM sys.fn_helpcollations()
to list the supported collations in your database
- Oracle:
binary_ai
for a general case insensitive and accent insensitive for Latin alphabet-based languagesspanish_m_ai
for a specific case insensitive and accent insensitive extended with the Spanish language rules- To see the collations list visit the Oracle 11g or Oracle 19 documentation webpage
Tip
If you set the startsWithInsensitive
property to an empty string (''), the function lower
will not be called, neither a collated will be specified. It is useful when you already defined the insensitive collate rules at the database level.
Instantiating the connection with the database connection¶
const { Pool } = require('pg');
import { PgPoolQueryRunner } from "ts-sql-query/queryRunners/PgPoolQueryRunner";
const pool = new Pool();
async function main() {
const connection = new DBConnection(new PgPoolQueryRunner(pool));
// Do your queries here
/*
* Maybe you want to perform the queries in a transaction:
* await connection.transaction(async () => {
* // Do your queries here
* })
*
* You also can manage the transaction at low level:
* await connection.beginTransaction();
* await connection.commit();
* await connection.rollback();
*/
}
Do not share connections between requests
A ts-sql-query
connection object — along with the query runner instances passed to its constructor — represents a dedicated connection to the database.
Therefore, you must not share the same connection object between concurrent HTTP requests. Instead, create a new connection object for each request, along with its own query runners.
Even if the query runner internally uses a connection pool, the ts-sql-query
connection still represents a single active connection, acquired from the pool. It must be treated as such and never reused across requests.
Instantiating the connection with a mock database connection¶
Have a mock database connection is useful when you want to make unit tests. Using a mock connection allows you to test your code against the generated query instead of running the query in the database.
import { MockQueryRunner } from "ts-sql-query/queryRunners/MockQueryRunner";
function test('my db test', () => {
const connection = new DBConnection(new MockQueryRunner(
(type, query, params, index) => {
switch (index) {
case 0:
expect(type).toBe('delete');
expect(query).toBe('delete from customer where id = $1');
expect(params).toEqual([10]);
return 1; // Returns the result of the query execution
default:
throw new Error('Unexpected query');
}
}
));
// Do your queries here, example:
const deleteCustomer = connection.deleteFrom(tCustomer)
.where(tCustomer.id.equals(10))
.executeDelete();
return deleteCustomer.then((result) => {
expect(result).toBe(1);
});
});