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.DECIMAL:
294 case ColumnProperty.IPV4:
295 case ColumnProperty.TIME:
296 column_type = Column.ColumnType.STRING;
297 column_property.Add( column_type_string );
302 column_type = Column.ColumnType.INT;
306 case ColumnProperty.INT8:
307 case ColumnProperty.INT16:
308 column_type = Column.ColumnType.INT;
309 column_property.Add( column_type_string );
314 column_type = Column.ColumnType.LONG;
318 case ColumnProperty.TIMESTAMP:
319 column_type = Column.ColumnType.LONG;
320 column_property.Add( column_type_string );
325 column_type = Column.ColumnType.FLOAT;
330 column_type = Column.ColumnType.DOUBLE;
335 column_type = Column.ColumnType.BYTES;
339 throw new KineticaException(
"Unknown data type/property: " + column_type_string );
343 if ( is_column_nulllable( $
"column_{i + 1}", dynamic_schema_json ) )
348 Column column =
new Column( column_name, column_type, column_property );
349 columns.Add( column );
352 column_properties.Add( column_name, column_property );
357 return new KineticaType(
"", columns, column_properties );
372 return fromClass( recordClass,
"", properties );
385 public static KineticaType fromClass( Type recordClass,
string label, IDictionary<
string, IList<string>> properties = null )
389 System.Reflection.PropertyInfo[] type_properties = recordClass.GetProperties( System.Reflection.BindingFlags.DeclaredOnly |
390 System.Reflection.BindingFlags.Instance |
391 System.Reflection.BindingFlags.Public );
392 Array.Sort( type_properties, delegate ( System.Reflection.PropertyInfo p1, System.Reflection.PropertyInfo p2 )
393 {
return p1.MetadataToken.CompareTo( p2.MetadataToken ); } );
396 List<Column> columns =
new List<Column>();
397 List<string> column_names =
new List<string>();
400 foreach ( var property
in type_properties )
402 string column_name =
"";
404 IList<string> column_properties = null;
405 bool is_column_nullable =
false;
408 column_name = property.Name;
410 Type prop_type = property.PropertyType;
413 if ( property.PropertyType.IsGenericType &&
414 ( property.PropertyType.GetGenericTypeDefinition() == typeof( Nullable<> ) ) )
416 is_column_nullable =
true;
418 prop_type = Nullable.GetUnderlyingType( prop_type );
422 if ( prop_type == typeof( System.String ) )
424 column_type = Column.ColumnType.STRING;
426 else if ( prop_type == typeof( System.Int32 ) )
428 column_type = Column.ColumnType.INT;
430 else if ( prop_type == typeof( System.Int64 ) )
432 column_type = Column.ColumnType.LONG;
434 else if ( prop_type == typeof(
float ) )
436 column_type = Column.ColumnType.FLOAT;
438 else if ( prop_type == typeof(
double ) )
440 column_type = Column.ColumnType.DOUBLE;
442 else if ( prop_type == typeof( byte ) )
444 column_type = Column.ColumnType.BYTES;
449 " (must be one of int, long, float, double, string, and byte)" );
452 if ( properties != null )
455 properties.TryGetValue( column_name, out column_properties );
459 column_names.Add( column_name );
462 Column column =
new Column( column_name, column_type, column_properties );
463 if ( is_column_nullable )
464 column.setIsNullable( true );
467 columns.Add( column );
471 if ( properties != null )
473 IEnumerable<string> property_keys = properties.Keys;
474 var unknown_columns = property_keys.Where( e => !column_names.Contains( e ) );
476 if ( unknown_columns.Any() )
484 kType.saveSourceType( recordClass );
500 return fromObject( recordObj,
"", properties );
513 public static KineticaType fromObject(Object recordObj,
string label =
"", IDictionary<
string, IList<string>> properties = null)
518 Type object_type = recordObj.GetType();
520 return fromClass( object_type, label, properties );
529 m_data.columns = columns;
539 public KineticaType(
string label, IList<Column> columns) : this(columns)
541 m_data.label = label;
550 public KineticaType(
string label, IList<Column> columns, IDictionary<
string, IList<string>> properties ) : this( label, columns )
552 m_properties = properties ??
new Dictionary<string, IList<string>>();
561 m_data.schemaString = typeSchema;
562 createSchemaFromString( typeSchema );
573 public KineticaType(
string label,
string typeSchema, IDictionary<
string, IList<string>> properties,
string typeID = null )
575 m_properties = properties;
577 m_data.label = label;
578 m_data.schemaString = typeSchema;
579 createSchemaFromString(typeSchema, properties);
589 public bool hasColumn(
string name) {
return m_data.columnMap.ContainsKey(name); }
600 this.m_data.sourceType = sourceType;
614 if ( this.m_data.sourceType != null )
615 kinetica.SetKineticaSourceClassToTypeMapping( this.m_data.sourceType, this );
618 CreateTypeResponse response = kinetica.createType( m_data.schemaString, m_data.label, m_properties);
619 return response.type_id;
628 private void initialize()
630 int columnCount = m_data.columns.Count;
632 if (columnCount == 0)
634 throw new ArgumentException(
"At least one column must be specified.");
637 for (
int i = 0; i < columnCount; ++i)
639 string columnName = m_data.columns[i].getName();
641 if (m_data.columnMap.ContainsKey(columnName))
643 throw new ArgumentException(
"Duplicate column name " + columnName +
" specified.");
646 m_data.columnMap[columnName] = i;
656 private void createSchemaFromString(
string typeSchema,
657 IDictionary<
string, IList<string>> properties = null)
662 m_data.schema = RecordSchema.Parse(typeSchema);
666 throw new KineticaException(ex.ToString());
669 var root = JObject.Parse(typeSchema);
671 var rootType = root[
"type"];
672 if ((null == rootType) || !rootType.ToString().Contains(
"record"))
674 throw new ArgumentException(
"Schema must be of type record.");
677 var fields = root[
"fields"];
678 if ((null == fields) || !fields.HasValues)
680 throw new ArgumentException(
"Schema has no fields.");
683 foreach (var field
in fields)
691 var fieldName = (string) field[
"name"];
692 if (
string.IsNullOrEmpty(fieldName))
694 throw new ArgumentException(
"Schema has unnamed field.");
697 if (m_data.columnMap.ContainsKey(fieldName))
699 throw new ArgumentException($
"Duplicate field name {fieldName}.");
702 var fieldType = field[
"type"];
703 if (null == fieldType)
705 throw new ArgumentException($
"Field {fieldName} has no type.");
709 bool is_column_nullable =
false;
711 if (fieldType.HasValues)
713 var fieldTypeArray = fieldType;
715 foreach (var fieldTypeElement
in fieldTypeArray.Children())
720 var fieldTypeElementString = fieldTypeElement.ToString();
722 if (!
string.IsNullOrEmpty(fieldTypeElementString))
724 if (fieldTypeElementString ==
"null" || fieldTypeElementString ==
"\"null\"")
726 is_column_nullable =
true;
731 fieldType = fieldTypeElement;
739 throw new ArgumentException(
"Field {fieldName} has invalid type.");
749 Column.ColumnType columnType;
751 if (fieldType.ToString().Equals(
"bytes") || fieldType.ToString().Equals(
"\"bytes\""))
753 columnType = Column.ColumnType.BYTES;
755 else if (fieldType.ToString().Equals(
"double") || fieldType.ToString().Equals(
"\"double\""))
757 columnType = Column.ColumnType.DOUBLE;
759 else if (fieldType.ToString().Equals(
"float") || fieldType.ToString().Equals(
"\"float\""))
761 columnType = Column.ColumnType.FLOAT;
763 else if (fieldType.ToString().Equals(
"int") || fieldType.ToString().Equals(
"\"int\""))
765 columnType = Column.ColumnType.INT;
767 else if (fieldType.ToString().Equals(
"long") || fieldType.ToString().Equals(
"\"long\""))
769 columnType = Column.ColumnType.LONG;
771 else if (fieldType.ToString().Equals(
"string") || fieldType.ToString().Equals(
"\"string\""))
773 columnType = Column.ColumnType.STRING;
777 throw new ArgumentException(
"Field {fieldName} must be of type bytes, double, float, int, long or string.");
780 IList<string> columnProperties = null;
781 if (null != properties) properties.TryGetValue(fieldName, out columnProperties);
783 if ( ( null != columnProperties ) &&
785 is_column_nullable =
true;
788 Column column =
new Column( fieldName, columnType, columnProperties );
791 column.setIsNullable( is_column_nullable );
793 m_data.columns.Add( column );
795 m_data.columnMap[fieldName] = m_data.columns.Count - 1;
802 private void createSchema()
805 if (m_data.schema != null)
812 if (m_data.schemaString != null)
816 m_data.schema = RecordSchema.Parse(m_data.schemaString);
821 throw new KineticaException(ex.ToString());
829 string schema_string =
"";
832 string schema_opening =
"{'type':'record','name':'type_name','fields':[";
834 string schema_closing =
"]}";
836 schema_string += schema_opening;
839 foreach (var column
in m_data.columns)
842 string field_name = (
"'name':'" + column.getName() +
"'");
845 string field_type =
"";
846 if (column.isNullable())
848 field_type = (
"['" + column.getTypeString() +
"','null']");
852 field_type = (
"'" + column.getTypeString() +
"'" );
854 field_type = (
"'type':" + field_type);
857 string field = (
"{" + field_name +
"," + field_type +
"},");
858 schema_string += field;
862 char[] comma = {
',' };
863 schema_string = schema_string.TrimEnd(comma);
865 schema_string += schema_closing;
870 m_data.schema = RecordSchema.Parse(schema_string);
874 throw new KineticaException(ex.ToString());
878 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 /create/type.
API to talk to Kinetica Database