1
+ import { Container } from '@n8n/di' ;
1
2
import alasql from 'alasql' ;
2
3
import type { Database } from 'alasql' ;
4
+ import { ErrorReporter } from 'n8n-core' ;
3
5
import type {
4
6
IDataObject ,
5
7
IExecuteFunctions ,
8
+ INode ,
6
9
INodeExecutionData ,
7
10
INodeProperties ,
8
11
IPairedItemData ,
@@ -12,6 +15,7 @@ import { NodeOperationError } from 'n8n-workflow';
12
15
import { getResolvables , updateDisplayOptions } from '@utils/utilities' ;
13
16
14
17
import { numberInputsProperty } from '../../helpers/descriptions' ;
18
+ import { modifySelectQuery , rowToExecutionData } from '../../helpers/utils' ;
15
19
16
20
export const properties : INodeProperties [ ] = [
17
21
numberInputsProperty ,
@@ -39,15 +43,102 @@ const displayOptions = {
39
43
40
44
export const description = updateDisplayOptions ( displayOptions , properties ) ;
41
45
46
+ const prepareError = ( node : INode , error : Error ) => {
47
+ let message = '' ;
48
+ if ( typeof error === 'string' ) {
49
+ message = error ;
50
+ } else {
51
+ message = error . message ;
52
+ }
53
+ throw new NodeOperationError ( node , error , {
54
+ message : 'Issue while executing query' ,
55
+ description : message ,
56
+ itemIndex : 0 ,
57
+ } ) ;
58
+ } ;
59
+
60
+ async function executeSelectWithMappedPairedItems (
61
+ node : INode ,
62
+ inputsData : INodeExecutionData [ ] [ ] ,
63
+ query : string ,
64
+ ) : Promise < INodeExecutionData [ ] [ ] > {
65
+ const returnData : INodeExecutionData [ ] = [ ] ;
66
+
67
+ const db : typeof Database = new ( alasql as any ) . Database ( node . id ) ;
68
+
69
+ try {
70
+ for ( let i = 0 ; i < inputsData . length ; i ++ ) {
71
+ const inputData = inputsData [ i ] ;
72
+
73
+ db . exec ( `CREATE TABLE input${ i + 1 } ` ) ;
74
+ db . tables [ `input${ i + 1 } ` ] . data = inputData . map ( ( entry ) => ( {
75
+ ...entry . json ,
76
+ pairedItem : entry . pairedItem ,
77
+ } ) ) ;
78
+ }
79
+ } catch ( error ) {
80
+ throw new NodeOperationError ( node , error , {
81
+ message : 'Issue while creating table from' ,
82
+ description : error . message ,
83
+ itemIndex : 0 ,
84
+ } ) ;
85
+ }
86
+
87
+ try {
88
+ const result : IDataObject [ ] = db . exec ( modifySelectQuery ( query , inputsData . length ) ) ;
89
+
90
+ for ( const item of result ) {
91
+ if ( Array . isArray ( item ) ) {
92
+ returnData . push ( ...item . map ( ( entry ) => rowToExecutionData ( entry ) ) ) ;
93
+ } else if ( typeof item === 'object' ) {
94
+ returnData . push ( rowToExecutionData ( item ) ) ;
95
+ }
96
+ }
97
+
98
+ if ( ! returnData . length ) {
99
+ returnData . push ( { json : { success : true } } ) ;
100
+ }
101
+ } catch ( error ) {
102
+ prepareError ( node , error as Error ) ;
103
+ } finally {
104
+ delete alasql . databases [ node . id ] ;
105
+ }
106
+
107
+ return [ returnData ] ;
108
+ }
109
+
42
110
export async function execute (
43
111
this : IExecuteFunctions ,
44
112
inputsData : INodeExecutionData [ ] [ ] ,
45
113
) : Promise < INodeExecutionData [ ] [ ] > {
46
- const nodeId = this . getNode ( ) . id ;
114
+ const node = this . getNode ( ) ;
47
115
const returnData : INodeExecutionData [ ] = [ ] ;
48
116
const pairedItem : IPairedItemData [ ] = [ ] ;
49
117
50
- const db : typeof Database = new ( alasql as any ) . Database ( nodeId ) ;
118
+ let query = this . getNodeParameter ( 'query' , 0 ) as string ;
119
+
120
+ for ( const resolvable of getResolvables ( query ) ) {
121
+ query = query . replace ( resolvable , this . evaluateExpression ( resolvable , 0 ) as string ) ;
122
+ }
123
+
124
+ const isSelectQuery = node . typeVersion >= 3.1 ? query . toLowerCase ( ) . startsWith ( 'select' ) : false ;
125
+
126
+ if ( isSelectQuery ) {
127
+ try {
128
+ return await executeSelectWithMappedPairedItems ( node , inputsData , query ) ;
129
+ } catch ( error ) {
130
+ Container . get ( ErrorReporter ) . error ( error , {
131
+ extra : {
132
+ nodeName : node . name ,
133
+ nodeType : node . type ,
134
+ nodeVersion : node . typeVersion ,
135
+ workflowId : this . getWorkflow ( ) . id ,
136
+ } ,
137
+ } ) ;
138
+ }
139
+ }
140
+
141
+ const db : typeof Database = new ( alasql as any ) . Database ( node . id ) ;
51
142
52
143
try {
53
144
for ( let i = 0 ; i < inputsData . length ; i ++ ) {
@@ -90,20 +181,14 @@ export async function execute(
90
181
db . tables [ `input${ i + 1 } ` ] . data = inputData . map ( ( entry ) => entry . json ) ;
91
182
}
92
183
} catch ( error ) {
93
- throw new NodeOperationError ( this . getNode ( ) , error , {
184
+ throw new NodeOperationError ( node , error , {
94
185
message : 'Issue while creating table from' ,
95
186
description : error . message ,
96
187
itemIndex : 0 ,
97
188
} ) ;
98
189
}
99
190
100
191
try {
101
- let query = this . getNodeParameter ( 'query' , 0 ) as string ;
102
-
103
- for ( const resolvable of getResolvables ( query ) ) {
104
- query = query . replace ( resolvable , this . evaluateExpression ( resolvable , 0 ) as string ) ;
105
- }
106
-
107
192
const result : IDataObject [ ] = db . exec ( query ) ;
108
193
109
194
for ( const item of result ) {
@@ -118,20 +203,10 @@ export async function execute(
118
203
returnData . push ( { json : { success : true } , pairedItem } ) ;
119
204
}
120
205
} catch ( error ) {
121
- let message = '' ;
122
- if ( typeof error === 'string' ) {
123
- message = error ;
124
- } else {
125
- message = error . message ;
126
- }
127
- throw new NodeOperationError ( this . getNode ( ) , error , {
128
- message : 'Issue while executing query' ,
129
- description : message ,
130
- itemIndex : 0 ,
131
- } ) ;
206
+ prepareError ( node , error as Error ) ;
207
+ } finally {
208
+ delete alasql . databases [ node . id ] ;
132
209
}
133
210
134
- delete alasql . databases [ nodeId ] ;
135
-
136
211
return [ returnData ] ;
137
212
}
0 commit comments