Skip to content

Commit

Permalink
Improve performance more by computing array size
Browse files Browse the repository at this point in the history
  • Loading branch information
blakeembrey committed May 23, 2020
1 parent 399a28c commit 3e54e0d
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 53 deletions.
24 changes: 24 additions & 0 deletions benchmarks/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import sql, { Sql } from "../src/index";
import bytes from "bytes";

const before = process.memoryUsage();
console.log(`before: ${bytes(before.heapUsed)} / ${bytes(before.heapTotal)}`);
const start = process.hrtime();

const queries: Sql[] = [];

for (let i = 0; i < 1_000_000; i++) {
const subQuery = `something ${"goes"} here and ${"there"}`;
const query = sql`this is ${"the"} query: ${i}, ${subQuery}`;
queries.push(query);

// Compute properties for perf testing.
query.text;
query.values;
}

const end = process.hrtime(start);
const after = process.memoryUsage();
console.log(`after: ${bytes(after.heapUsed)} / ${bytes(after.heapTotal)}`);
console.log(`difference: ${bytes(after.heapUsed - before.heapUsed)}`);
console.log(`time: ${end[0]}s ${~~(end[1] / 1000000)}ms`);
37 changes: 37 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"dist/"
],
"scripts": {
"benchmark": "ts-node benchmarks/index.ts",
"prettier": "prettier --write",
"lint": "tslint \"src/**/*.ts\" --project tsconfig.json",
"format": "npm run prettier -- README.md \"{.,src/**/}*.{js,jsx,json,ts,tsx,css,md,yml,yaml}\"",
Expand Down Expand Up @@ -76,14 +77,17 @@
"node": ">=6"
},
"devDependencies": {
"@types/bytes": "^3.1.0",
"@types/jest": "^25.2.3",
"@types/node": "^14.0.5",
"bytes": "^3.1.0",
"husky": "^4.2.5",
"jest": "^26.0.1",
"lint-staged": "^10.2.6",
"prettier": "^2.0.5",
"rimraf": "^3.0.0",
"ts-jest": "^26.0.0",
"ts-node": "^8.10.1",
"tslint": "^6.1.2",
"tslint-config-prettier": "^1.18.0",
"tslint-config-standard": "^9.0.0",
Expand Down
2 changes: 1 addition & 1 deletion src/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ describe("sql template tag", () => {

for (const key in query) keys.push(key);

expect(keys).toEqual(["rawStrings", "rawValues", "values", "text", "sql"]);
expect(keys).toEqual(["values", "strings", "text", "sql"]);
});

describe("join", () => {
Expand Down
84 changes: 33 additions & 51 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ export type RawValue = Value | Sql;
* A SQL instance can be nested within each other to build SQL strings.
*/
export class Sql {
private rawStrings: Array<string>;
private rawValues: Array<RawValue>;
values: Value[];
strings: string[];

constructor(
rawStrings: ReadonlyArray<string>,
rawValues: ReadonlyArray<RawValue>
Expand All @@ -25,65 +26,47 @@ export class Sql {
);
}

this.rawStrings = [];
this.rawValues = [];
let valuesLength = rawValues.length;
let stringsLength = rawStrings.length;

if (rawValues.length === 0) {
this.rawStrings = rawStrings.slice(0);
return;
for (const child of rawValues) {
if (child instanceof Sql) {
valuesLength += child.values.length - 1;
stringsLength += child.strings.length - 2;
}
}

this.rawStrings.length = rawStrings.length;

if (rawValues.length) {
this.rawValues.length = rawValues.length;
this.values = new Array(valuesLength);
this.strings = new Array(stringsLength);

for (let child of rawValues) {
if (child instanceof Sql) {
this.rawStrings.length += child.strings.length;
this.rawValues.length += child.values.length - 1;
}
}
}
this.rawStrings[0] = rawStrings[0];
this.strings[0] = rawStrings[0];

let i = 1;
let strIn = 1;
for (; i < rawStrings.length; ++i) {
const rawString = rawStrings[i];
const child = rawValues[i - 1];
// Iterate over raw values, strings, and children. The value is always
// positioned between two strings, e.g. `index + 1`.
let index = 1;
let position = 0;
while (index < rawStrings.length) {
const child = rawValues[index - 1];
const rawString = rawStrings[index++];

// check for type
// Check for nested `sql` queries.
if (child instanceof Sql) {
const len = child.values.length;
// concat beginning
this.rawStrings[strIn - 1] += child.strings[0];

for (let d = 0; d < len; ++d) {
this.rawStrings[strIn] = child.strings[d + 1];
this.rawValues[strIn - 1] = child.values[d];
strIn++;
// Append child prefix text to current string.
this.strings[position] += child.strings[0];

let childIndex = 0;
while (childIndex < child.values.length) {
this.values[position++] = child.values[childIndex++];
this.strings[position] = child.strings[childIndex];
}

// set current
this.rawStrings[strIn - 1] += rawString;
// Append raw string to current string.
this.strings[position] += rawString;
} else {
this.rawStrings[strIn] = rawString;
this.rawValues[strIn - 1] = child;
++strIn;
this.values[position++] = child;
this.strings[position] = rawString;
}
}

this.rawStrings.length = strIn;
this.rawValues.length = strIn - 1;
}

get values(): Value[] {
return this.rawValues;
}

get strings(): string[] {
return this.rawStrings;
}

get text() {
Expand All @@ -106,9 +89,8 @@ export class Sql {
}

// Work around MySQL enumerable keys in issue #2.
Object.defineProperty(Sql.prototype, "text", { enumerable: true });
Object.defineProperty(Sql.prototype, "values", { enumerable: true });
Object.defineProperty(Sql.prototype, "sql", { enumerable: true });
Object.defineProperty(Sql.prototype, "text", { enumerable: true });

/**
* Create a SQL query for a list of values.
Expand Down
4 changes: 3 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
"declaration": true,
"sourceMap": true,
"inlineSources": true,
"esModuleInterop": true,
"experimentalDecorators": true
}
},
"include": ["src/**/*"]
}

0 comments on commit 3e54e0d

Please sign in to comment.