otsdaq  v2_04_01
TableViewColumnInfo.cc
1 #include "otsdaq-core/TableCore/TableViewColumnInfo.h"
2 
3 #include "otsdaq-core/Macros/CoutMacros.h"
4 #include "otsdaq-core/Macros/StringMacros.h"
5 
6 #include <iostream>
7 #include <sstream>
8 #include <stdexcept>
9 
10 #include "otsdaq-core/TableCore/TableView.h"
11 
12 using namespace ots;
13 
14 // NOTE: Do NOT put '-' in static const TYPEs because it will mess up javascript handling
15 // in the web gui
16 const std::string TableViewColumnInfo::TYPE_UID = "UID";
17 
18 const std::string TableViewColumnInfo::TYPE_DATA = "Data";
19 const std::string TableViewColumnInfo::TYPE_UNIQUE_DATA = "UniqueData";
20 const std::string TableViewColumnInfo::TYPE_UNIQUE_GROUP_DATA = "UniqueGroupData";
21 const std::string TableViewColumnInfo::TYPE_MULTILINE_DATA = "MultilineData";
22 const std::string TableViewColumnInfo::TYPE_FIXED_CHOICE_DATA = "FixedChoiceData";
23 const std::string TableViewColumnInfo::TYPE_BITMAP_DATA = "BitMap";
24 
25 const std::string TableViewColumnInfo::TYPE_ON_OFF = "OnOff";
26 const std::string TableViewColumnInfo::TYPE_TRUE_FALSE = "TrueFalse";
27 const std::string TableViewColumnInfo::TYPE_YES_NO = "YesNo";
28 
29 const std::string TableViewColumnInfo::TYPE_START_CHILD_LINK = "ChildLink";
30 const std::string TableViewColumnInfo::TYPE_START_CHILD_LINK_UID = "ChildLinkUID";
31 const std::string TableViewColumnInfo::TYPE_START_CHILD_LINK_GROUP_ID =
32  "ChildLinkGroupID";
33 const std::string TableViewColumnInfo::TYPE_START_GROUP_ID = "GroupID";
34 const std::string TableViewColumnInfo::TYPE_COMMENT = "Comment";
35 const std::string TableViewColumnInfo::TYPE_AUTHOR = "Author";
36 const std::string TableViewColumnInfo::TYPE_TIMESTAMP = "Timestamp";
37 // NOTE: Do NOT put '-' in static const TYPEs because it will mess up javascript handling
38 // in the web gui
39 
40 const std::string TableViewColumnInfo::DATATYPE_NUMBER = "NUMBER";
41 const std::string TableViewColumnInfo::DATATYPE_STRING = "VARCHAR2";
42 const std::string TableViewColumnInfo::DATATYPE_TIME = "TIMESTAMP WITH TIMEZONE";
43 
44 const std::string TableViewColumnInfo::TYPE_VALUE_YES = "Yes";
45 const std::string TableViewColumnInfo::TYPE_VALUE_NO = "No";
46 const std::string TableViewColumnInfo::TYPE_VALUE_TRUE = "True";
47 const std::string TableViewColumnInfo::TYPE_VALUE_FALSE = "False";
48 const std::string TableViewColumnInfo::TYPE_VALUE_ON = "On";
49 const std::string TableViewColumnInfo::TYPE_VALUE_OFF = "Off";
50 
51 const std::string TableViewColumnInfo::DATATYPE_STRING_DEFAULT = "DEFAULT";
52 const std::string TableViewColumnInfo::DATATYPE_COMMENT_DEFAULT = "No Comment";
53 const std::string TableViewColumnInfo::DATATYPE_BOOL_DEFAULT = "0";
54 const std::string TableViewColumnInfo::DATATYPE_NUMBER_DEFAULT = "0";
55 const std::string TableViewColumnInfo::DATATYPE_TIME_DEFAULT = "0";
56 const std::string TableViewColumnInfo::DATATYPE_LINK_DEFAULT = "NO_LINK";
57 
58 const std::string TableViewColumnInfo::COL_NAME_STATUS = "Status";
59 const std::string TableViewColumnInfo::COL_NAME_PRIORITY = "Priority";
60 const std::string TableViewColumnInfo::COL_NAME_COMMENT = "CommentDescription";
61 
62 //==============================================================================
63 // TableViewColumnInfo
64 // if(capturedExceptionString) *capturedExceptionString = ""; //indicates no error found
65 // if(!capturedExceptionString) then exception is thrown on error
66 TableViewColumnInfo::TableViewColumnInfo(const std::string& type,
67  const std::string& name,
68  const std::string& storageName,
69  const std::string& dataType,
70  const std::string& dataChoicesCSV,
71  std::string* capturedExceptionString)
72  : type_(type)
73  , name_(name)
74  , storageName_(storageName)
75  , dataType_(dataType)
76  , bitMapInfoP_(0)
77 {
78  // verify type
79  if((type_ != TYPE_UID) && (type_ != TYPE_DATA) && (type_ != TYPE_UNIQUE_DATA) &&
80  (type_ != TYPE_UNIQUE_GROUP_DATA) && (type_ != TYPE_MULTILINE_DATA) &&
81  (type_ != TYPE_FIXED_CHOICE_DATA) && (type_ != TYPE_BITMAP_DATA) &&
82  (type_ != TYPE_ON_OFF) && (type_ != TYPE_TRUE_FALSE) && (type_ != TYPE_YES_NO) &&
83  (type_ != TYPE_COMMENT) && (type_ != TYPE_AUTHOR) && (type_ != TYPE_TIMESTAMP) &&
84  !isChildLink() && !isChildLinkUID() && !isChildLinkGroupID() && !isGroupID())
85  {
86  __SS__ << "The type for column " << name_ << " is " << type_
87  << ", while the only accepted types are: " << TYPE_DATA << " "
88  << TYPE_UNIQUE_DATA << " " << TYPE_UNIQUE_GROUP_DATA << " "
89  << TYPE_MULTILINE_DATA << " " << TYPE_FIXED_CHOICE_DATA << " " << TYPE_UID
90  << " " << TYPE_ON_OFF << " " << TYPE_TRUE_FALSE << " " << TYPE_YES_NO
91  << " " << TYPE_START_CHILD_LINK << "-* " << TYPE_START_CHILD_LINK_UID
92  << "-* " << TYPE_START_CHILD_LINK_GROUP_ID << "-* " << TYPE_START_GROUP_ID
93  << "-* " << std::endl;
94  if(capturedExceptionString)
95  *capturedExceptionString = ss.str();
96  else
97  __SS_THROW__;
98  }
99  else if(capturedExceptionString)
100  *capturedExceptionString = ""; // indicates no error found
101 
102  // enforce that type only
103  // allows letters, numbers, dash, underscore
104  for(unsigned int i = 0; i < type_.size(); ++i)
105  if(!((type_[i] >= 'A' && type_[i] <= 'Z') ||
106  (type_[i] >= 'a' && type_[i] <= 'z') ||
107  (type_[i] >= '0' && type_[i] <= '9') ||
108  (type_[i] == '-' || type_[i] <= '_' || type_[i] <= '.')))
109  {
110  __SS__ << "The data type for column " << name_ << " is '" << type_
111  << "'. Data types must contain only letters, numbers,"
112  << "dashes, underscores, and periods." << std::endl;
113  if(capturedExceptionString)
114  *capturedExceptionString += ss.str();
115  else
116  __SS_THROW__;
117  }
118 
119  // verify data type
120  if((dataType_ != DATATYPE_NUMBER) && (dataType_ != DATATYPE_STRING) &&
121  (dataType_ != DATATYPE_TIME))
122  {
123  __SS__ << "The data type for column " << name_ << " is " << dataType_
124  << ", while the only accepted types are: " << DATATYPE_NUMBER << " "
125  << DATATYPE_STRING << " " << DATATYPE_TIME << std::endl;
126  if(capturedExceptionString)
127  *capturedExceptionString += ss.str();
128  else
129  __SS_THROW__;
130  }
131 
132  if(dataType_.size() == 0)
133  {
134  __SS__ << "The data type for column " << name_ << " is '" << dataType_
135  << "'. Data types must contain at least 1 character." << std::endl;
136  if(capturedExceptionString)
137  *capturedExceptionString += ss.str();
138  else
139  __SS_THROW__;
140  }
141 
142  // enforce that data type only
143  // allows letters, numbers, dash, underscore
144  for(unsigned int i = 0; i < dataType_.size(); ++i)
145  if(!((dataType_[i] >= 'A' && dataType_[i] <= 'Z') ||
146  (dataType_[i] >= 'a' && dataType_[i] <= 'z') ||
147  (dataType_[i] >= '0' && dataType_[i] <= '9') ||
148  (dataType_[i] == '-' || dataType_[i] <= '_')))
149  {
150  __SS__ << "The data type for column " << name_ << " is '" << dataType_
151  << "'. Data types must contain only letters, numbers,"
152  << "dashes, and underscores." << std::endl;
153  if(capturedExceptionString)
154  *capturedExceptionString += ss.str();
155  else
156  __SS_THROW__;
157  }
158 
159  if(name_.size() == 0)
160  {
161  __SS__ << "There is a column named " << name_
162  << "'. Column names must contain at least 1 character." << std::endl;
163  if(capturedExceptionString)
164  *capturedExceptionString += ss.str();
165  else
166  __SS_THROW__;
167  }
168 
169  // enforce that col name only
170  // allows letters, numbers, dash, underscore
171  for(unsigned int i = 0; i < name_.size(); ++i)
172  if(!((name_[i] >= 'A' && name_[i] <= 'Z') ||
173  (name_[i] >= 'a' && name_[i] <= 'z') ||
174  (name_[i] >= '0' && name_[i] <= '9') ||
175  (name_[i] == '-' || name_[i] <= '_')))
176  {
177  __SS__ << "There is a column named " << name_
178  << "'. Column names must contain only letters, numbers,"
179  << "dashes, and underscores." << std::endl;
180  if(capturedExceptionString)
181  *capturedExceptionString += ss.str();
182  else
183  __SS_THROW__;
184  }
185 
186  if(storageName_.size() == 0)
187  {
188  __SS__ << "The storage name for column " << name_ << " is '" << storageName_
189  << "'. Storage names must contain at least 1 character." << std::endl;
190  if(capturedExceptionString)
191  *capturedExceptionString += ss.str();
192  else
193  __SS_THROW__;
194  }
195 
196  // enforce that col storage name only
197  // allows capital letters, numbers, dash, underscore
198  for(unsigned int i = 0; i < storageName_.size(); ++i)
199  if(!((storageName_[i] >= 'A' && storageName_[i] <= 'Z') ||
200  (storageName_[i] >= '0' && storageName_[i] <= '9') ||
201  (storageName_[i] == '-' || storageName_[i] <= '_')))
202  {
203  __SS__ << "The storage name for column " << name_ << " is '" << storageName_
204  << "'. Storage names must contain only capital letters, numbers,"
205  << "dashes, and underscores." << std::endl;
206  if(capturedExceptionString)
207  *capturedExceptionString += ss.str();
208  else
209  __SS_THROW__;
210  }
211 
212  // build data choices vector from URI encoded data
213  //__COUT__ << "dataChoicesCSV " << dataChoicesCSV << std::endl;
214  {
215  std::istringstream f(dataChoicesCSV);
216  std::string s;
217  while(getline(f, s, ','))
218  dataChoices_.push_back(StringMacros::decodeURIComponent(s));
219  // for(const auto &dc: dataChoices_)
220  // __COUT__ << dc << std::endl;
221  }
222 
223  try
224  {
225  extractBitMapInfo();
226  }
227  catch(std::runtime_error& e)
228  {
229  if(capturedExceptionString)
230  *capturedExceptionString += e.what();
231  else
232  throw;
233  }
234 
235  //__COUT__ << "dataChoicesCSV " << dataChoicesCSV << std::endl;
236 }
237 
238 //==============================================================================
239 void TableViewColumnInfo::extractBitMapInfo()
240 {
241  // create BitMapInfo if this is a bitmap column
242  if(type_ == TYPE_BITMAP_DATA)
243  {
244  if(bitMapInfoP_)
245  delete bitMapInfoP_;
246  bitMapInfoP_ = new BitMapInfo();
247 
248  // extract bitMapInfo parameters:
249  // must match TableEditor js handling:
250 
251  // [ //types => 0:string, 1:bool (default no),
252  // //2:bool (default yes), 3:color
253  //
254  // 0 0,//"Number of Rows",
255  // 1 0,//"Number of Columns",
256  // 2 0,//"Cell Bit-field Size",
257  // 3 0,//"Min-value Allowed",
258  // 4 0,//"Max-value Allowed",
259  // 5 0,//"Value step-size Allowed",
260  // 6 0,//"Display Aspect H:W",
261  // 7 3,//"Min-value Cell Color",
262  // 8 3,//"Mid-value Cell Color",
263  // 9 3,//"Max-value Cell Color",
264  // 10 3,//"Absolute Min-value Cell Color",
265  // 11 3,//"Absolute Max-value Cell Color",
266  // 12 1,//"Display Rows in Ascending Order",
267  // 13 2,//"Display Columns in Ascending Order",
268  // 14 1,//"Snake Double Rows",
269  // 15 1];//"Snake Double Columns"];
270 
271  if(dataChoices_.size() < 16)
272  {
273  __SS__ << "The Bit-Map data parameters for column " << name_
274  << " should be size 16, but is size " << dataChoices_.size()
275  << ". Bit-Map parameters should be rows, cols, cellBitSize, and min, "
276  "mid, max color."
277  << std::endl;
278  __SS_THROW__;
279  }
280 
281  sscanf(dataChoices_[0].c_str(), "%u", &(bitMapInfoP_->numOfRows_));
282  sscanf(dataChoices_[1].c_str(), "%u", &(bitMapInfoP_->numOfColumns_));
283  sscanf(dataChoices_[2].c_str(), "%u", &(bitMapInfoP_->cellBitSize_));
284 
285  sscanf(dataChoices_[3].c_str(), "%lu", &(bitMapInfoP_->minValue_));
286  sscanf(dataChoices_[4].c_str(), "%lu", &(bitMapInfoP_->maxValue_));
287  sscanf(dataChoices_[5].c_str(), "%lu", &(bitMapInfoP_->stepValue_));
288 
289  bitMapInfoP_->aspectRatio_ = dataChoices_[6];
290  bitMapInfoP_->minColor_ = dataChoices_[7];
291  bitMapInfoP_->midColor_ = dataChoices_[8];
292  bitMapInfoP_->maxColor_ = dataChoices_[9];
293  bitMapInfoP_->absMinColor_ = dataChoices_[10];
294  bitMapInfoP_->absMaxColor_ = dataChoices_[11];
295 
296  bitMapInfoP_->rowsAscending_ = dataChoices_[12] == "Yes" ? 1 : 0;
297  bitMapInfoP_->colsAscending_ = dataChoices_[13] == "Yes" ? 1 : 0;
298  bitMapInfoP_->snakeRows_ = dataChoices_[14] == "Yes" ? 1 : 0;
299  bitMapInfoP_->snakeCols_ = dataChoices_[15] == "Yes" ? 1 : 0;
300  }
301 }
302 
303 //==============================================================================
304 // private empty default constructor. Only used by assignment operator.
305 TableViewColumnInfo::TableViewColumnInfo(void) {}
306 
307 //==============================================================================
308 TableViewColumnInfo::TableViewColumnInfo(
309  const TableViewColumnInfo& c) // copy constructor because of bitmap pointer
310  : type_(c.type_)
311  , name_(c.name_)
312  , storageName_(c.storageName_)
313  , dataType_(c.dataType_)
314  , dataChoices_(c.dataChoices_)
315  , bitMapInfoP_(0)
316 {
317  // extract bitmap info if necessary
318  extractBitMapInfo();
319 }
320 
321 //==============================================================================
322 TableViewColumnInfo& TableViewColumnInfo::operator=(
323  const TableViewColumnInfo& c) // assignment operator because of bitmap pointer
324 {
325  TableViewColumnInfo* retColInfo = new TableViewColumnInfo();
326  retColInfo->type_ = c.type_;
327  retColInfo->name_ = c.name_;
328  retColInfo->storageName_ = c.storageName_;
329  retColInfo->dataType_ = c.dataType_;
330  retColInfo->dataChoices_ = c.dataChoices_;
331  retColInfo->bitMapInfoP_ = 0;
332 
333  // extract bitmap info if necessary
334  retColInfo->extractBitMapInfo();
335 
336  return *retColInfo;
337 }
338 
339 //==============================================================================
340 TableViewColumnInfo::~TableViewColumnInfo(void)
341 {
342  if(bitMapInfoP_)
343  delete bitMapInfoP_;
344 }
345 
346 //==============================================================================
347 const std::string& TableViewColumnInfo::getType(void) const { return type_; }
348 
349 //==============================================================================
350 const std::string& TableViewColumnInfo::getDefaultValue(void) const
351 {
352  if(getDataType() == TableViewColumnInfo::DATATYPE_STRING)
353  {
354  if(getType() == TableViewColumnInfo::TYPE_ON_OFF ||
355  getType() == TableViewColumnInfo::TYPE_TRUE_FALSE ||
356  getType() == TableViewColumnInfo::TYPE_YES_NO)
357  return (
358  TableViewColumnInfo::DATATYPE_BOOL_DEFAULT); // default to OFF, NO, FALSE
359  else if(isChildLink())
360  return (TableViewColumnInfo::DATATYPE_LINK_DEFAULT);
361  else if(getType() == TableViewColumnInfo::TYPE_COMMENT)
362  return (TableViewColumnInfo::DATATYPE_COMMENT_DEFAULT);
363  else
364  return (TableViewColumnInfo::DATATYPE_STRING_DEFAULT);
365  }
366  else if(getDataType() == TableViewColumnInfo::DATATYPE_NUMBER)
367  return (TableViewColumnInfo::DATATYPE_NUMBER_DEFAULT);
368  else if(getDataType() == TableViewColumnInfo::DATATYPE_TIME)
369  return (TableViewColumnInfo::DATATYPE_TIME_DEFAULT);
370  else
371  {
372  __SS__ << "\tUnrecognized View data type: " << getDataType() << std::endl;
373  __COUT_ERR__ << "\n" << ss.str();
374  __SS_THROW__;
375  }
376 }
377 
378 //==============================================================================
379 std::vector<std::string> TableViewColumnInfo::getAllTypesForGUI(void)
380 {
381  std::vector<std::string> all;
382  all.push_back(TYPE_DATA);
383  all.push_back(TYPE_UNIQUE_DATA);
384  all.push_back(TYPE_UNIQUE_GROUP_DATA);
385  all.push_back(TYPE_FIXED_CHOICE_DATA);
386  all.push_back(TYPE_MULTILINE_DATA);
387  all.push_back(TYPE_BITMAP_DATA);
388  all.push_back(TYPE_ON_OFF);
389  all.push_back(TYPE_TRUE_FALSE);
390  all.push_back(TYPE_YES_NO);
391  all.push_back(TYPE_START_CHILD_LINK_UID);
392  all.push_back(TYPE_START_CHILD_LINK_GROUP_ID);
393  all.push_back(TYPE_START_CHILD_LINK);
394  all.push_back(TYPE_START_GROUP_ID);
395  return all;
396 }
397 
398 //==============================================================================
399 std::vector<std::string> TableViewColumnInfo::getAllDataTypesForGUI(void)
400 {
401  std::vector<std::string> all;
402  all.push_back(DATATYPE_STRING);
403  all.push_back(DATATYPE_NUMBER);
404  all.push_back(DATATYPE_TIME);
405  return all;
406 }
407 
408 //==============================================================================
409 // map of datatype,type to default value
410 std::map<std::pair<std::string, std::string>, std::string>
411 TableViewColumnInfo::getAllDefaultsForGUI(void)
412 {
413  std::map<std::pair<std::string, std::string>, std::string> all;
414  all[std::pair<std::string, std::string>(DATATYPE_NUMBER, "*")] =
415  DATATYPE_NUMBER_DEFAULT;
416  all[std::pair<std::string, std::string>(DATATYPE_TIME, "*")] = DATATYPE_TIME_DEFAULT;
417 
418  all[std::pair<std::string, std::string>(DATATYPE_STRING, TYPE_ON_OFF)] =
419  DATATYPE_BOOL_DEFAULT;
420  all[std::pair<std::string, std::string>(DATATYPE_STRING, TYPE_TRUE_FALSE)] =
421  DATATYPE_BOOL_DEFAULT;
422  all[std::pair<std::string, std::string>(DATATYPE_STRING, TYPE_YES_NO)] =
423  DATATYPE_BOOL_DEFAULT;
424 
425  all[std::pair<std::string, std::string>(DATATYPE_STRING, TYPE_START_CHILD_LINK)] =
426  DATATYPE_LINK_DEFAULT;
427  all[std::pair<std::string, std::string>(DATATYPE_STRING, "*")] =
428  DATATYPE_STRING_DEFAULT;
429  return all;
430 }
431 
432 //==============================================================================
433 // isBoolType
434 const bool TableViewColumnInfo::isBoolType(void) const
435 {
436  return (type_ == TYPE_ON_OFF || type_ == TYPE_TRUE_FALSE || type_ == TYPE_YES_NO);
437 } // end isBoolType()
438 
439 //==============================================================================
440 // isNumberDataType
441 const bool TableViewColumnInfo::isNumberDataType(void) const
442 {
443  return (dataType_ == DATATYPE_NUMBER);
444 } // end isBoolType()
445 
446 //==============================================================================
447 const std::string& TableViewColumnInfo::getName(void) const { return name_; }
448 
449 //==============================================================================
450 const std::string& TableViewColumnInfo::getStorageName(void) const
451 {
452  return storageName_;
453 }
454 
455 //==============================================================================
456 const std::string& TableViewColumnInfo::getDataType(void) const { return dataType_; }
457 
458 //==============================================================================
459 const std::vector<std::string>& TableViewColumnInfo::getDataChoices(void) const
460 {
461  return dataChoices_;
462 }
463 
464 //==============================================================================
465 // getBitMapInfo
466 // uses dataChoices CSV fields if type is TYPE_BITMAP_DATA
467 const TableViewColumnInfo::BitMapInfo& TableViewColumnInfo::getBitMapInfo(void) const
468 {
469  if(bitMapInfoP_)
470  return *bitMapInfoP_;
471 
472  // throw error at this point!
473  {
474  __SS__ << "getBitMapInfo request for non-BitMap column of type: " << getType()
475  << std::endl;
476  __COUT_ERR__ << "\n" << ss.str();
477  __SS_THROW__;
478  }
479 }
480 
481 //==============================================================================
482 // isChildLink
483 // note: TYPE_START_CHILD_LINK index may be a subset of UID and GROUP_ID
484 // so don't allow alpha character immediately after
485 const bool TableViewColumnInfo::isChildLink(void) const
486 {
487  return (type_.find(TYPE_START_CHILD_LINK) == 0 &&
488  type_.length() > TYPE_START_CHILD_LINK.length() &&
489  type_[TYPE_START_CHILD_LINK.length()] == '-');
490 }
491 
492 //==============================================================================
493 // isChildLinkUID
494 // note: TYPE_START_CHILD_LINK index may be a subset of UID and GROUP_ID
495 // so don't allow alpha character immediately after
496 const bool TableViewColumnInfo::isChildLinkUID(void) const
497 {
498  return (type_.find(TYPE_START_CHILD_LINK_UID) == 0 &&
499  type_.length() > TYPE_START_CHILD_LINK_UID.length() &&
500  type_[TYPE_START_CHILD_LINK_UID.length()] == '-');
501 }
502 
503 //==============================================================================
504 // isChildLinkGroupID
505 // note: TYPE_START_CHILD_LINK index may be a subset of UID and GROUP_ID
506 // so don't allow alpha character immediately after
507 const bool TableViewColumnInfo::isChildLinkGroupID(void) const
508 {
509  return (type_.find(TYPE_START_CHILD_LINK_GROUP_ID) == 0 &&
510  type_.length() > TYPE_START_CHILD_LINK_GROUP_ID.length() &&
511  type_[TYPE_START_CHILD_LINK_GROUP_ID.length()] == '-');
512 }
513 
514 //==============================================================================
515 // isGroupID
516 // note: TYPE_START_CHILD_LINK index may be a subset of UID and GROUP_ID
517 // so don't allow alpha character immediately after in group index
518 const bool TableViewColumnInfo::isGroupID(void) const
519 {
520  return (type_.find(TYPE_START_GROUP_ID) == 0 &&
521  type_.length() > TYPE_START_GROUP_ID.length() &&
522  type_[TYPE_START_GROUP_ID.length()] == '-');
523 }
524 
525 //==============================================================================
526 // isUID
527 const bool TableViewColumnInfo::isUID(void) const { return (type_ == TYPE_UID); }
528 
529 //==============================================================================
530 // getChildLinkIndex
531 std::string TableViewColumnInfo::getChildLinkIndex(void) const
532 {
533  // note: +1 to skip '-'
534  if(isChildLink())
535  return type_.substr(TYPE_START_CHILD_LINK.length() + 1);
536  else if(isChildLinkUID())
537  return type_.substr(TYPE_START_CHILD_LINK_UID.length() + 1);
538  else if(isChildLinkGroupID())
539  return type_.substr(TYPE_START_CHILD_LINK_GROUP_ID.length() + 1);
540  else if(isGroupID())
541  return type_.substr(TYPE_START_GROUP_ID.length() + 1);
542  else
543  {
544  __SS__
545  << ("Requesting a Link Index from a column that is not a child link member!")
546  << std::endl;
547  __COUT_ERR__ << ss.str();
548  __SS_THROW__;
549  }
550 }