@bimatrix-aud-platform/aud_mcp_server 1.1.16 → 1.1.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/generators/datasource.js +1 -1
- package/dist/generators/fixer.js +10 -67
- package/dist/generators/olap-field.d.ts +45 -0
- package/dist/generators/olap-field.js +316 -0
- package/dist/index.js +68 -0
- package/package.json +1 -1
- package/schemas/mtsd.interface.ts +6 -6
- package/schemas/mtsd.schema.json +6 -7
|
@@ -40,7 +40,7 @@ export function generateDataSource(input) {
|
|
|
40
40
|
// Params 배열 (스키마: Name, Value 필수)
|
|
41
41
|
const params = paramNames.map((name) => ({
|
|
42
42
|
Name: name.startsWith(":") ? name : `:${name}`,
|
|
43
|
-
|
|
43
|
+
ParamType: "String",
|
|
44
44
|
}));
|
|
45
45
|
// Columns 배열 (스키마: Name, Type 필수)
|
|
46
46
|
const columns = (input.columns || []).map((col) => ({
|
package/dist/generators/fixer.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { readFileSync, writeFileSync } from "fs";
|
|
2
|
+
import { createDefaultOlapField, isNumericColumnType } from "./olap-field.js";
|
|
2
3
|
/**
|
|
3
4
|
* MTSD 파일을 읽고, 자동 보정 규칙을 적용한 뒤, 파일을 덮어씁니다.
|
|
4
5
|
*/
|
|
@@ -38,6 +39,14 @@ export function fixMtsd(filePath) {
|
|
|
38
39
|
if (ds.Id && ds.Name) {
|
|
39
40
|
dsNameToId.set(ds.Name, ds.Id);
|
|
40
41
|
dsIdSet.add(ds.Id);
|
|
42
|
+
if (ds.Params) {
|
|
43
|
+
//파라미터 fix
|
|
44
|
+
for (let i = 0, i2 = ds.Params.length; i < i2; i++) {
|
|
45
|
+
if (!ds.Params[i].ParamType) {
|
|
46
|
+
ds.Params[i].ParamType = ds.Params[i].Name.toUpperCase().indexOf("VN_") ? "Numeric" : "String";
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
41
50
|
}
|
|
42
51
|
}
|
|
43
52
|
// 3. 보정 규칙 적용
|
|
@@ -92,73 +101,7 @@ function fixDataSourceReferences(doc, dsNameToId, dsIdSet, fixes) {
|
|
|
92
101
|
}
|
|
93
102
|
}
|
|
94
103
|
// ---- Rule 2: OlapGrid DataSource 기반 Fields 자동 생성 ----
|
|
95
|
-
//
|
|
96
|
-
const NUMERIC_COLUMN_TYPES = new Set([
|
|
97
|
-
"Numeric",
|
|
98
|
-
// SQL 타입 호환
|
|
99
|
-
"INT", "INTEGER", "BIGINT", "SMALLINT", "TINYINT",
|
|
100
|
-
"NUMERIC", "DECIMAL", "FLOAT", "DOUBLE", "REAL", "NUMBER", "MONEY",
|
|
101
|
-
]);
|
|
102
|
-
function isNumericColumnType(type) {
|
|
103
|
-
return NUMERIC_COLUMN_TYPES.has(type) || NUMERIC_COLUMN_TYPES.has(type.toUpperCase());
|
|
104
|
-
}
|
|
105
|
-
/** OlapField 기본값 생성 (OlapField constructor + Serialize 기준) */
|
|
106
|
-
function createDefaultOlapField(key, caption) {
|
|
107
|
-
return {
|
|
108
|
-
Key: key,
|
|
109
|
-
Caption: caption,
|
|
110
|
-
ToolTipField: "",
|
|
111
|
-
ToolTipText: "",
|
|
112
|
-
Category: 1, // enCategory.Dimension
|
|
113
|
-
Area: 0, // enArea.Hidden
|
|
114
|
-
SummaryType: 0, // enSummaryType.None
|
|
115
|
-
TotalSummaryType: 0,
|
|
116
|
-
SummaryVariation: 0,
|
|
117
|
-
GroupByType: 0, // enGroupByType.Auto
|
|
118
|
-
Format: "",
|
|
119
|
-
Formula: "",
|
|
120
|
-
Formula2: "",
|
|
121
|
-
RefFormula: "",
|
|
122
|
-
Width: 100,
|
|
123
|
-
Unit: 1,
|
|
124
|
-
CreateType: 0, // enOlapFieldCreateType.Default
|
|
125
|
-
SortType: 0, // enSortType.None
|
|
126
|
-
MeasureSortField: "",
|
|
127
|
-
SortBaseField: "",
|
|
128
|
-
MoveAble: true,
|
|
129
|
-
SortAble: true,
|
|
130
|
-
FilterAble: true,
|
|
131
|
-
AllowFilter: true,
|
|
132
|
-
AllowRow: true,
|
|
133
|
-
AllowColumn: true,
|
|
134
|
-
AllowData: true,
|
|
135
|
-
KeyType: 0, // enKeyType.None
|
|
136
|
-
DataType: 0, // enDataType.Numeric
|
|
137
|
-
SaveMode: 0, // enSaveMode.All
|
|
138
|
-
LanguageCode: "",
|
|
139
|
-
UseChartSource: true,
|
|
140
|
-
VisibleSubTotal: true,
|
|
141
|
-
SummaryBaseFieldKey: "",
|
|
142
|
-
TextAlignment: 1, // enHorizonAlign.Right
|
|
143
|
-
HeaderAlignment: 0, // enHorizonAlign.Left
|
|
144
|
-
InDimensions: "",
|
|
145
|
-
Visible: true,
|
|
146
|
-
Expanded: true,
|
|
147
|
-
MetaItemCode: "",
|
|
148
|
-
MetaItemName: "",
|
|
149
|
-
MetaRollupType: 0,
|
|
150
|
-
MetaCalculatorField: false,
|
|
151
|
-
MetaSummaryTypeIsDistinct: false,
|
|
152
|
-
FilterInfo: {
|
|
153
|
-
FilterType: 0, // enOlapFilterType.In
|
|
154
|
-
FilterKind: 0, // enOlapFilterKind.Dimension
|
|
155
|
-
HasMeasureFilter: false,
|
|
156
|
-
MeasureFilterTypeA: 0, // enOlapMeasureFilterType.Equals
|
|
157
|
-
MeasureFilterTypeB: 0,
|
|
158
|
-
MeasureAndOrOperator: 2, // enAndOrOperator.And
|
|
159
|
-
},
|
|
160
|
-
};
|
|
161
|
-
}
|
|
104
|
+
// createDefaultOlapField, isNumericColumnType는 olap-field.ts에서 import
|
|
162
105
|
function fixOlapGridFields(doc, datas, fixes) {
|
|
163
106
|
// DataSource Id → DataSource 객체 매핑
|
|
164
107
|
const dsById = new Map();
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OlapGrid iOLAPView.Fields 생성기
|
|
3
|
+
*
|
|
4
|
+
* 컬럼 정의를 입력받아 OlapField 배열을 생성합니다.
|
|
5
|
+
* iOLAP.OlapGrid.ts의 createDataSourceFields (UseMeta==false) 로직을 기반으로 합니다.
|
|
6
|
+
*
|
|
7
|
+
* @see 2.Sources/src/control/olapgrid/iOLAP.OlapGrid.ts:4592-4657 — 필드 생성
|
|
8
|
+
* @see 2.Sources/src/control/olapgrid/iOLAP.OlapGrid.ts:1806-1837 — Area 자동 배치
|
|
9
|
+
* @see 2.Sources/src/control/olapgrid/iOLAP.Enums.ts — enCategory, enArea 등
|
|
10
|
+
*/
|
|
11
|
+
export declare function isNumericColumnType(type: string): boolean;
|
|
12
|
+
export declare function createDefaultOlapField(key: string, caption: string): any;
|
|
13
|
+
export interface OlapFieldColumn {
|
|
14
|
+
name: string;
|
|
15
|
+
caption?: string;
|
|
16
|
+
type?: string;
|
|
17
|
+
area?: string;
|
|
18
|
+
summaryType?: string;
|
|
19
|
+
format?: string;
|
|
20
|
+
sortType?: string;
|
|
21
|
+
width?: number;
|
|
22
|
+
}
|
|
23
|
+
export interface GenerateOlapFieldsInput {
|
|
24
|
+
columns: OlapFieldColumn[];
|
|
25
|
+
autoPlace?: boolean;
|
|
26
|
+
includeOptions?: boolean;
|
|
27
|
+
}
|
|
28
|
+
export interface GenerateOlapFieldsResult {
|
|
29
|
+
fields: any[];
|
|
30
|
+
iOLAPView?: any;
|
|
31
|
+
warnings: string[];
|
|
32
|
+
summary: {
|
|
33
|
+
total: number;
|
|
34
|
+
dimensions: number;
|
|
35
|
+
measures: number;
|
|
36
|
+
areaMap: {
|
|
37
|
+
row: string[];
|
|
38
|
+
column: string[];
|
|
39
|
+
data: string[];
|
|
40
|
+
filter: string[];
|
|
41
|
+
hidden: string[];
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export declare function generateOlapFields(input: GenerateOlapFieldsInput): GenerateOlapFieldsResult;
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OlapGrid iOLAPView.Fields 생성기
|
|
3
|
+
*
|
|
4
|
+
* 컬럼 정의를 입력받아 OlapField 배열을 생성합니다.
|
|
5
|
+
* iOLAP.OlapGrid.ts의 createDataSourceFields (UseMeta==false) 로직을 기반으로 합니다.
|
|
6
|
+
*
|
|
7
|
+
* @see 2.Sources/src/control/olapgrid/iOLAP.OlapGrid.ts:4592-4657 — 필드 생성
|
|
8
|
+
* @see 2.Sources/src/control/olapgrid/iOLAP.OlapGrid.ts:1806-1837 — Area 자동 배치
|
|
9
|
+
* @see 2.Sources/src/control/olapgrid/iOLAP.Enums.ts — enCategory, enArea 등
|
|
10
|
+
*/
|
|
11
|
+
// ─── enums (iOLAP.Enums.ts 기준) ───
|
|
12
|
+
const enArea = { Hidden: 0, Row: 1, Column: 2, Filter: 3, Data: 4 };
|
|
13
|
+
const enCategory = { Default: 0, Dimension: 1, Measure: 2, Attribute: 3, Period: 4 };
|
|
14
|
+
const enSummaryType = { None: 0, Sum: 1, Min: 2, Max: 3, Average: 4, Count: 5, Calculate: 9, DistinctCount: 13, Text: 14 };
|
|
15
|
+
const enSortType = { None: 0, Asc: 1, Desc: 2, Custom: 3 };
|
|
16
|
+
const enDataType = { Numeric: 0, String: 1, DateTime8: 2, DateTimeNow: 3, UserCode: 4, CLOB: 5 };
|
|
17
|
+
// ─── 숫자형 컬럼 타입 판별 ───
|
|
18
|
+
const NUMERIC_COLUMN_TYPES = new Set([
|
|
19
|
+
"Numeric",
|
|
20
|
+
"INT", "INTEGER", "BIGINT", "SMALLINT", "TINYINT",
|
|
21
|
+
"NUMERIC", "DECIMAL", "FLOAT", "DOUBLE", "REAL", "NUMBER", "MONEY",
|
|
22
|
+
]);
|
|
23
|
+
export function isNumericColumnType(type) {
|
|
24
|
+
return NUMERIC_COLUMN_TYPES.has(type) || NUMERIC_COLUMN_TYPES.has(type.toUpperCase());
|
|
25
|
+
}
|
|
26
|
+
// ─── OlapField 기본값 생성 (OlapField constructor + Serialize 기준) ───
|
|
27
|
+
export function createDefaultOlapField(key, caption) {
|
|
28
|
+
return {
|
|
29
|
+
Key: key,
|
|
30
|
+
Caption: caption,
|
|
31
|
+
ToolTipField: "",
|
|
32
|
+
ToolTipText: "",
|
|
33
|
+
Category: enCategory.Dimension,
|
|
34
|
+
Area: enArea.Hidden,
|
|
35
|
+
SummaryType: enSummaryType.None,
|
|
36
|
+
TotalSummaryType: 0,
|
|
37
|
+
SummaryVariation: 0,
|
|
38
|
+
GroupByType: 0,
|
|
39
|
+
Format: "",
|
|
40
|
+
Formula: "",
|
|
41
|
+
Formula2: "",
|
|
42
|
+
RefFormula: "",
|
|
43
|
+
Width: 100,
|
|
44
|
+
Unit: 1,
|
|
45
|
+
CreateType: 0,
|
|
46
|
+
SortType: enSortType.None,
|
|
47
|
+
MeasureSortField: "",
|
|
48
|
+
SortBaseField: "",
|
|
49
|
+
MoveAble: true,
|
|
50
|
+
SortAble: true,
|
|
51
|
+
FilterAble: true,
|
|
52
|
+
AllowFilter: true,
|
|
53
|
+
AllowRow: true,
|
|
54
|
+
AllowColumn: true,
|
|
55
|
+
AllowData: true,
|
|
56
|
+
KeyType: 0,
|
|
57
|
+
DataType: enDataType.Numeric,
|
|
58
|
+
SaveMode: 0,
|
|
59
|
+
LanguageCode: "",
|
|
60
|
+
UseChartSource: true,
|
|
61
|
+
VisibleSubTotal: true,
|
|
62
|
+
SummaryBaseFieldKey: "",
|
|
63
|
+
TextAlignment: 1, // Right
|
|
64
|
+
HeaderAlignment: 0, // Left
|
|
65
|
+
InDimensions: "",
|
|
66
|
+
Visible: true,
|
|
67
|
+
Expanded: true,
|
|
68
|
+
MetaItemCode: "",
|
|
69
|
+
MetaItemName: "",
|
|
70
|
+
MetaRollupType: 0,
|
|
71
|
+
MetaCalculatorField: false,
|
|
72
|
+
MetaSummaryTypeIsDistinct: false,
|
|
73
|
+
FilterInfo: {
|
|
74
|
+
FilterType: 0,
|
|
75
|
+
FilterKind: 0,
|
|
76
|
+
HasMeasureFilter: false,
|
|
77
|
+
MeasureFilterTypeA: 0,
|
|
78
|
+
MeasureFilterTypeB: 0,
|
|
79
|
+
MeasureAndOrOperator: 2,
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
// ─── summaryType 문자열 → enum 변환 ───
|
|
84
|
+
function parseSummaryType(s) {
|
|
85
|
+
switch (s.toLowerCase()) {
|
|
86
|
+
case "sum": return enSummaryType.Sum;
|
|
87
|
+
case "count": return enSummaryType.Count;
|
|
88
|
+
case "average":
|
|
89
|
+
case "avg": return enSummaryType.Average;
|
|
90
|
+
case "min": return enSummaryType.Min;
|
|
91
|
+
case "max": return enSummaryType.Max;
|
|
92
|
+
case "none": return enSummaryType.None;
|
|
93
|
+
case "distinctcount": return enSummaryType.DistinctCount;
|
|
94
|
+
case "text": return enSummaryType.Text;
|
|
95
|
+
default: return enSummaryType.None;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// ─── sortType 문자열 → enum 변환 ───
|
|
99
|
+
function parseSortType(s) {
|
|
100
|
+
switch (s.toLowerCase()) {
|
|
101
|
+
case "asc": return enSortType.Asc;
|
|
102
|
+
case "desc": return enSortType.Desc;
|
|
103
|
+
case "none": return enSortType.None;
|
|
104
|
+
default: return enSortType.None;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// ─── area 문자열 → enum 변환 ───
|
|
108
|
+
function parseArea(s) {
|
|
109
|
+
switch (s.toLowerCase()) {
|
|
110
|
+
case "row": return enArea.Row;
|
|
111
|
+
case "column":
|
|
112
|
+
case "col": return enArea.Column;
|
|
113
|
+
case "data": return enArea.Data;
|
|
114
|
+
case "filter": return enArea.Filter;
|
|
115
|
+
case "hidden": return enArea.Hidden;
|
|
116
|
+
default: return enArea.Hidden;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// ─── iOLAPView.Options 기본값 ───
|
|
120
|
+
function createDefaultOptions() {
|
|
121
|
+
return {
|
|
122
|
+
ViewType: 0,
|
|
123
|
+
IsExpandAll: true,
|
|
124
|
+
ShowExpandButtons: true,
|
|
125
|
+
EmptyCellText: "",
|
|
126
|
+
NotAvaliableCellText: "",
|
|
127
|
+
ZeroDivisioinCellText: "",
|
|
128
|
+
ErrorCellText: "",
|
|
129
|
+
RowGrandTotalText: "총계",
|
|
130
|
+
ColumnGrandTotalText: "총계",
|
|
131
|
+
RowTotalText: "소계",
|
|
132
|
+
ColumnTotalText: "소계",
|
|
133
|
+
RowTotalLocation: 1,
|
|
134
|
+
ColumnTotalLocation: 1,
|
|
135
|
+
RowGrandTotalLocation: 1,
|
|
136
|
+
ColumnGrandTotalLocation: 1,
|
|
137
|
+
DisplayColumnSubTotal: true,
|
|
138
|
+
DisplayRowSubTotal: true,
|
|
139
|
+
DisplayColumnGrandTotal: true,
|
|
140
|
+
DisplayRowGrandTotal: true,
|
|
141
|
+
ShowFilterArea: true,
|
|
142
|
+
ShowColumnrArea: true,
|
|
143
|
+
ShowRowArea: true,
|
|
144
|
+
ShowDataArea: true,
|
|
145
|
+
UseMultiHeader: false,
|
|
146
|
+
AutoSelection: false,
|
|
147
|
+
HideHorizontalScrollBar: false,
|
|
148
|
+
HideVerticalScrollBar: false,
|
|
149
|
+
DisableClipBoard: false,
|
|
150
|
+
CellHeight: 24,
|
|
151
|
+
HeaderCellHeight: 24,
|
|
152
|
+
CanResizeCellWidth: true,
|
|
153
|
+
RowHeaderUnFix: false,
|
|
154
|
+
MeasuresCreateArea: 1,
|
|
155
|
+
TreeHeaderWidth: 200,
|
|
156
|
+
TreeIndentWidth: 16,
|
|
157
|
+
DisableColumnSort: false,
|
|
158
|
+
EnableWriteBack: false,
|
|
159
|
+
MergeColumnHeaders: false,
|
|
160
|
+
MergeRowHeaders: false,
|
|
161
|
+
CacheOption: {
|
|
162
|
+
UseHybrid: true,
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
export function generateOlapFields(input) {
|
|
167
|
+
const warnings = [];
|
|
168
|
+
const columns = input.columns || [];
|
|
169
|
+
const autoPlace = input.autoPlace !== false; // 기본 true
|
|
170
|
+
const includeOptions = input.includeOptions === true;
|
|
171
|
+
if (columns.length === 0) {
|
|
172
|
+
warnings.push("columns 배열이 비어 있습니다.");
|
|
173
|
+
return {
|
|
174
|
+
fields: [],
|
|
175
|
+
warnings,
|
|
176
|
+
summary: { total: 0, dimensions: 0, measures: 0, areaMap: { row: [], column: [], data: [], filter: [], hidden: [] } },
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
// 1. 필드 생성
|
|
180
|
+
const fields = [];
|
|
181
|
+
const nameSet = new Set();
|
|
182
|
+
for (const col of columns) {
|
|
183
|
+
if (!col.name) {
|
|
184
|
+
warnings.push("name이 비어있는 컬럼이 있어 건너뜁니다.");
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
if (nameSet.has(col.name)) {
|
|
188
|
+
warnings.push(`중복 컬럼명 "${col.name}" 발견, 건너뜁니다.`);
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
nameSet.add(col.name);
|
|
192
|
+
const caption = col.caption || col.name;
|
|
193
|
+
const field = createDefaultOlapField(col.name, caption);
|
|
194
|
+
const isNumeric = isNumericColumnType(col.type || "string");
|
|
195
|
+
// 타입 기반 기본값 설정 (createDataSourceFields 로직)
|
|
196
|
+
if (isNumeric) {
|
|
197
|
+
field.Category = enCategory.Measure;
|
|
198
|
+
field.Format = "{0:N0}";
|
|
199
|
+
field.DataType = enDataType.Numeric;
|
|
200
|
+
field.SummaryType = enSummaryType.Sum;
|
|
201
|
+
field.TextAlignment = 1; // Right
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
field.Category = enCategory.Dimension;
|
|
205
|
+
field.DataType = enDataType.String;
|
|
206
|
+
field.SortType = enSortType.Asc;
|
|
207
|
+
field.SummaryType = enSummaryType.Count;
|
|
208
|
+
field.TextAlignment = 1; // Right
|
|
209
|
+
}
|
|
210
|
+
// 커스텀 오버라이드
|
|
211
|
+
if (col.summaryType) {
|
|
212
|
+
field.SummaryType = parseSummaryType(col.summaryType);
|
|
213
|
+
}
|
|
214
|
+
if (col.format) {
|
|
215
|
+
field.Format = col.format;
|
|
216
|
+
}
|
|
217
|
+
if (col.sortType) {
|
|
218
|
+
field.SortType = parseSortType(col.sortType);
|
|
219
|
+
}
|
|
220
|
+
if (col.width != null) {
|
|
221
|
+
field.Width = col.width;
|
|
222
|
+
}
|
|
223
|
+
// 수동 Area 지정
|
|
224
|
+
if (col.area) {
|
|
225
|
+
field.Area = parseArea(col.area);
|
|
226
|
+
}
|
|
227
|
+
fields.push(field);
|
|
228
|
+
}
|
|
229
|
+
// 2. Area 자동 배치 (setDataSource 로직 준용)
|
|
230
|
+
if (autoPlace) {
|
|
231
|
+
let rowCnt = 0;
|
|
232
|
+
let colCnt = 0;
|
|
233
|
+
let dataCnt = 0;
|
|
234
|
+
for (const field of fields) {
|
|
235
|
+
// 수동 area가 이미 지정된 경우 스킵 (Hidden=0이 아닌 경우)
|
|
236
|
+
if (field.Area !== enArea.Hidden)
|
|
237
|
+
continue;
|
|
238
|
+
if (field.DataType === enDataType.Numeric) {
|
|
239
|
+
// Numeric → Data(최대 3개) → Filter
|
|
240
|
+
if (dataCnt < 3) {
|
|
241
|
+
field.Area = enArea.Data;
|
|
242
|
+
dataCnt++;
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
field.Area = enArea.Filter;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
// String → Row(최대 2개) → Column(최대 2개) → Filter
|
|
250
|
+
if (rowCnt < 2) {
|
|
251
|
+
field.Area = enArea.Row;
|
|
252
|
+
rowCnt++;
|
|
253
|
+
}
|
|
254
|
+
else if (colCnt < 2) {
|
|
255
|
+
field.Area = enArea.Column;
|
|
256
|
+
colCnt++;
|
|
257
|
+
}
|
|
258
|
+
else {
|
|
259
|
+
field.Area = enArea.Filter;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
// 3. 요약 정보 생성
|
|
265
|
+
const areaMap = { row: [], column: [], data: [], filter: [], hidden: [] };
|
|
266
|
+
let dimensions = 0;
|
|
267
|
+
let measures = 0;
|
|
268
|
+
for (const field of fields) {
|
|
269
|
+
if (field.Category === enCategory.Measure)
|
|
270
|
+
measures++;
|
|
271
|
+
else
|
|
272
|
+
dimensions++;
|
|
273
|
+
switch (field.Area) {
|
|
274
|
+
case enArea.Row:
|
|
275
|
+
areaMap.row.push(field.Key);
|
|
276
|
+
break;
|
|
277
|
+
case enArea.Column:
|
|
278
|
+
areaMap.column.push(field.Key);
|
|
279
|
+
break;
|
|
280
|
+
case enArea.Data:
|
|
281
|
+
areaMap.data.push(field.Key);
|
|
282
|
+
break;
|
|
283
|
+
case enArea.Filter:
|
|
284
|
+
areaMap.filter.push(field.Key);
|
|
285
|
+
break;
|
|
286
|
+
default:
|
|
287
|
+
areaMap.hidden.push(field.Key);
|
|
288
|
+
break;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
// 4. 결과 조립
|
|
292
|
+
const result = {
|
|
293
|
+
fields,
|
|
294
|
+
warnings,
|
|
295
|
+
summary: {
|
|
296
|
+
total: fields.length,
|
|
297
|
+
dimensions,
|
|
298
|
+
measures,
|
|
299
|
+
areaMap,
|
|
300
|
+
},
|
|
301
|
+
};
|
|
302
|
+
// includeOptions: iOLAPView 전체 구조 포함
|
|
303
|
+
if (includeOptions) {
|
|
304
|
+
result.iOLAPView = {
|
|
305
|
+
Options: createDefaultOptions(),
|
|
306
|
+
TopFilter: {
|
|
307
|
+
Dimension: "",
|
|
308
|
+
Measure: "",
|
|
309
|
+
Rank: 0,
|
|
310
|
+
IsTop: true,
|
|
311
|
+
},
|
|
312
|
+
Fields: fields,
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
return result;
|
|
316
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -12,6 +12,7 @@ import { generateGridColumns } from "./generators/grid-column.js";
|
|
|
12
12
|
import { generateDataSource } from "./generators/datasource.js";
|
|
13
13
|
import { fixMtsd } from "./generators/fixer.js";
|
|
14
14
|
import { getControlInfo } from "./generators/control-info.js";
|
|
15
|
+
import { generateOlapFields } from "./generators/olap-field.js";
|
|
15
16
|
import { callSchemaService, callDbmsList, isAudConfigured, setWorkspaceRoots } from "./utils/aud-api-client.js";
|
|
16
17
|
const __filename = fileURLToPath(import.meta.url);
|
|
17
18
|
const __dirname = dirname(__filename);
|
|
@@ -494,6 +495,54 @@ const tools = [
|
|
|
494
495
|
additionalProperties: true,
|
|
495
496
|
},
|
|
496
497
|
},
|
|
498
|
+
{
|
|
499
|
+
name: "generate_olap_fields",
|
|
500
|
+
description: "OlapGrid의 iOLAPView.Fields 배열을 생성합니다. 컬럼 정의를 입력하면 Dimension/Measure 분류, Area 자동 배치, SummaryType 설정이 완료된 OlapField 배열을 반환합니다.",
|
|
501
|
+
inputSchema: {
|
|
502
|
+
type: "object",
|
|
503
|
+
properties: {
|
|
504
|
+
columns: {
|
|
505
|
+
type: "array",
|
|
506
|
+
items: {
|
|
507
|
+
type: "object",
|
|
508
|
+
properties: {
|
|
509
|
+
name: { type: "string", description: "컬럼명 (OlapField Key)" },
|
|
510
|
+
caption: { type: "string", description: "표시명 (생략 시 name)" },
|
|
511
|
+
type: {
|
|
512
|
+
type: "string",
|
|
513
|
+
enum: ["string", "number", "numeric", "date", "datetime", "int", "float", "decimal", "varchar", "nvarchar", "char"],
|
|
514
|
+
description: "컬럼 데이터 타입 (number/numeric/int/float/decimal → Measure, 그 외 → Dimension)",
|
|
515
|
+
},
|
|
516
|
+
area: {
|
|
517
|
+
type: "string",
|
|
518
|
+
enum: ["row", "column", "data", "filter", "hidden"],
|
|
519
|
+
description: "수동 Area 배치 (생략 시 자동 배치)",
|
|
520
|
+
},
|
|
521
|
+
summaryType: {
|
|
522
|
+
type: "string",
|
|
523
|
+
enum: ["sum", "count", "average", "min", "max", "none", "distinctcount", "text"],
|
|
524
|
+
description: "집계 함수 (Measure 기본: sum, Dimension 기본: count)",
|
|
525
|
+
},
|
|
526
|
+
format: { type: "string", description: "표시 포맷 (예: {0:N0})" },
|
|
527
|
+
sortType: { type: "string", enum: ["asc", "desc", "none"], description: "정렬" },
|
|
528
|
+
width: { type: "number", description: "너비 (기본 100)" },
|
|
529
|
+
},
|
|
530
|
+
required: ["name"],
|
|
531
|
+
},
|
|
532
|
+
description: "컬럼 정의 배열",
|
|
533
|
+
},
|
|
534
|
+
autoPlace: {
|
|
535
|
+
type: "boolean",
|
|
536
|
+
description: "Area 자동 배치 (기본: true). false면 수동 area 지정 필드만 배치, 나머지 Hidden",
|
|
537
|
+
},
|
|
538
|
+
includeOptions: {
|
|
539
|
+
type: "boolean",
|
|
540
|
+
description: "iOLAPView 전체 구조(Options + Fields) 포함 여부 (기본: false)",
|
|
541
|
+
},
|
|
542
|
+
},
|
|
543
|
+
required: ["columns"],
|
|
544
|
+
},
|
|
545
|
+
},
|
|
497
546
|
{
|
|
498
547
|
name: "fix_mtsd",
|
|
499
548
|
description: "MTSD 파일을 읽어 자동 보정 규칙을 적용하고 파일을 덮어씁니다. DataSource Name→Id 참조 보정, Params Value 누락 보정, Columns Type 누락 보정, Docking/Border 필수 속성 보정을 수행합니다.",
|
|
@@ -942,6 +991,25 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
942
991
|
],
|
|
943
992
|
};
|
|
944
993
|
}
|
|
994
|
+
case "generate_olap_fields": {
|
|
995
|
+
const result = generateOlapFields(args);
|
|
996
|
+
return {
|
|
997
|
+
content: [
|
|
998
|
+
{
|
|
999
|
+
type: "text",
|
|
1000
|
+
text: JSON.stringify({
|
|
1001
|
+
success: true,
|
|
1002
|
+
fields: result.fields,
|
|
1003
|
+
iOLAPView: result.iOLAPView,
|
|
1004
|
+
summary: result.summary,
|
|
1005
|
+
warnings: result.warnings.length > 0
|
|
1006
|
+
? result.warnings
|
|
1007
|
+
: undefined,
|
|
1008
|
+
}, null, 2),
|
|
1009
|
+
},
|
|
1010
|
+
],
|
|
1011
|
+
};
|
|
1012
|
+
}
|
|
945
1013
|
case "fix_mtsd": {
|
|
946
1014
|
const filePath = args?.path;
|
|
947
1015
|
if (!filePath) {
|
package/package.json
CHANGED
|
@@ -107,14 +107,14 @@ export interface IDataSource {
|
|
|
107
107
|
Id: string;
|
|
108
108
|
/** 데이터소스의 표시 이름 */
|
|
109
109
|
Name: string;
|
|
110
|
-
/** 메타 데이터소스 사용 여부
|
|
111
|
-
UseMeta:
|
|
112
|
-
/** 쿼리 결과 캐싱 사용 여부
|
|
113
|
-
UseCache:
|
|
110
|
+
/** 메타 데이터소스 사용 여부 */
|
|
111
|
+
UseMeta: boolean;
|
|
112
|
+
/** 쿼리 결과 캐싱 사용 여부 */
|
|
113
|
+
UseCache: boolean;
|
|
114
114
|
/** 연결된 DB 커넥션 코드 */
|
|
115
115
|
ConnectionCode: string;
|
|
116
|
-
/** SQL 쿼리 암호화 여부
|
|
117
|
-
Encrypted:
|
|
116
|
+
/** SQL 쿼리 암호화 여부 */
|
|
117
|
+
Encrypted: boolean;
|
|
118
118
|
/** 데이터소스 타입 (0: DataSource, 1: MetaData, 2: Template, 3: ServerDataSource) */
|
|
119
119
|
DSType: number;
|
|
120
120
|
/** 실행할 SQL 쿼리문 */
|
package/schemas/mtsd.schema.json
CHANGED
|
@@ -98,10 +98,10 @@
|
|
|
98
98
|
"properties": {
|
|
99
99
|
"Id": { "type": "string", "description": "데이터소스의 고유 ID" },
|
|
100
100
|
"Name": { "type": "string", "description": "데이터소스의 표시 이름" },
|
|
101
|
-
"UseMeta": { "type": "
|
|
102
|
-
"UseCache": { "type": "
|
|
101
|
+
"UseMeta": { "type": "boolean", "description": "메타 데이터소스 사용 여부" },
|
|
102
|
+
"UseCache": { "type": "boolean", "description": "쿼리 결과 캐싱 사용 여부" },
|
|
103
103
|
"ConnectionCode": { "type": "string", "description": "연결된 DB 커넥션 코드" },
|
|
104
|
-
"Encrypted": { "type": "
|
|
104
|
+
"Encrypted": { "type": "boolean", "description": "SQL 쿼리 암호화 여부" },
|
|
105
105
|
"DSType": { "type": "integer", "enum": [0, 1, 2, 3], "description": "데이터소스 타입 (0:DataSource, 1:MetaData, 2:Template, 3:ServerDataSource)" },
|
|
106
106
|
"SQL": { "type": "string", "description": "실행할 SQL 쿼리문" },
|
|
107
107
|
"Params": {
|
|
@@ -117,11 +117,10 @@
|
|
|
117
117
|
"DataSourceParam": {
|
|
118
118
|
"type": "object",
|
|
119
119
|
"description": "데이터소스 파라미터",
|
|
120
|
-
"required": ["Name", "
|
|
120
|
+
"required": ["Name", "ParamType"],
|
|
121
121
|
"properties": {
|
|
122
|
-
"Name": { "type": "string" },
|
|
123
|
-
"
|
|
124
|
-
"Type": { "type": "string" }
|
|
122
|
+
"Name": { "type": "string" },
|
|
123
|
+
"ParamType": { "type": "string" }
|
|
125
124
|
}
|
|
126
125
|
},
|
|
127
126
|
"DataSourceColumn": {
|