Skip to content

Commit 1396fbe

Browse files
committed
Improved functionality to allow different parameters to be applied to each sheet in the same SQL statement.
1 parent e744fb7 commit 1396fbe

File tree

5 files changed

+75
-6
lines changed

5 files changed

+75
-6
lines changed

queries/queries-with-dynamic-variables.json

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,26 @@
4242
"query": "SELECT OrderID, OrderNumber, OrderDate FROM SampleDB.dbo.Orders WHERE OrderDate >= '${startDate}' AND OrderDate <= '${endDate}' AND OrderDate >= DATEADD(day, -30, '${CURRENT_DATE}') ORDER BY OrderDate DESC"
4343
}
4444
],
45+
"queryDefs": {
46+
"customer_base": {
47+
"name": "customer_base",
48+
"description": "Base customer query",
49+
"query": "SELECT c.CustomerID as 고객ID, c.CustomerName as 고객명, c.City as 도시, c.Region as 지역, c.CustomerType as 고객유형 FROM SampleDB.dbo.Customers c WHERE c.CustomerID IN (${customerData.CustomerID}) AND c.Region IN (${regionList}) ORDER BY c.CustomerID"
50+
}
51+
},
4552
"sheets": [
4653
{
4754
"name": "${envType}_동적변수_테스트",
4855
"use": true,
56+
"queryRef": "customer_base",
4957
"aggregateColumn": "지역",
5058
"maxRows": 100,
5159
"db": "sampleDB",
52-
"query": "SELECT c.CustomerID as 고객ID, c.CustomerName as 고객명, c.City as 도시, c.Region as 지역, c.CustomerType as 고객유형 FROM SampleDB.dbo.Customers c WHERE c.CustomerID IN (${customerData.CustomerID}) AND c.Region IN (${regionList}) ORDER BY c.CustomerID"
60+
"params": {
61+
"regionList": ["서울", "부산", "대구"],
62+
"startDate": "2024-03-01",
63+
"endDate": "2024-12-31"
64+
}
5365
},
5466
{
5567
"name": "주문상세_동적변수_테스트2",

queries/queries-with-dynamic-variables.xml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,17 @@
8080

8181

8282
<!-- 시트 정의 -->
83-
<sheet name="${envType}_동적변수_테스트" use="true" queryRef="customer_base" aggregateColumn="지역" maxRows="100" db="sampleDB"/>
83+
<sheet name="${envType}_동적변수_서울_테스트" use="true" queryRef="customer_base" aggregateColumn="지역" maxRows="100" db="sampleDB">
84+
<params>
85+
<param name="regionList">["서울"]</param>
86+
</params>
87+
</sheet>
88+
89+
<sheet name="${envType}_동적변수_부산_테스트" use="true" queryRef="customer_base" aggregateColumn="지역" maxRows="100" db="sampleDB">
90+
<params>
91+
<param name="regionList">["부산"]</param>
92+
</params>
93+
</sheet>
8494

8595
<sheet name="주문상세_동적변수_테스트2" use="false" aggregateColumn="주문상태">
8696
<![CDATA[

src/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,8 @@ async function main() {
177177
continue;
178178
}
179179

180-
let sql = variableProcessor.substituteVars(sheetDef.query, mergedVars);
181-
const sheetName = variableProcessor.substituteVars(sheetDef.name, mergedVars);
180+
let sql = variableProcessor.substituteVars(sheetDef.query, mergedVars, sheetDef.params || {});
181+
const sheetName = variableProcessor.substituteVars(sheetDef.name, mergedVars, sheetDef.params || {});
182182

183183
// maxRows 제한 적용 (개별 시트 설정 > 전역 설정 우선)
184184
const effectiveMaxRows = sheetDef.maxRows || globalMaxRows;

src/query-parser.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,13 +117,48 @@ class QueryParser {
117117

118118
const sheets = parsed.queries.sheet.map(s => {
119119
let query = '';
120+
let sheetParams = {};
121+
122+
// 시트별 파라미터 파싱
123+
if (s.params && s.params[0] && s.params[0].param) {
124+
const paramElements = Array.isArray(s.params[0].param)
125+
? s.params[0].param
126+
: [s.params[0].param];
127+
128+
for (const param of paramElements) {
129+
if (param.$ && param.$.name && param._) {
130+
let value = param._.toString();
131+
// 배열 형태 문자열을 실제 배열로 변환
132+
if (value.startsWith('[') && value.endsWith(']')) {
133+
try {
134+
value = JSON.parse(value);
135+
} catch (e) {
136+
// JSON 파싱 실패 시 문자열 그대로 사용
137+
}
138+
}
139+
// boolean 값 처리
140+
if (value === 'true') value = true;
141+
if (value === 'false') value = false;
142+
// 숫자 값 처리
143+
if (!isNaN(value) && !isNaN(parseFloat(value)) && typeof value === 'string') {
144+
value = parseFloat(value);
145+
}
146+
sheetParams[param.$.name] = value;
147+
}
148+
}
149+
}
120150

121151
// queryRef 속성이 있으면 쿼리 정의에서 참조
122152
if (s.$.queryRef) {
123153
const queryRef = s.$.queryRef;
124154
if (queryDefs[queryRef]) {
125155
query = queryDefs[queryRef].query;
126156
console.log(`[쿼리 참조] 시트 "${s.$.name}"이(가) 쿼리 정의 "${queryRef}"을(를) 참조합니다.`);
157+
158+
// 시트별 파라미터가 있으면 로그 출력
159+
if (Object.keys(sheetParams).length > 0) {
160+
console.log(`[파라미터 재설정] 시트 "${s.$.name}"에서 파라미터 재설정:`, sheetParams);
161+
}
127162
} else {
128163
throw new Error(`쿼리 정의를 찾을 수 없습니다: ${queryRef} (시트: ${s.$.name})`);
129164
}
@@ -140,6 +175,7 @@ class QueryParser {
140175
db: s.$.db || null,
141176
queryRef: s.$.queryRef || null,
142177
style: s.$.style || null, // 시트별 스타일 추가
178+
params: sheetParams, // 시트별 파라미터 추가
143179
query: query
144180
};
145181
});
@@ -167,19 +203,26 @@ class QueryParser {
167203
// JSON 시트에서 queryRef 처리
168204
const sheets = (queries.sheets || []).map(sheet => {
169205
let query = sheet.query || '';
206+
let sheetParams = sheet.params || {};
170207

171208
// queryRef가 있으면 쿼리 정의에서 참조
172209
if (sheet.queryRef) {
173210
if (queryDefs[sheet.queryRef]) {
174211
query = queryDefs[sheet.queryRef].query || queryDefs[sheet.queryRef];
175212
console.log(`[쿼리 참조] 시트 "${sheet.name}"이(가) 쿼리 정의 "${sheet.queryRef}"을(를) 참조합니다.`);
213+
214+
// 시트별 파라미터가 있으면 로그 출력
215+
if (Object.keys(sheetParams).length > 0) {
216+
console.log(`[파라미터 재설정] 시트 "${sheet.name}"에서 파라미터 재설정:`, sheetParams);
217+
}
176218
} else {
177219
throw new Error(`쿼리 정의를 찾을 수 없습니다: ${sheet.queryRef} (시트: ${sheet.name})`);
178220
}
179221
}
180222

181223
return {
182224
...sheet,
225+
params: sheetParams,
183226
query: query
184227
};
185228
});

src/variable-processor.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,16 +117,20 @@ class VariableProcessor {
117117
* 향상된 변수 치환 함수 (동적 변수 지원)
118118
* @param {string} str - 치환할 문자열
119119
* @param {Object} vars - 변수 객체
120+
* @param {Object} sheetParams - 시트별 파라미터 (선택사항)
120121
* @returns {string} 치환된 문자열
121122
*/
122-
substituteVars(str, vars) {
123+
substituteVars(str, vars, sheetParams = {}) {
123124
let result = str;
124125
const debugVariables = process.env.DEBUG_VARIABLES === 'true';
125126

126127
if (debugVariables) {
127128
console.log(`변수 치환 시작: ${str.substring(0, 200)}${str.length > 200 ? '...' : ''}`);
128129
}
129130

131+
// 시트별 파라미터를 전역 변수에 병합 (우선순위 높음)
132+
const mergedVars = { ...vars, ...sheetParams };
133+
130134
// 동적 변수 치환 (우선순위 높음)
131135
Object.entries(this.dynamicVariables).forEach(([key, value]) => {
132136
const pattern = new RegExp(`\\$\\{${key}\\}`, 'g');
@@ -203,7 +207,7 @@ class VariableProcessor {
203207

204208
// 일반 변수 치환 (기존 방식)
205209
result = result.replace(/\$\{(\w+)\}/g, (_, v) => {
206-
const value = vars[v];
210+
const value = mergedVars[v];
207211
if (value === undefined || value === null) return '';
208212

209213
// 배열 타입인 경우 IN절 처리

0 commit comments

Comments
 (0)