@@ -13,6 +13,8 @@ const Cli = require('./../include/cli');
1313const TABLE_ISSUES = 'issues' ;
1414const TABLE_MERGE_REQUESTS = 'merge_requests' ;
1515const TABLE_TIMES = 'times' ;
16+ const TABLE_LABELS = 'labels' ;
17+ const TABLE_LABEL_GROUP = 'label_group' ;
1618
1719const COLUMNS = {
1820 [ TABLE_ISSUES ] : 'issueColumns' ,
@@ -33,8 +35,8 @@ function getGeneralColumnType(columnName) {
3335 return 'INTEGER PRIMARY KEY' ;
3436 }
3537
36- if ( [ 'iid' , 'project_id' ] . includes ( columnName ) ) {
37- return 'INTEGER' ;
38+ if ( [ 'iid' , 'project_id' , 'gid' ] . includes ( columnName ) ) {
39+ return 'INTEGER NOT NULL ' ;
3840 }
3941
4042 if ( [ 'spent' , 'total_spent' , 'total_estimate' , 'time' ] . includes ( columnName ) ) {
@@ -45,6 +47,14 @@ function getGeneralColumnType(columnName) {
4547 return 'DATE' ;
4648 }
4749
50+ if ( columnName === 'label_group' ) {
51+ return `REFERENCES ${ TABLE_LABEL_GROUP } (gid)` ;
52+ }
53+
54+ if ( columnName === 'label_id' ) {
55+ return `REFERENCES ${ TABLE_LABELS } (id)` ;
56+ }
57+
4858 // default:
4959 return 'TEXT' ;
5060}
@@ -175,6 +185,23 @@ class Sqlite extends Base {
175185 super ( config , report ) ;
176186 this . tables = new Map ( ) ;
177187 this . stats = new Map ( ) ;
188+ this . labels = new Map ( ) ;
189+ this . labelGroupSerial = 0 ;
190+ this . labelsSerial = 0 ;
191+ this . makeDefaultTables ( ) ;
192+ }
193+
194+ makeDefaultTables ( ) {
195+ this . tables . set ( TABLE_LABELS , new Table (
196+ TABLE_LABELS ,
197+ [ 'id' , 'name' ] ,
198+ [ ]
199+ ) ) ;
200+ this . tables . set ( TABLE_LABEL_GROUP , new Table (
201+ TABLE_LABEL_GROUP ,
202+ [ 'gid' , 'label_id' ] ,
203+ [ ]
204+ ) ) ;
178205 }
179206
180207 makeStats ( ) {
@@ -197,11 +224,29 @@ class Sqlite extends Base {
197224 }
198225
199226 makeIssues ( ) {
200- this . makeTable ( TABLE_ISSUES , this . report . issues ) ;
227+ const table = this . makeTable ( TABLE_ISSUES , this . report . issues ) ;
228+ const columns = this . config . get ( COLUMNS [ TABLE_ISSUES ] ) ;
229+
230+ if ( columns . includes ( 'labels' ) ) {
231+ columns . push ( 'label_group' ) ;
232+
233+ table . records . forEach ( record => {
234+ record [ columns . indexOf ( 'label_group' ) ] = this . parseLabelList ( record [ columns . indexOf ( 'labels' ) ] ) ;
235+ } ) ;
236+ }
201237 }
202238
203239 makeMergeRequests ( ) {
204- this . makeTable ( TABLE_MERGE_REQUESTS , this . report . mergeRequests ) ;
240+ const table = this . makeTable ( TABLE_MERGE_REQUESTS , this . report . mergeRequests ) ;
241+ const columns = this . config . get ( COLUMNS [ TABLE_MERGE_REQUESTS ] ) ;
242+
243+ if ( columns . includes ( 'labels' ) ) {
244+ columns . push ( 'label_group' ) ;
245+
246+ table . records . forEach ( record => {
247+ record [ columns . indexOf ( 'label_group' ) ] = this . parseLabelList ( record [ columns . indexOf ( 'labels' ) ] ) ;
248+ } ) ;
249+ }
205250 }
206251
207252 makeRecords ( ) {
@@ -214,8 +259,49 @@ class Sqlite extends Base {
214259
215260 const table = new Table ( name , columns , preparedData ) ;
216261 this . tables . set ( name , table ) ;
262+ return table ;
217263 }
218264
265+
266+ /**
267+ * Creates a normalized labels structure from a labels comma list.
268+ *
269+ * @param labels {Array<string>}
270+ * @returns {number | 'NULL' } id of the new label group
271+ */
272+ parseLabelList ( labels ) {
273+ const serial = this . labelGroupSerial ++ ;
274+
275+ if ( ! labels ) {
276+ return 'NULL' ;
277+ }
278+
279+ const records = labels
280+ . map ( label => this . getOrCreateLabelId ( label ) )
281+ . map ( labelId => [ serial , labelId ] ) ;
282+ this . tables . get ( 'label_group' ) . records . push ( ...records ) ;
283+
284+ return serial ;
285+ }
286+
287+ /**
288+ * Gets the id of a label (and create it, if it not yet exists)
289+ *
290+ * @param name
291+ * @returns {number } id of the label
292+ */
293+ getOrCreateLabelId ( name ) {
294+ if ( this . labels . has ( name ) ) {
295+ return this . labels . get ( name ) ;
296+ }
297+
298+ const serial = this . labelsSerial ++ ;
299+ this . tables . get ( 'labels' ) . records . push ( [ serial , name ] ) ;
300+ this . labels . set ( name , serial ) ;
301+ return serial ;
302+ }
303+
304+
219305 toFile ( file , resolve ) {
220306 this . db = new SqliteDatabaseAbstraction ( file ) ;
221307 this . provisionDatabase ( )
0 commit comments