/// <summary>
        /// Create a composite schema of both the partitioned columns and the underlying loader columns.
        /// </summary>
        /// <param name="ectx">The exception context.</param>
        /// <param name="cols">The partitioned columns.</param>
        /// <param name="subLoader">The sub loader.</param>
        /// <returns>The resulting schema.</returns>
        private Schema CreateSchema(IExceptionContext ectx, Column[] cols, IDataLoader subLoader)
        {
            Contracts.AssertValue(cols);
            Contracts.AssertValue(subLoader);

            var builder = new SchemaBuilder();

            builder.AddColumns(cols.Select(c => new Schema.DetachedColumn(c.Name, ColumnTypeExtensions.PrimitiveTypeFromKind(c.Type.Value), null)));
            var colSchema = builder.GetSchema();

            var subSchema = subLoader.Schema;

            if (subSchema.Count == 0)
            {
                return(colSchema);
            }
            else
            {
                var schemas = new Schema[]
                {
                    subSchema,
                    colSchema
                };

                return(new ZipBinding(schemas).OutputSchema);
            }
        }
            public Bindings(ModelLoadContext ctx, DatabaseLoader parent)
            {
                Contracts.AssertValue(ctx);

                // *** Binary format ***
                // int: number of columns
                // foreach column:
                //   int: id of column name
                //   byte: DataKind
                //   byte: bool of whether this is a key type
                //   for a key type:
                //     ulong: count for key range
                //   byte: bool of whether the source index is valid
                //   for a valid source index:
                //     int: source index
                int cinfo = ctx.Reader.ReadInt32();

                Contracts.CheckDecode(cinfo > 0);
                Infos = new ColInfo[cinfo];

                for (int iinfo = 0; iinfo < cinfo; iinfo++)
                {
                    string name = ctx.LoadNonEmptyString();

                    PrimitiveDataViewType itemType;
                    var kind = (InternalDataKind)ctx.Reader.ReadByte();
                    Contracts.CheckDecode(Enum.IsDefined(typeof(InternalDataKind), kind));
                    bool isKey = ctx.Reader.ReadBoolByte();
                    if (isKey)
                    {
                        ulong count;
                        Contracts.CheckDecode(KeyDataViewType.IsValidDataType(kind.ToType()));

                        count = ctx.Reader.ReadUInt64();
                        Contracts.CheckDecode(0 < count);

                        itemType = new KeyDataViewType(kind.ToType(), count);
                    }
                    else
                    {
                        itemType = ColumnTypeExtensions.PrimitiveTypeFromKind(kind);
                    }

                    int? sourceIndex    = null;
                    bool hasSourceIndex = ctx.Reader.ReadBoolByte();
                    if (hasSourceIndex)
                    {
                        sourceIndex = ctx.Reader.ReadInt32();
                    }

                    Infos[iinfo] = new ColInfo(name, sourceIndex, itemType);
                }

                OutputSchema = ComputeOutputSchema();
            }
            public Bindings(DatabaseLoader parent, Column[] cols)
            {
                Contracts.AssertNonEmpty(cols);

                using (var ch = parent._host.Start("Binding"))
                {
                    // Make sure all columns have at least one source range.
                    foreach (var col in cols)
                    {
                        if (col.Source < 0)
                        {
                            throw ch.ExceptUserArg(nameof(Column.Source), "Source column index must be non-negative");
                        }
                    }

                    Infos = new ColInfo[cols.Length];

                    // This dictionary is used only for detecting duplicated column names specified by user.
                    var nameToInfoIndex = new Dictionary <string, int>(Infos.Length);

                    for (int iinfo = 0; iinfo < Infos.Length; iinfo++)
                    {
                        var col = cols[iinfo];

                        ch.CheckNonWhiteSpace(col.Name, nameof(col.Name));
                        string name = col.Name.Trim();
                        if (iinfo == nameToInfoIndex.Count && nameToInfoIndex.ContainsKey(name))
                        {
                            ch.Info("Duplicate name(s) specified - later columns will hide earlier ones");
                        }

                        PrimitiveDataViewType itemType;
                        if (col.KeyCount != null)
                        {
                            itemType = ConstructKeyType(col.Type, col.KeyCount);
                        }
                        else
                        {
                            itemType = ColumnTypeExtensions.PrimitiveTypeFromType(col.Type.ToType());
                        }

                        Infos[iinfo] = new ColInfo(name, col.Source, itemType);

                        nameToInfoIndex[name] = iinfo;
                    }
                }
                OutputSchema = ComputeOutputSchema();
            }
            public Bindings(ModelLoadContext ctx, DatabaseLoader parent)
            {
                Contracts.AssertValue(ctx);

                // *** Binary format ***
                // int: number of columns
                // foreach column:
                //   int: id of column name
                //   byte: DataKind
                //   byte: bool of whether this is a key type
                //   for a key type:
                //     ulong: count for key range
                //   int: number of segments
                //   foreach segment:
                //     string id: name
                //     int: min
                //     int: lim
                //     byte: force vector (verWrittenCur: verIsVectorSupported)
                int cinfo = ctx.Reader.ReadInt32();

                Contracts.CheckDecode(cinfo > 0);
                Infos = new ColInfo[cinfo];

                for (int iinfo = 0; iinfo < cinfo; iinfo++)
                {
                    string name = ctx.LoadNonEmptyString();

                    PrimitiveDataViewType itemType;
                    var kind = (InternalDataKind)ctx.Reader.ReadByte();
                    Contracts.CheckDecode(Enum.IsDefined(typeof(InternalDataKind), kind));
                    bool isKey = ctx.Reader.ReadBoolByte();
                    if (isKey)
                    {
                        ulong count;
                        Contracts.CheckDecode(KeyDataViewType.IsValidDataType(kind.ToType()));

                        count = ctx.Reader.ReadUInt64();
                        Contracts.CheckDecode(0 < count);

                        itemType = new KeyDataViewType(kind.ToType(), count);
                    }
                    else
                    {
                        itemType = ColumnTypeExtensions.PrimitiveTypeFromKind(kind);
                    }

                    int cseg = ctx.Reader.ReadInt32();

                    Segment[] segs;

                    if (cseg == 0)
                    {
                        segs = null;
                    }
                    else
                    {
                        Contracts.CheckDecode(cseg > 0);
                        segs = new Segment[cseg];
                        for (int iseg = 0; iseg < cseg; iseg++)
                        {
                            string columnName = ctx.LoadStringOrNull();
                            int    min        = ctx.Reader.ReadInt32();
                            int    lim        = ctx.Reader.ReadInt32();
                            Contracts.CheckDecode(0 <= min && min < lim);
                            bool forceVector = ctx.Reader.ReadBoolByte();
                            segs[iseg] = (columnName is null) ? new Segment(min, lim, forceVector) : new Segment(columnName, forceVector);
                        }
                    }

                    // Note that this will throw if the segments are ill-structured, including the case
                    // of multiple variable segments (since those segments will overlap and overlapping
                    // segments are illegal).
                    Infos[iinfo] = ColInfo.Create(name, itemType, segs, false);
                }

                OutputSchema = ComputeOutputSchema();
            }
            public Bindings(DatabaseLoader parent, Column[] cols)
            {
                Contracts.AssertNonEmpty(cols);

                using (var ch = parent._host.Start("Binding"))
                {
                    Infos = new ColInfo[cols.Length];

                    // This dictionary is used only for detecting duplicated column names specified by user.
                    var nameToInfoIndex = new Dictionary <string, int>(Infos.Length);

                    for (int iinfo = 0; iinfo < Infos.Length; iinfo++)
                    {
                        var col = cols[iinfo];

                        ch.CheckNonWhiteSpace(col.Name, nameof(col.Name));
                        string name = col.Name.Trim();
                        if (iinfo == nameToInfoIndex.Count && nameToInfoIndex.ContainsKey(name))
                        {
                            ch.Info("Duplicate name(s) specified - later columns will hide earlier ones");
                        }

                        PrimitiveDataViewType itemType;
                        if (col.KeyCount != null)
                        {
                            itemType = ConstructKeyType(col.Type, col.KeyCount);
                        }
                        else
                        {
                            ch.CheckUserArg(Enum.IsDefined(typeof(DbType), col.Type), nameof(Column.Type), "Bad item type");
                            itemType = ColumnTypeExtensions.PrimitiveTypeFromType(col.Type.ToType());
                        }

                        Segment[] segs = null;

                        if (col.Source != null)
                        {
                            segs = new Segment[col.Source.Length];

                            for (int i = 0; i < segs.Length; i++)
                            {
                                var     range = col.Source[i];
                                Segment seg;

                                if (range.Name is null)
                                {
                                    int min = range.Min;
                                    ch.CheckUserArg(0 <= min, nameof(range.Min));

                                    int max = range.Max;
                                    ch.CheckUserArg(min <= max, nameof(range.Max));
                                    seg = new Segment(min, max + 1, range.ForceVector);
                                }
                                else
                                {
                                    string columnName = range.Name;
                                    ch.CheckUserArg(columnName != null, nameof(range.Name));
                                    seg = new Segment(columnName, range.ForceVector);
                                }

                                segs[i] = seg;
                            }
                        }

                        Infos[iinfo] = ColInfo.Create(name, itemType, segs, true);

                        nameToInfoIndex[name] = iinfo;
                    }
                }
                OutputSchema = ComputeOutputSchema();
            }
Exemple #6
0
        public static InternalSchemaDefinition Create(Type userType, SchemaDefinition userSchemaDefinition)
        {
            Contracts.AssertValue(userType);
            Contracts.AssertValueOrNull(userSchemaDefinition);

            if (userSchemaDefinition == null)
            {
                userSchemaDefinition = SchemaDefinition.Create(userType);
            }

            Column[] dstCols = new Column[userSchemaDefinition.Count];

            for (int i = 0; i < userSchemaDefinition.Count; ++i)
            {
                var col = userSchemaDefinition[i];
                if (col.MemberName == null)
                {
                    throw Contracts.ExceptParam(nameof(userSchemaDefinition), "Null field name detected in schema definition");
                }

                bool       isVector;
                Type       dataItemType;
                MemberInfo memberInfo = null;

                if (col.Generator == null)
                {
                    memberInfo = userType.GetField(col.MemberName);

                    if (memberInfo == null)
                    {
                        memberInfo = userType.GetProperty(col.MemberName);
                    }

                    if (memberInfo == null)
                    {
                        throw Contracts.ExceptParam(nameof(userSchemaDefinition), "No field or property with name '{0}' found in type '{1}'",
                                                    col.MemberName,
                                                    userType.FullName);
                    }

                    //Clause to handle the field that may be used to expose the cursor channel.
                    //This field does not need a column.
                    if ((memberInfo is FieldInfo && (memberInfo as FieldInfo).FieldType == typeof(IChannel)) ||
                        (memberInfo is PropertyInfo && (memberInfo as PropertyInfo).PropertyType == typeof(IChannel)))
                    {
                        continue;
                    }

                    GetVectorAndItemType(memberInfo, out isVector, out dataItemType);
                }
                else
                {
                    var parameterType = col.ReturnType;
                    if (parameterType == null)
                    {
                        throw Contracts.ExceptParam(nameof(userSchemaDefinition), "No return parameter found in computed column.");
                    }
                    GetVectorAndItemType("returnType", parameterType, null, out isVector, out dataItemType);
                }
                // Infer the column name.
                var colName = string.IsNullOrEmpty(col.ColumnName) ? col.MemberName : col.ColumnName;
                // REVIEW: Because order is defined, we allow duplicate column names, since producing an IDataView
                // with duplicate column names is completely legal. Possible objection is that we should make it less
                // convenient to produce "hidden" columns, since this may not be of practical use to users.

                DataViewType colType;
                if (col.ColumnType == null)
                {
                    // Infer a type as best we can.
                    PrimitiveDataViewType itemType = ColumnTypeExtensions.PrimitiveTypeFromType(dataItemType);
                    colType = isVector ? new VectorDataViewType(itemType) : (DataViewType)itemType;
                }
                else
                {
                    // Make sure that the types are compatible with the declared type, including
                    // whether it is a vector type.
                    VectorDataViewType columnVectorType = col.ColumnType as VectorDataViewType;
                    if (isVector != (columnVectorType != null))
                    {
                        throw Contracts.ExceptParam(nameof(userSchemaDefinition), "Column '{0}' is supposed to be {1}, but type of associated field '{2}' is {3}",
                                                    colName, columnVectorType != null ? "vector" : "scalar", col.MemberName, isVector ? "vector" : "scalar");
                    }
                    DataViewType itemType = columnVectorType?.ItemType ?? col.ColumnType;
                    if (itemType.RawType != dataItemType)
                    {
                        throw Contracts.ExceptParam(nameof(userSchemaDefinition), "Column '{0}' is supposed to have item type {1}, but associated field has type {2}",
                                                    colName, itemType.RawType, dataItemType);
                    }
                    colType = col.ColumnType;
                }

                dstCols[i] = col.Generator != null ?
                             new Column(colName, colType, col.Generator, col.AnnotationInfos)
                    : new Column(colName, colType, memberInfo, col.AnnotationInfos);
            }
            return(new InternalSchemaDefinition(dstCols));
        }