2 using System.Collections.Generic;
5 using Newtonsoft.Json.Linq;
15 BYTES = Avro.EnumSchema.Type.Bytes,
16 DOUBLE = Avro.EnumSchema.Type.Double,
17 FLOAT = Avro.EnumSchema.Type.Float,
18 INT = Avro.EnumSchema.Type.Int,
19 LONG = Avro.EnumSchema.Type.Long,
20 STRING = Avro.EnumSchema.Type.String,
21 DEFAULT = Avro.EnumSchema.Type.Error
24 private string m_name;
26 private bool m_isNullable;
27 private IList<string> m_properties;
40 m_properties = properties ??
new List<string>();
49 public string getName() {
return m_name; }
69 internal void setIsNullable(
bool val ) { m_isNullable = val; }
79 case ColumnType.BYTES:
81 case ColumnType.DOUBLE:
83 case ColumnType.FLOAT:
89 case ColumnType.STRING:
96 private void initialize()
98 if (
string.IsNullOrEmpty(m_name))
100 throw new ArgumentException(
"Name must not be empty.");
105 case ColumnType.BYTES:
106 case ColumnType.DOUBLE:
107 case ColumnType.FLOAT:
109 case ColumnType.LONG:
110 case ColumnType.STRING:
114 throw new ArgumentException(
"Column " + m_name +
" must be of type BYTES, DOUBLE, FLOAT, INT, LONG or STRING.");
117 foreach (var it
in m_properties)
119 if (
string.IsNullOrEmpty(it))
121 throw new ArgumentException(
"Properties must not be empty.");
124 if (!m_isNullable && (it == ColumnProperty.NULLABLE))
133 return $
"{m_name} ({m_type.ToString()})";
137 private class TypeData
140 public IList<Column> columns =
new List<Column>();
141 public Dictionary<string, int> columnMap =
new Dictionary<string, int>();
142 public string schemaString = null;
143 public Schema schema = null;
144 public Type sourceType = null;
147 private TypeData m_data =
new TypeData();
148 private IDictionary<string, IList<string>> m_properties =
new Dictionary<string, IList<string>>();
149 private string m_type_id = null;
159 var response = kinetica.showTable(tableName);
160 var typeIdCount = response.type_ids.Count;
162 if (typeIdCount == 0)
167 string typeID = response.type_ids[0];
170 for (
int i = 1; i < typeIdCount; ++i)
172 if (response.type_ids[i] != typeID)
179 return new KineticaType(response.type_labels[0], response.type_schemas[0], response.properties[0], typeID );
190 var response = kinetica.showTypes(typeId,
"");
192 if (response.type_ids.Count < 1)
197 return new KineticaType(response.labels[0], response.type_schemas[0], response.properties[0]);
209 Object[] column_headers, Object[] column_types )
212 if ( column_headers.Length != column_types.Length )
213 throw new KineticaException(
"List of column names and types are not of the same length." );
216 JObject dynamic_schema_json;
219 dynamic_schema_json = JObject.Parse( dynamic_table_schema_string );
221 catch ( Exception ex )
229 var is_column_nulllable =
new Func<string, JObject, bool>( (column_name, schema_json) => {
231 bool found_field =
false;
232 foreach ( var field
in schema_json[
"fields"] )
234 if ( (
string)field[
"name" ] == column_name )
240 var type_element = field[
"type"][
"items"];
241 if ( type_element is JValue )
244 if ( (type_element is JArray) && ((string)((JArray)type_element)[ 1 ] ==
"null") )
250 throw new KineticaException( $
"Could not find the field named '{column_name}'" );
256 IList<Column> columns =
new List<Column>();
257 IDictionary<string, IList<string>> column_properties =
new Dictionary<string, IList<string>>();
258 for (
int i = 0; i < column_headers.Length; ++i )
261 string column_name = column_headers[ i ].ToString();
265 string column_type_string = column_types[ i ].ToString();
269 IList<string> column_property =
new List<string>();
275 switch ( column_type_string )
279 column_type = Column.ColumnType.STRING;
283 case ColumnProperty.CHAR1:
284 case ColumnProperty.CHAR2:
285 case ColumnProperty.CHAR4:
286 case ColumnProperty.CHAR8:
287 case ColumnProperty.CHAR16:
288 case ColumnProperty.CHAR32:
289 case ColumnProperty.CHAR64:
290 case ColumnProperty.CHAR128:
291 case ColumnProperty.CHAR256:
292 case ColumnProperty.DATE:
293 case ColumnProperty.DATETIME:
294 case ColumnProperty.DECIMAL:
295 case ColumnProperty.IPV4:
296 case ColumnProperty.TIME:
297 column_type = Column.ColumnType.STRING;
298 column_property.Add( column_type_string );
303 column_type = Column.ColumnType.INT;
307 case ColumnProperty.INT8:
308 case ColumnProperty.INT16:
309 column_type = Column.ColumnType.INT;
310 column_property.Add( column_type_string );
315 column_type = Column.ColumnType.LONG;
319 case ColumnProperty.TIMESTAMP:
320 column_type = Column.ColumnType.LONG;
321 column_property.Add( column_type_string );
326 column_type = Column.ColumnType.FLOAT;
331 column_type = Column.ColumnType.DOUBLE;
336 column_type = Column.ColumnType.BYTES;
340 throw new KineticaException(
"Unknown data type/property: " + column_type_string );
344 if ( is_column_nulllable( $
"column_{i + 1}", dynamic_schema_json ) )
349 Column column =
new Column( column_name, column_type, column_property );
350 columns.Add( column );
353 column_properties.Add( column_name, column_property );
358 return new KineticaType(
"", columns, column_properties );
380 return fromClass( recordClass,
"", properties );
393 public static KineticaType fromClass( Type recordClass,
string label, IDictionary<
string, IList<string>> properties = null )
397 System.Reflection.PropertyInfo[] type_properties = recordClass.GetProperties( System.Reflection.BindingFlags.DeclaredOnly |
398 System.Reflection.BindingFlags.Instance |
399 System.Reflection.BindingFlags.Public );
400 Array.Sort( type_properties, delegate ( System.Reflection.PropertyInfo p1, System.Reflection.PropertyInfo p2 )
401 {
return p1.MetadataToken.CompareTo( p2.MetadataToken ); } );
404 List<Column> columns =
new List<Column>();
405 List<string> column_names =
new List<string>();
408 foreach ( var property
in type_properties )
410 string column_name =
"";
412 IList<string> column_properties = null;
413 bool is_column_nullable =
false;
416 column_name = property.Name;
418 Type prop_type = property.PropertyType;
421 if ( property.PropertyType.IsGenericType &&
422 ( property.PropertyType.GetGenericTypeDefinition() == typeof( Nullable<> ) ) )
424 is_column_nullable =
true;
426 prop_type = Nullable.GetUnderlyingType( prop_type );
430 if ( prop_type == typeof( System.String ) )
432 column_type = Column.ColumnType.STRING;
434 else if ( prop_type == typeof( System.Int32 ) )
436 column_type = Column.ColumnType.INT;
438 else if ( prop_type == typeof( System.Int64 ) )
440 column_type = Column.ColumnType.LONG;
442 else if ( prop_type == typeof(
float ) )
444 column_type = Column.ColumnType.FLOAT;
446 else if ( prop_type == typeof(
double ) )
448 column_type = Column.ColumnType.DOUBLE;
450 else if ( prop_type == typeof( byte ) )
452 column_type = Column.ColumnType.BYTES;
457 " (must be one of int, long, float, double, string, and byte)" );
460 if ( properties != null )
463 properties.TryGetValue( column_name, out column_properties );
467 column_names.Add( column_name );
470 Column column =
new Column( column_name, column_type, column_properties );
471 if ( is_column_nullable )
472 column.setIsNullable( true );
475 columns.Add( column );
479 if ( properties != null )
481 IEnumerable<string> property_keys = properties.Keys;
482 var unknown_columns = property_keys.Where( e => !column_names.Contains( e ) );
484 if ( unknown_columns.Any() )
492 kType.saveSourceType( recordClass );
508 return fromObject( recordObj,
"", properties );
521 public static KineticaType fromObject(Object recordObj,
string label =
"", IDictionary<
string, IList<string>> properties = null)
526 Type object_type = recordObj.GetType();
528 return fromClass( object_type, label, properties );
537 m_data.columns = columns;
547 public KineticaType(
string label, IList<Column> columns) : this(columns)
549 m_data.label = label;
558 public KineticaType(
string label, IList<Column> columns, IDictionary<
string, IList<string>> properties ) : this( label, columns )
560 m_properties = properties ??
new Dictionary<string, IList<string>>();
569 m_data.schemaString = typeSchema;
570 createSchemaFromString( typeSchema );
581 public KineticaType(
string label,
string typeSchema, IDictionary<
string, IList<string>> properties,
string typeID = null )
583 m_properties = properties;
585 m_data.label = label;
586 m_data.schemaString = typeSchema;
587 createSchemaFromString(typeSchema, properties);
597 public bool hasColumn(
string name) {
return m_data.columnMap.ContainsKey(name); }
608 this.m_data.sourceType = sourceType;
622 if ( this.m_data.sourceType != null )
623 kinetica.SetKineticaSourceClassToTypeMapping( this.m_data.sourceType, this );
626 CreateTypeResponse response = kinetica.createType( m_data.schemaString, m_data.label, m_properties);
627 return response.type_id;
636 private void initialize()
638 int columnCount = m_data.columns.Count;
640 if (columnCount == 0)
642 throw new ArgumentException(
"At least one column must be specified.");
645 for (
int i = 0; i < columnCount; ++i)
647 string columnName = m_data.columns[i].getName();
649 if (m_data.columnMap.ContainsKey(columnName))
651 throw new ArgumentException(
"Duplicate column name " + columnName +
" specified.");
654 m_data.columnMap[columnName] = i;
664 private void createSchemaFromString(
string typeSchema,
665 IDictionary<
string, IList<string>> properties = null)
670 m_data.schema = RecordSchema.Parse(typeSchema);
674 throw new KineticaException(ex.ToString());
677 var root = JObject.Parse(typeSchema);
679 var rootType = root[
"type"];
680 if ((null == rootType) || !rootType.ToString().Contains(
"record"))
682 throw new ArgumentException(
"Schema must be of type record.");
685 var fields = root[
"fields"];
686 if ((null == fields) || !fields.HasValues)
688 throw new ArgumentException(
"Schema has no fields.");
691 foreach (var field
in fields)
699 var fieldName = (string) field[
"name"];
700 if (
string.IsNullOrEmpty(fieldName))
702 throw new ArgumentException(
"Schema has unnamed field.");
705 if (m_data.columnMap.ContainsKey(fieldName))
707 throw new ArgumentException($
"Duplicate field name {fieldName}.");
710 var fieldType = field[
"type"];
711 if (null == fieldType)
713 throw new ArgumentException($
"Field {fieldName} has no type.");
717 bool is_column_nullable =
false;
719 if (fieldType.HasValues)
721 var fieldTypeArray = fieldType;
723 foreach (var fieldTypeElement
in fieldTypeArray.Children())
728 var fieldTypeElementString = fieldTypeElement.ToString();
730 if (!
string.IsNullOrEmpty(fieldTypeElementString))
732 if (fieldTypeElementString ==
"null" || fieldTypeElementString ==
"\"null\"")
734 is_column_nullable =
true;
739 fieldType = fieldTypeElement;
747 throw new ArgumentException(
"Field {fieldName} has invalid type.");
757 Column.ColumnType columnType;
759 if (fieldType.ToString().Equals(
"bytes") || fieldType.ToString().Equals(
"\"bytes\""))
761 columnType = Column.ColumnType.BYTES;
763 else if (fieldType.ToString().Equals(
"double") || fieldType.ToString().Equals(
"\"double\""))
765 columnType = Column.ColumnType.DOUBLE;
767 else if (fieldType.ToString().Equals(
"float") || fieldType.ToString().Equals(
"\"float\""))
769 columnType = Column.ColumnType.FLOAT;
771 else if (fieldType.ToString().Equals(
"int") || fieldType.ToString().Equals(
"\"int\""))
773 columnType = Column.ColumnType.INT;
775 else if (fieldType.ToString().Equals(
"long") || fieldType.ToString().Equals(
"\"long\""))
777 columnType = Column.ColumnType.LONG;
779 else if (fieldType.ToString().Equals(
"string") || fieldType.ToString().Equals(
"\"string\""))
781 columnType = Column.ColumnType.STRING;
785 throw new ArgumentException(
"Field {fieldName} must be of type bytes, double, float, int, long or string.");
788 IList<string> columnProperties = null;
789 if (null != properties) properties.TryGetValue(fieldName, out columnProperties);
791 if ( ( null != columnProperties ) &&
793 is_column_nullable =
true;
796 Column column =
new Column( fieldName, columnType, columnProperties );
799 column.setIsNullable( is_column_nullable );
801 m_data.columns.Add( column );
803 m_data.columnMap[fieldName] = m_data.columns.Count - 1;
810 private void createSchema()
813 if (m_data.schema != null)
820 if (m_data.schemaString != null)
824 m_data.schema = RecordSchema.Parse(m_data.schemaString);
829 throw new KineticaException(ex.ToString());
837 string schema_string =
"";
840 string schema_opening =
"{'type':'record','name':'type_name','fields':[";
842 string schema_closing =
"]}";
844 schema_string += schema_opening;
847 foreach (var column
in m_data.columns)
850 string field_name = (
"'name':'" + column.getName() +
"'");
853 string field_type =
"";
854 if (column.isNullable())
856 field_type = (
"['" + column.getTypeString() +
"','null']");
860 field_type = (
"'" + column.getTypeString() +
"'" );
862 field_type = (
"'type':" + field_type);
865 string field = (
"{" + field_name +
"," + field_type +
"},");
866 schema_string += field;
870 char[] comma = {
',' };
871 schema_string = schema_string.TrimEnd(comma);
873 schema_string += schema_closing;
878 m_data.schema = RecordSchema.Parse(schema_string);
882 throw new KineticaException(ex.ToString());
886 m_data.schemaString = m_data.schema.ToString();
ColumnType getType()
Returns the enumeration for the column type.
bool hasColumn(string name)
KineticaType(string typeSchema)
Create a KineticaType object using the string-formatted schema for the type.
static KineticaType fromObject(Object recordObj, string label="", IDictionary< string, IList< string >> properties=null)
Create a KineticaType object from properties of a record object and Kinetica column properties...
KineticaType(string label, IList< Column > columns)
Create a KineticaType object with the given column and label information.
int getColumnIndex(string name)
static KineticaType fromTable(Kinetica kinetica, string tableName)
Create a KineticaType object based on an existing table in the database.
static KineticaType fromTypeID(Kinetica kinetica, string typeId)
Create a KineticaType object based on an existing type in the database.
Column getColumn(int index)
string getTypeString()
Returns the string format of the data type.
KineticaType(string label, IList< Column > columns, IDictionary< string, IList< string >> properties)
Create a KineticaType object with the given column, label, and property information.
Column(string name, ColumnType type, IList< string > properties=null)
Creates a Column object from the given name, type, and properties.
IList< string > getProperties()
Returns the properties for the column.
IList< Column > getColumns()
static KineticaType fromClass(Type recordClass, string label, IDictionary< string, IList< string >> properties=null)
Create a KineticaType object from properties of a record class and Kinetica column properties...
void saveSourceType(Type sourceType)
Saves the given type as this KineticaType's source type.
static KineticaType fromClass(Type recordClass, IDictionary< string, IList< string >> properties=null)
Create a KineticaType object from properties of a record class and Kinetica column properties...
KineticaType(string label, string typeSchema, IDictionary< string, IList< string >> properties, string typeID=null)
Create a KineticaType object using the string-formatted schema and properties for its columns...
bool isNullable()
Returns if the column is nullable.
Column getColumn(string name)
static KineticaType fromObject(Object recordObj, IDictionary< string, IList< string >> properties=null)
Create a KineticaType object from properties of a record object and Kinetica column properties...
string create(Kinetica kinetica)
Given a handle to the server, creates a type in the database based on this data type.
string getName()
Returns the name of the column.
static KineticaType fromDynamicSchema(string dynamic_table_schema_string, Object[] column_headers, Object[] column_types)
Create a KineticaType object based on information provided in a dynamic schema.
override string ToString()
KineticaType(IList< Column > columns)
Create a KineticaType object with the given column information.
const string NULLABLE
This property indicates that this column is nullable.
A set of results returned by Kinetica.createType(string,string,IDictionary{string, IList{string}},IDictionary{string, string}).
API to talk to Kinetica Database