diff --git a/.gitignore b/.gitignore index 40ff672..1a43e8e 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,9 @@ dist node_modules tmp.db +test/generated +test/pg/port.json +test/mysql/port.json src/generated/mysql src/generated/pg diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..6ae84e7 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,39 @@ +version: '3.8' + +services: + drizzle-plus-postgres: + image: postgres:18beta1 + environment: + POSTGRES_USER: user + POSTGRES_PASSWORD: password + POSTGRES_DB: testdb + ports: + - '0:5432' + healthcheck: + test: ['CMD-SHELL', 'pg_isready -U user -d testdb'] + interval: 5s + timeout: 5s + retries: 5 + + drizzle-plus-mysql: + image: mysql:9 + environment: + MYSQL_ROOT_PASSWORD: password + MYSQL_DATABASE: testdb + ports: + - '0:3306' + healthcheck: + test: + [ + 'CMD', + 'mysqladmin', + 'ping', + '-h', + 'localhost', + '-u', + 'root', + '-ppassword', + ] + interval: 5s + timeout: 5s + retries: 5 diff --git a/test/findManyAndCount.test.ts b/test/findManyAndCount.test.ts index 035ae93..b3a14e1 100644 --- a/test/findManyAndCount.test.ts +++ b/test/findManyAndCount.test.ts @@ -1,18 +1,7 @@ import 'drizzle-plus/sqlite/findManyAndCount' import { db } from './config/client' -import { user } from './config/schema' - -describe('findManyAndCount', () => { - beforeAll(async () => { - await db.insert(user).values([ - { id: 1, name: 'Alice', age: 25 }, - { id: 2, name: 'Bob', age: 30 }, - { id: 3, name: 'Charlie', age: 35 }, - { id: 4, name: 'Diana', age: 28 }, - { id: 5, name: 'Eve', age: 22 }, - ]) - }) +describe('findManyAndCount (SQL)', () => { test('SQL output', () => { const query = db.query.user.findManyAndCount() @@ -58,126 +47,4 @@ describe('findManyAndCount', () => { } `) }) - - test('returns data and count without filters', async () => { - const result = await db.query.user.findManyAndCount({ - columns: { name: true, age: true }, - }) - expect(result).toMatchInlineSnapshot(` - { - "count": 5, - "data": [ - { - "age": 25, - "name": "Alice", - }, - { - "age": 30, - "name": "Bob", - }, - { - "age": 35, - "name": "Charlie", - }, - { - "age": 28, - "name": "Diana", - }, - { - "age": 22, - "name": "Eve", - }, - ], - } - `) - }) - - test('returns data and count with filters', async () => { - const result = await db.query.user.findManyAndCount({ - columns: { name: true, age: true }, - where: { - age: { gte: 30 }, - }, - }) - expect(result).toMatchInlineSnapshot(` - { - "count": 2, - "data": [ - { - "age": 30, - "name": "Bob", - }, - { - "age": 35, - "name": "Charlie", - }, - ], - } - `) - }) - - test('returns data and count with limit', async () => { - const result = await db.query.user.findManyAndCount({ - columns: { name: true, age: true }, - limit: 3, - }) - expect(result).toMatchInlineSnapshot(` - { - "count": 5, - "data": [ - { - "age": 25, - "name": "Alice", - }, - { - "age": 30, - "name": "Bob", - }, - { - "age": 35, - "name": "Charlie", - }, - ], - } - `) - }) - - test('returns data and count with filters and limit', async () => { - const result = await db.query.user.findManyAndCount({ - columns: { name: true, age: true }, - where: { - age: { lte: 30 }, - }, - limit: 2, - }) - expect(result).toMatchInlineSnapshot(` - { - "count": 4, - "data": [ - { - "age": 25, - "name": "Alice", - }, - { - "age": 30, - "name": "Bob", - }, - ], - } - `) - }) - - test('returns empty data but correct count when no results match', async () => { - const result = await db.query.user.findManyAndCount({ - where: { - age: { gt: 100 }, - }, - }) - expect(result).toMatchInlineSnapshot(` - { - "count": 0, - "data": [], - } - `) - }) }) diff --git a/test/integration/findManyAndCount.test.ts b/test/integration/findManyAndCount.test.ts new file mode 100644 index 0000000..ab52af9 --- /dev/null +++ b/test/integration/findManyAndCount.test.ts @@ -0,0 +1,137 @@ +import 'drizzle-plus/sqlite/findManyAndCount' +import { db } from '../config/client' +import { user } from '../config/schema' + +describe('findManyAndCount (Integration)', () => { + beforeAll(async () => { + await db.insert(user).values([ + { id: 1, name: 'Alice', age: 25 }, + { id: 2, name: 'Bob', age: 30 }, + { id: 3, name: 'Charlie', age: 35 }, + { id: 4, name: 'Diana', age: 28 }, + { id: 5, name: 'Eve', age: 22 }, + ]) + }) + + test('returns data and count without filters', async () => { + const result = await db.query.user.findManyAndCount({ + columns: { name: true, age: true }, + }) + expect(result).toMatchInlineSnapshot(` + { + "count": 5, + "data": [ + { + "age": 25, + "name": "Alice", + }, + { + "age": 30, + "name": "Bob", + }, + { + "age": 35, + "name": "Charlie", + }, + { + "age": 28, + "name": "Diana", + }, + { + "age": 22, + "name": "Eve", + }, + ], + } + `) + }) + + test('returns data and count with filters', async () => { + const result = await db.query.user.findManyAndCount({ + columns: { name: true, age: true }, + where: { + age: { gte: 30 }, + }, + }) + expect(result).toMatchInlineSnapshot(` + { + "count": 2, + "data": [ + { + "age": 30, + "name": "Bob", + }, + { + "age": 35, + "name": "Charlie", + }, + ], + } + `) + }) + + test('returns data and count with limit', async () => { + const result = await db.query.user.findManyAndCount({ + columns: { name: true, age: true }, + limit: 3, + }) + expect(result).toMatchInlineSnapshot(` + { + "count": 5, + "data": [ + { + "age": 25, + "name": "Alice", + }, + { + "age": 30, + "name": "Bob", + }, + { + "age": 35, + "name": "Charlie", + }, + ], + } + `) + }) + + test('returns data and count with filters and limit', async () => { + const result = await db.query.user.findManyAndCount({ + columns: { name: true, age: true }, + where: { + age: { lte: 30 }, + }, + limit: 2, + }) + expect(result).toMatchInlineSnapshot(` + { + "count": 4, + "data": [ + { + "age": 25, + "name": "Alice", + }, + { + "age": 30, + "name": "Bob", + }, + ], + } + `) + }) + + test('returns empty data but correct count when no results match', async () => { + const result = await db.query.user.findManyAndCount({ + where: { + age: { gt: 100 }, + }, + }) + expect(result).toMatchInlineSnapshot(` + { + "count": 0, + "data": [], + } + `) + }) +}) diff --git a/test/mysql/globalSetup.ts b/test/mysql/globalSetup.ts new file mode 100644 index 0000000..a32b3f3 --- /dev/null +++ b/test/mysql/globalSetup.ts @@ -0,0 +1,34 @@ +import { execSync } from 'child_process' +import fs from 'fs' +import path from 'path' + +const outputFilePath = path.resolve(__dirname, './port.json') + +export async function setup() { + const ports: { mysql?: number } = {} + try { + const mysqlPortOutput = execSync( + 'docker compose port drizzle-plus-mysql 3306', + { encoding: 'utf8' } + ).trim() + if (mysqlPortOutput) { + ports.mysql = parseInt(mysqlPortOutput.split(':')[1], 10) + } + fs.writeFileSync(outputFilePath, JSON.stringify(ports, null, 2), 'utf8') + console.log(`Extracted MySQL port to ${outputFilePath}`) + } catch (e: any) { + console.error( + 'Error extracting MySQL port. Ensure docker compose services are running:', + e.message + ) + process.exit(1) + } +} + +export async function teardown() { + // Clean up the port.json file if it exists + if (fs.existsSync(outputFilePath)) { + fs.unlinkSync(outputFilePath) + console.log(`Cleaned up ${outputFilePath}`) + } +} diff --git a/test/pg/globalSetup.ts b/test/pg/globalSetup.ts new file mode 100644 index 0000000..3799f10 --- /dev/null +++ b/test/pg/globalSetup.ts @@ -0,0 +1,34 @@ +import { execSync } from 'child_process' +import fs from 'fs' +import path from 'path' + +const outputFilePath = path.resolve(__dirname, './port.json') + +export async function setup() { + const ports: { postgres?: number } = {} + try { + const pgPortOutput = execSync( + 'docker compose port drizzle-plus-postgres 5432', + { encoding: 'utf8' } + ).trim() + if (pgPortOutput) { + ports.postgres = parseInt(pgPortOutput.split(':')[1], 10) + } + fs.writeFileSync(outputFilePath, JSON.stringify(ports, null, 2), 'utf8') + console.log(`Extracted PostgreSQL port to ${outputFilePath}`) + } catch (e: any) { + console.error( + 'Error extracting PostgreSQL port. Ensure docker compose services are running:', + e.message + ) + process.exit(1) + } +} + +export async function teardown() { + // Clean up the port.json file if it exists + if (fs.existsSync(outputFilePath)) { + fs.unlinkSync(outputFilePath) + console.log(`Cleaned up ${outputFilePath}`) + } +} diff --git a/vitest.config.ts b/vitest.config.ts index 88160b2..de706bc 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -3,7 +3,11 @@ import { defineConfig } from 'vitest/config' export default defineConfig({ test: { - include: ['test/**/*.test.ts'], + include: [ + 'test/*.test.ts', + 'test/integration/*.test.ts', + 'test/generated/*.test.ts', + ], globals: true, isolate: false, fileParallelism: false,