Skip to content

Commit

Permalink
support multirow-statement (#38)
Browse files Browse the repository at this point in the history
  • Loading branch information
Lupennat committed Dec 24, 2023
1 parent b827b46 commit 80dac79
Show file tree
Hide file tree
Showing 15 changed files with 1,090 additions and 4,519 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:

strategy:
matrix:
node-version: [14.x, 16.x, 18.x]
node-version: [16.x, 18.x]

steps:
- uses: actions/checkout@v3
Expand All @@ -26,7 +26,7 @@ jobs:

- name: npm install, build, and test
run: |
npm install
npm ci
npm run build
npm run test:coverage
env:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: "14.x"
node-version: "16.x"
registry-url: "https://registry.npmjs.org"

- name: Install deps
run: npm install
run: npm ci
env:
CI: true

Expand Down
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@ All notable changes to this project from 1.0.0 forward will be documented in thi
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [3.4.0] - 2023-12-24

### Added

- `PdoStatementI.nextRowset` added, you can advances to the next rowset in a multi-rowset statement handle.

### Changed

- **(DEV)** please ensure your driver is updated for lupdo version 3.4.0,
- **(DEV)** support `pdo-raw-connection` methods `doQuery`, `executeStatement`, `execute`, `query` signature are changed to support multi-rowset statement.

## [3.3.0] - 2023-03-22

### Added
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ Debug mode, is defined through Pdo Attributes, custom debug connection options,
- prototype.getColumnMeta(column: number): ColumnData | null;
- prototype.rowCount(): number;
- prototype.lastInsertId(name?: string): Promise<string | bigint | number | null>;
- prototype.nextRowset(): boolean;

> **Note**
> statement.debug() will return SQL and Params Reflecting user input, statement.debugSent() will return SQL and Params Adapted by the Driver.
Expand Down
5,393 changes: 905 additions & 4,488 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "lupdo",
"version": "3.3.0",
"version": "3.4.0",
"description": "Database Abstraction Layer for Node js",
"author": "Claudio Pennati <claudio.pennati@gmail.com>",
"license": "MIT",
Expand Down Expand Up @@ -41,7 +41,7 @@
"lint:fix": "eslint --fix --ext \".js,.jsx,.ts,.tsx\" \"./src\""
},
"engines": {
"node": "^14.19.0 || ^16.10.0 || >=18.0.0"
"node": "^16.10.0 || >=18.0.0"
},
"devDependencies": {
"@types/jest": "^29.2.4",
Expand Down
24 changes: 24 additions & 0 deletions src/__tests__/fixtures/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,5 +57,29 @@ export default {
{ id: 18, name: 'Beier and Sons', opened: '1999-12-22T00:00:00.000Z', active: 0, binary: null },
{ id: 19, name: 'Harvey Inc', opened: '2022-12-22T00:00:00.000Z', active: 1, binary: null }
]
},
procedure: {
columns: [
[
{ name: 'id', table: 'companies' },
{ name: 'name', table: 'companies' }
],
[
{ name: 'id', table: 'users' },
{ name: 'name', table: 'users' },
{ name: 'gender', table: 'users' }
]
],
data: [
[
[1, 'Satterfield Inc'],
[2, 'Grimes - Reinger'],
[3, 'Skiles LLC']
],
[
[1, 'Edmund', 'Multigender'],
[2, 'Kyleigh', 'Cis man']
]
]
}
};
12 changes: 9 additions & 3 deletions src/__tests__/fixtures/fake-db-connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,13 @@ async function processSql(
threadId: number,
sql: string,
transaction = false
): Promise<[PdoAffectingData, PdoRowData[], PdoColumnData[]]> {
): Promise<[PdoAffectingData, PdoRowData[][] | PdoRowData[], PdoColumnData[][] | PdoColumnData[]]> {
sql = sql.toLowerCase().trim();

if (sql === 'call multiple_rowsets()') {
return [{}, db.procedure.data, db.procedure.columns];
}

if (sql.startsWith('select sleep(60)')) {
sleeps[threadId] = true;
try {
Expand Down Expand Up @@ -518,7 +522,7 @@ export class FakeDBStatement {

public async execute(
params: string[] | string[][] | { [key: string]: string | string[] }
): Promise<[PdoAffectingData, PdoRowData[], PdoColumnData[]]> {
): Promise<[PdoAffectingData, PdoRowData[][] | PdoRowData[], PdoColumnData[][] | PdoColumnData[]]> {
this.logIfDebug('Execute', params);
let sql = this.query;
if (Array.isArray(params)) {
Expand Down Expand Up @@ -584,7 +588,9 @@ class FakeDBConnection {
this.inTransaction = false;
}

public async query(sql: string): Promise<[PdoAffectingData, PdoRowData[], PdoColumnData[]]> {
public async query(
sql: string
): Promise<[PdoAffectingData, PdoRowData[][] | PdoRowData[], PdoColumnData[][] | PdoColumnData[]]> {
this.logIfDebug('query', sql);
return await processSql(this.threadId, sql, this.inTransaction);
}
Expand Down
4 changes: 2 additions & 2 deletions src/__tests__/fixtures/fake-raw-connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class FakeRawConnection extends PdoRawConnection {
protected async executeStatement(
statement: FakeDBStatement,
bindings: string[] | { [key: string]: string }
): Promise<[string, PdoAffectingData, PdoRowData[], PdoColumnData[]]> {
): Promise<[string, PdoAffectingData, PdoRowData[][] | PdoRowData[], PdoColumnData[][] | PdoColumnData[]]> {
return [statement.query, ...(await statement.execute(bindings))];
}

Expand All @@ -51,7 +51,7 @@ class FakeRawConnection extends PdoRawConnection {
protected async doQuery(
connection: FakeDBConnection,
sql: string
): Promise<[PdoAffectingData, PdoRowData[], PdoColumnData[]]> {
): Promise<[PdoAffectingData, PdoRowData[][] | PdoRowData[], PdoColumnData[][] | PdoColumnData[]]> {
return await connection.query(sql);
}

Expand Down
51 changes: 51 additions & 0 deletions src/__tests__/pdo-statement.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,4 +99,55 @@ describe('Pdo Statement', () => {
stmt.resetCursor();
expect(fetch.get()).toEqual([5, 'Sincere', 'Demi-girl']);
});

it('Works nextRowset return false when not rowset', async () => {
const stmt = await pdo.query('SELECT * FROM users limit 5;');
expect(stmt.nextRowset()).toBeFalsy();
});

it('Works nextRowset return type when rowset', async () => {
const stmt = await pdo.query('CALL multiple_rowsets()');
expect(stmt.nextRowset()).toBeTruthy();
expect(stmt.nextRowset()).toBeFalsy();
});

it('Works fetch multiple rowset', async () => {
const stmt = await pdo.query('CALL multiple_rowsets()');
let i = 0;
do {
expect(stmt.columnCount()).toBe(i === 0 ? 2 : 3);
expect(stmt.getColumnMeta(0)).toEqual({
name: 'id',
table: i === 0 ? 'companies' : 'users'
});
expect(stmt.getColumnMeta(1)).toEqual({
name: 'name',
table: i === 0 ? 'companies' : 'users'
});
if (i === 0) {
expect(stmt.getColumnMeta(2)).toBeNull();
} else {
expect(stmt.getColumnMeta(2)).toEqual({
name: 'gender',
table: 'users'
});
}

expect(stmt.fetchArray().all()).toEqual(
i === 0
? [
[1, 'Satterfield Inc'],
[2, 'Grimes - Reinger'],
[3, 'Skiles LLC']
]
: [
[1, 'Edmund', 'Multigender'],
[2, 'Kyleigh', 'Cis man']
]
);
i++;
} while (stmt.nextRowset());

expect(i).toBe(2);
});
});
10 changes: 6 additions & 4 deletions src/support/pdo-raw-connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ abstract class PdoRawConnection implements PdoRawConnectionI {
protected abstract doQuery(
connection: PoolConnection,
sql: string
): Promise<[PdoAffectingData, PdoRowData[], PdoColumnData[]]>;
): Promise<[PdoAffectingData, PdoRowData[][] | PdoRowData[], PdoColumnData[][] | PdoColumnData[]]>;

protected abstract doExec(connection: PoolConnection, sql: string): Promise<PdoAffectingData>;

Expand All @@ -32,7 +32,7 @@ abstract class PdoRawConnection implements PdoRawConnectionI {
statement: any,
bindings: Params,
connection: PoolConnection
): Promise<[string, PdoAffectingData, PdoRowData[], PdoColumnData[]]>;
): Promise<[string, PdoAffectingData, PdoRowData[][] | PdoRowData[], PdoColumnData[][] | PdoColumnData[]]>;
protected abstract closeStatement(statement: any, connection: PoolConnection): Promise<void>;

protected abstract adaptBindValue(value: ValidBindingsSingle): ValidBindingsSingle;
Expand Down Expand Up @@ -92,7 +92,7 @@ abstract class PdoRawConnection implements PdoRawConnectionI {
public async execute(
sql: string,
params: Params | null
): Promise<[string, PdoAffectingData, PdoRowData[], PdoColumnData[]]> {
): Promise<[string, PdoAffectingData, PdoRowData[][] | PdoRowData[], PdoColumnData[][] | PdoColumnData[]]> {
try {
const connection = await this.generateOrReuseConnection();

Expand Down Expand Up @@ -135,7 +135,9 @@ abstract class PdoRawConnection implements PdoRawConnectionI {
}
}

public async query(sql: string): Promise<[PdoAffectingData, PdoRowData[], PdoColumnData[]]> {
public async query(
sql: string
): Promise<[PdoAffectingData, PdoRowData[][] | PdoRowData[], PdoColumnData[][] | PdoColumnData[]]> {
try {
const connection = await this.generateOrReuseConnection();
const [affectingResults, selectResults, columns] = await this.doQuery(connection, sql);
Expand Down
73 changes: 61 additions & 12 deletions src/support/pdo-statement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,31 @@ class PdoStatement implements PdoStatementI {
protected rawParams: Params | null = null;
protected params: Params | null = null;
protected cursor: number | null = null;
protected rowset = 0;
protected isRowset = false;
protected currentSelectResults: PdoRowData[] = [];
protected currentColumns: PdoColumnData[] = [];
protected selectResults: PdoRowData[] | PdoRowData[][];
protected columns: PdoColumnData[] | PdoColumnData[][];

constructor(
protected readonly connection: PdoRawConnectionI,
protected readonly rawSql: string,
protected affectingResults: PdoAffectingData,
protected selectResults: PdoRowData[],
protected columns: PdoColumnData[]
selectResults: PdoRowData[] | PdoRowData[][],
columns: PdoColumnData[] | PdoColumnData[][]
) {
this.sql = this.rawSql;
this.columns = columns;
this.selectResults = selectResults;
this.resetRowset();
this.resetCursor();
this.setCurrentColumns();
this.setCurrentSelectResults();
}

public columnCount(): number {
return this.columns.length;
return this.currentColumns.length;
}

public debug(): string {
Expand All @@ -48,7 +60,7 @@ class PdoStatement implements PdoStatementI {
}

public getColumnMeta(column: number): PdoColumnData | null {
return this.columns.length > column ? this.columns[column] : null;
return this.currentColumns.length > column ? this.currentColumns[column] : null;
}

public rowCount(): number {
Expand All @@ -60,7 +72,11 @@ class PdoStatement implements PdoStatementI {

public async lastInsertId(name?: string): Promise<string | bigint | number | null> {
return await this.connection.lastInsertId(
{ affectingResults: this.affectingResults, selectResults: this.selectResults, columns: this.columns },
{
affectingResults: this.affectingResults,
selectResults: this.currentSelectResults,
columns: this.currentColumns
},
name
);
}
Expand Down Expand Up @@ -273,7 +289,7 @@ class PdoStatement implements PdoStatementI {

protected getCasedColumnsName(): string[] {
const columnCase = this.getAttribute(ATTR_CASE) as number;
return this.columns.map(column => {
return this.currentColumns.map(column => {
return (columnCase & CASE_NATURAL) !== 0
? column.name
: (columnCase & CASE_LOWER) !== 0
Expand Down Expand Up @@ -320,27 +336,27 @@ class PdoStatement implements PdoStatementI {

this.setCursor(cursor);

return this.selectResults[cursor];
return this.currentSelectResults[cursor];
}

protected fetchAll(): PdoRowData[] {
const cursorOrientation = this.getAttribute(ATTR_FETCH_DIRECTION) as number;
const cursor = this.getTempCursorForFetch(cursorOrientation);
if (cursorOrientation === FETCH_BACKWARD) {
this.setCursorToStart();
return this.selectResults.slice(0, cursor + 1).reverse();
return this.currentSelectResults.slice(0, cursor + 1).reverse();
}

this.setCursorToEnd();
return this.selectResults.slice(cursor);
return this.currentSelectResults.slice(cursor);
}

protected setCursor(cursor: number | null): void {
this.cursor = cursor;
}

protected setCursorToEnd(): void {
this.setCursor(this.selectResults.length);
this.setCursor(this.currentSelectResults.length);
}

protected setCursorToStart(): void {
Expand All @@ -350,14 +366,47 @@ class PdoStatement implements PdoStatementI {
protected getTempCursorForFetch(cursorOrientation: number): number {
let cursor = this.cursor;
if (cursor === null) {
cursor = cursorOrientation === FETCH_BACKWARD ? this.selectResults.length : -1;
cursor = cursorOrientation === FETCH_BACKWARD ? this.currentSelectResults.length : -1;
}

return cursorOrientation === FETCH_BACKWARD ? cursor - 1 : cursor + 1;
}

protected isValidCursor(cursor: number, cursorOrientation: number): boolean {
return cursorOrientation === FETCH_BACKWARD ? cursor > -1 : cursor < this.selectResults.length;
return cursorOrientation === FETCH_BACKWARD ? cursor > -1 : cursor < this.currentSelectResults.length;
}

protected resetRowset(): void {
this.rowset = 0;
this.isRowset = Array.isArray(this.columns[0]);
}

protected setCurrentColumns(): void {
this.currentColumns = this.isRowset
? (this.columns as PdoColumnData[][])[this.rowset]
: (this.columns as PdoColumnData[]);
}

protected setCurrentSelectResults(): void {
this.currentSelectResults = this.isRowset
? (this.selectResults as PdoRowData[][])[this.rowset]
: (this.selectResults as PdoRowData[]);
}

public nextRowset(): boolean {
if (!this.isRowset) {
return false;
} else {
if (this.selectResults.length > this.rowset + 1) {
this.rowset++;
this.resetCursor();
this.setCurrentColumns();
this.setCurrentSelectResults();

return true;
}
return false;
}
}
}

Expand Down
Loading

0 comments on commit 80dac79

Please sign in to comment.