Skip to content

Commit 47f1c0b

Browse files
committed
Cache block objects when used for minor performance boost
Signed-off-by: worksofliam <[email protected]>
1 parent 7e51583 commit 47f1c0b

File tree

1 file changed

+45
-54
lines changed

1 file changed

+45
-54
lines changed

src/language/sql/statement.ts

Lines changed: 45 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import Tokenizer from "sql-formatter/lib/src/lexer/Tokenizer";
12
import SQLTokeniser, { NameTypes } from "./tokens";
23
import { CTEReference, CallableReference, ClauseType, ClauseTypeWord, IRange, ObjectRef, QualifiedObject, StatementType, StatementTypeWord, Token } from "./types";
34

@@ -8,6 +9,15 @@ const tokenIs = (token: Token|undefined, type: string, value?: string) => {
89
export default class Statement {
910
public type: StatementType = StatementType.Unknown;
1011
private label: string|undefined;
12+
private _blockTokens: Token[]|undefined;
13+
14+
private get blockTokens() {
15+
if (!this._blockTokens) {
16+
this._blockTokens = SQLTokeniser.createBlocks(this.tokens.slice(0));
17+
}
18+
19+
return this._blockTokens;
20+
}
1121

1222
constructor(public tokens: Token[], public range: IRange) {
1323
this.tokens = this.tokens.filter(newToken => newToken.type !== `newline`);
@@ -101,62 +111,34 @@ export default class Statement {
101111
return currentClause;
102112
}
103113

104-
getBlockRangeAt(offset: number) {
105-
let start = -1;
106-
let end = -1;
107-
108-
// Get the current token for the provided offset
109-
let i = this.tokens.findIndex((token, i) => (offset >= token.range.start && offset <= token.range.end) || (offset > token.range.end && this.tokens[i+1] && offset < this.tokens[i+1].range.start));
110-
111-
let depth = 0;
112-
113-
if (tokenIs(this.tokens[i], `closebracket`)) {
114-
i--;
115-
}
116-
117-
if (tokenIs(this.tokens[i], `openbracket`)) {
118-
start = i+1;
119-
i++;
120-
} else {
121-
for (let x = i; x >= 0; x--) {
122-
if (tokenIs(this.tokens[x], `openbracket`)) {
123-
if (depth === 0) {
124-
start = x+1;
125-
break;
114+
getBlockRangeAt(offset: number): IRange|undefined {
115+
const blockContainsOffset = (cOffset: number, block: Token[]): IRange|undefined => {
116+
const tokenInOffset = block.find(token => cOffset >= token.range.start && cOffset <= token.range.end);
117+
if (tokenInOffset) {
118+
if (tokenInOffset.type === `block`) {
119+
if (tokenInOffset.block!.length > 0) {
120+
return blockContainsOffset(cOffset, tokenInOffset.block!);
126121
} else {
127-
depth--;
122+
const rawEnd = this.tokens.findIndex(token => token.range.end === tokenInOffset.range.end);
123+
return {
124+
start: rawEnd,
125+
end: rawEnd
126+
}
128127
}
129-
} else
130-
if (tokenIs(this.tokens[x], `closebracket`)) {
131-
depth++;
132-
}
133-
}
134-
}
135-
136-
depth = 0;
137-
138-
for (let x = i; x <= this.tokens.length; x++) {
139-
if (tokenIs(this.tokens[x], `openbracket`)) {
140-
depth++;
141-
} else
142-
if (tokenIs(this.tokens[x], `closebracket`)) {
143-
if (depth === 0) {
144-
end = x;
145-
break;
146128
} else {
147-
depth--;
129+
const rawStart = this.tokens.findIndex(token => token.range.start === block[0].range.start);
130+
const rawEnd = this.tokens.findIndex(token => token.range.end === block[block.length-1].range.end);
131+
return {
132+
start: rawStart,
133+
end: rawEnd+1
134+
};
148135
}
149136
}
150-
}
151137

152-
if (start === -1 || end === -1) {
153138
return undefined;
154-
} else {
155-
return {
156-
start,
157-
end
158-
}
159139
}
140+
141+
return blockContainsOffset(offset, this.blockTokens);
160142
}
161143

162144
getCallableDetail(offset: number, withBlocks = false): CallableReference {
@@ -176,13 +158,22 @@ export default class Statement {
176158
}
177159

178160
getBlockAt(offset: number): Token[] {
179-
const range = this.getBlockRangeAt(offset);
161+
const expandBlock = (tokens: Token[]): Token[] => {
162+
const block = tokens.filter(token => token.type === `block`);
163+
if (block.length > 0) {
164+
return block.reduce((acc, token) => acc.concat(expandBlock(token.block!)), tokens);
165+
}
180166

181-
if (range) {
182-
return this.tokens.slice(range.start, range.end)
183-
} else {
184-
return []
167+
return tokens;
168+
}
169+
170+
let blockRange = this.getBlockRangeAt(offset);
171+
172+
if (blockRange) {
173+
return expandBlock(this.tokens.slice(blockRange.start, blockRange.end));
185174
}
175+
176+
return [];
186177
}
187178

188179
getReferenceByOffset(offset: number) {
@@ -227,7 +218,7 @@ export default class Statement {
227218
getCTEReferences(): CTEReference[] {
228219
if (this.type !== StatementType.With) return [];
229220

230-
const withBlocks = SQLTokeniser.createBlocks(this.tokens.slice(0));
221+
const withBlocks = this.blockTokens;
231222

232223
let cteList: CTEReference[] = [];
233224

0 commit comments

Comments
 (0)