// // The link map allow to have as key the types: // STRING,SHORT,INTEGER,LONG,BYTE,DATE,DECIMAL,DATETIME,DATA,FLOAT,DOUBLE // the serialization of the linkmap is a list of entry // // +----------------------------+ // | values:link_map_entry[] | // +----------------------------+ // // link_map_entry structure // // +--------------+------------------+------------+ // | keyType:byte | keyValue:byte[] | link:LINK | // +--------------+------------------+------------+ // // keyType - is the type of the key, can be only one of the listed type. // keyValue - the value of the key serialized with the serializer of the type // link - the link value stored with the formant of a LINK // // TODO: right now only supporting string keys, but need to support the // datatypes listed above (also for EmbeddedMaps) // func (serde ORecordSerializerV0) writeLinkMap(buf *obuf.WriteBuf, m map[string]*oschema.OLink) error { // number of entries in the map err := varint.EncodeAndWriteVarInt32(buf, int32(len(m))) if err != nil { return oerror.NewTrace(err) } for k, v := range m { // keyType err = rw.WriteByte(buf, byte(oschema.STRING)) if err != nil { return oerror.NewTrace(err) } // keyValue err = varint.WriteString(buf, k) if err != nil { return oerror.NewTrace(err) } // link err = serde.writeLink(buf, v) if err != nil { return oerror.NewTrace(err) } } return nil }
// // writeEmbeddedMap serializes the EMBEDDEDMAP type. Currently, OrientDB only uses string // types for the map keys, so that is an assumption of this method as well. // func (serde ORecordSerializerV0) writeEmbeddedMap(buf *obuf.WriteBuf, m oschema.OEmbeddedMap) error { // number of entries in the map err := varint.EncodeAndWriteVarInt32(buf, int32(m.Len())) if err != nil { return oerror.NewTrace(err) } ptrPos := make([]int, 0, m.Len()) // position in buf where data ptr int needs to be written // TODO: do the map entries have to be written in any particular order? I will assume no for now keys, vals, types := m.All() /* ---[ write embedded map header ]--- */ for i, k := range keys { // key type err = rw.WriteByte(buf, byte(oschema.STRING)) if err != nil { return oerror.NewTrace(err) } // write the key value err = varint.WriteString(buf, k) if err != nil { return oerror.NewTrace(err) } ptrPos = append(ptrPos, buf.Len()) buf.Skip(4) // placeholder integer for data ptr dataType := types[i] if dataType == oschema.UNKNOWN { dataType = getDataType(vals[i]) // TODO: not sure this is necessary } // write data type of the data err = rw.WriteByte(buf, byte(dataType)) if err != nil { return oerror.NewTrace(err) } } /* ---[ write embedded map data values ]--- */ for i := 0; i < len(vals); i++ { currPos := buf.Len() buf.Seek(uint(ptrPos[i])) err = rw.WriteInt(buf, int32(currPos)) if err != nil { return oerror.NewTrace(err) } buf.Seek(uint(currPos)) err = serde.writeDataValue(buf, vals[i], types[i]) if err != nil { return oerror.NewTrace(err) } } return nil }
// // +-----------------+-----------------+ // |clusterId:varint | recordId:varInt | // +-----------------+-----------------+ // func (serde ORecordSerializerV0) writeLink(buf *obuf.WriteBuf, lnk *oschema.OLink) error { err := varint.EncodeAndWriteVarInt32(buf, int32(lnk.RID.ClusterID)) if err != nil { return oerror.NewTrace(err) } err = varint.EncodeAndWriteVarInt64(buf, lnk.RID.ClusterPos) if err != nil { return oerror.NewTrace(err) } return nil }
// // +-------------+-------------------+ // | size:varint | collection:LINK[] | // +-------------+-------------------+ // func (serde ORecordSerializerV0) writeLinkList(buf *obuf.WriteBuf, lnks []*oschema.OLink) error { // number of entries in the list err := varint.EncodeAndWriteVarInt32(buf, int32(len(lnks))) if err != nil { return oerror.NewTrace(err) } for _, lnk := range lnks { err = serde.writeLink(buf, lnk) if err != nil { return oerror.NewTrace(err) } } return nil }
// // Serialization format for EMBEDDEDLIST and EMBEDDEDSET // +-------------+------------+-------------------+ // |size:varInt | type:Otype | items:item_data[] | // +-------------+------------+-------------------+ // // The item_data data structure is: // +------------------+--------------+ // | data_type:OType | data:byte[] | // +------------------+--------------+ // func (serde ORecordSerializerV0) serializeEmbeddedCollection(buf *obuf.WriteBuf, ls oschema.OEmbeddedList) error { err := varint.EncodeAndWriteVarInt32(buf, int32(ls.Len())) if err != nil { return oerror.NewTrace(err) } // following the lead of the Java driver, you don't specify the type of the list overall // (I tried to and it doesn't work, at least with OrientDB-2.0.1) err = rw.WriteByte(buf, byte(oschema.ANY)) if err != nil { return oerror.NewTrace(err) } for _, val := range ls.Values() { buf.WriteByte(byte(ls.Type())) err = serde.writeDataValue(buf, val, ls.Type()) if err != nil { return oerror.NewTrace(err) } } return nil }
// // writeDataValue is part of the Serialize functionality // TODO: change name to writeSingleValue ? // func (serde ORecordSerializerV0) writeDataValue(buf *obuf.WriteBuf, value interface{}, datatype oschema.ODataType) (err error) { switch datatype { case oschema.STRING: err = varint.WriteString(buf, value.(string)) ogl.Debugf("DEBUG STR: -writeDataVal val: %v\n", value.(string)) // DEBUG case oschema.BOOLEAN: err = rw.WriteBool(buf, value.(bool)) ogl.Debugf("DEBUG BOOL: -writeDataVal val: %v\n", value.(bool)) // DEBUG case oschema.INTEGER: var i32val int32 i32val, err = toInt32(value) if err == nil { err = varint.EncodeAndWriteVarInt32(buf, i32val) // TODO: are serialized integers ALWAYS varint encoded? ogl.Debugf("DEBUG INT: -writeDataVal val: %v\n", i32val) // DEBUG } case oschema.SHORT: // TODO: needs toInt16 conversion fn err = varint.EncodeAndWriteVarInt32(buf, int32(value.(int16))) ogl.Debugf("DEBUG SHORT: -writeDataVal val: %v\n", value.(int16)) // DEBUG case oschema.LONG: var i64val int64 i64val, err = toInt64(value) if err == nil { err = varint.EncodeAndWriteVarInt64(buf, i64val) // TODO: are serialized longs ALWAYS varint encoded? ogl.Debugf("DEBUG LONG: -writeDataVal val: %v\n", i64val) // DEBUG } case oschema.FLOAT: var f32 float32 f32, err = toFloat32(value) if err == nil { err = rw.WriteFloat(buf, f32) } ogl.Debugf("DEBUG FLOAT: -writeDataVal val: %v\n", value) // DEBUG case oschema.DOUBLE: var f64 float64 f64, err = toFloat64(value) if err == nil { err = rw.WriteDouble(buf, f64) } ogl.Debugf("DEBUG DOUBLE: -writeDataVal val: %v\n", value.(float64)) // DEBUG case oschema.DATETIME: err = writeDateTime(buf, value) ogl.Debugf("DEBUG DATETIME: -writeDataVal val: %v\n", value) // DEBUG case oschema.DATE: err = writeDate(buf, value) ogl.Debugf("DEBUG DATE: -writeDataVal val: %v\n", value) // DEBUG case oschema.BINARY: err = varint.WriteBytes(buf, value.([]byte)) ogl.Debugf("DEBUG BINARY: -writeDataVal val: %v\n", value.([]byte)) // DEBUG case oschema.EMBEDDED: err = serde.serializeDocument(buf, value.(*oschema.ODocument)) ogl.Debugf("DEBUG EMBEDDED: -writeDataVal val: %v\n", value) // DEBUG case oschema.EMBEDDEDLIST: err = serde.serializeEmbeddedCollection(buf, value.(oschema.OEmbeddedList)) ogl.Debugf("DEBUG EMBD-LIST: -writeDataVal val: %v\n", value) // DEBUG case oschema.EMBEDDEDSET: err = serde.serializeEmbeddedCollection(buf, value.(oschema.OEmbeddedList)) ogl.Debugf("DEBUG EMBD-SET: -writeDataVal val: %v\n", value) // DEBUG case oschema.EMBEDDEDMAP: err = serde.writeEmbeddedMap(buf, value.(oschema.OEmbeddedMap)) ogl.Debugf("DEBUG EMBEDDEDMAP: val %v\n", value.(oschema.OEmbeddedMap)) case oschema.LINK: err = serde.writeLink(buf, value.(*oschema.OLink)) ogl.Debugf("DEBUG LINK: val %v\n", value) // DEBUG case oschema.LINKLIST: err = serde.writeLinkList(buf, value.([]*oschema.OLink)) ogl.Debugf("DEBUG LINKLIST: val %v\n", value) // DEBUG case oschema.LINKSET: err = serde.writeLinkList(buf, value.([]*oschema.OLink)) ogl.Debugf("DEBUG LINKSET: val %v\n", value) // DEBUG case oschema.LINKMAP: err = serde.writeLinkMap(buf, value.(map[string]*oschema.OLink)) ogl.Debugf("DEBUG LINKMAP: val %v\n", value) // DEBUG case oschema.BYTE: err = rw.WriteByte(buf, value.(byte)) ogl.Debugf("DEBUG BYTE: -writeDataVal val: %v\n", value.(byte)) // DEBUG case oschema.DECIMAL: // TODO: impl me -> Java client uses BigDecimal for this panic("ORecordSerializerV0#writeDataValue DECIMAL NOT YET IMPLEMENTED") case oschema.CUSTOM: // TODO: impl me panic("ORecordSerializerV0#writeDataValue CUSTOM NOT YET IMPLEMENTED") case oschema.LINKBAG: panic("ORecordSerializerV0#writeDataValue LINKBAG NOT YET IMPLEMENTED") default: // ANY and TRANSIENT are do nothing ops } return err }
// // In Progress attempt to rewrite writeSerializedRecord and related fns // using a seekable/skipping WriteBuf // func (serde ORecordSerializerV0) writeSerializedRecord(wbuf *obuf.WriteBuf, doc *oschema.ODocument) (err error) { nfields := len(doc.FieldNames()) ptrPos := make([]int, 0, nfields) // position in buf where data ptr int needs to be written currDB := serde.dbc.GetCurrDB() oclass, ok := currDB.Classes[doc.Classname] docFields := doc.GetFields() for _, fld := range docFields { var oprop *oschema.OProperty if ok { oprop = oclass.Properties[fld.Name] } // FROM THE JAVA CLIENT: // if (properties[i] != null) { // OVarIntSerializer.write(bytes, (properties[i].getId() + 1) * -1); // if (properties[i].getType() != OType.ANY) // pos[i] = bytes.alloc(OIntegerSerializer.INT_SIZE); // else // pos[i] = bytes.alloc(OIntegerSerializer.INT_SIZE + 1); // TODO: why does ANY required an additional byte? // } else { // writeString(bytes, entry.getKey()); // pos[i] = bytes.alloc(OIntegerSerializer.INT_SIZE + 1); if oprop != nil { // if property is known in the global properties, then // just write its encoded id varint.EncodeAndWriteVarInt32(wbuf, encodeFieldIDForHeader(oprop.ID)) ptrPos = append(ptrPos, wbuf.Len()) wbuf.Skip(4) // Note: no need to write property type when writing property ID } else { // property Name err = varint.WriteString(wbuf, fld.Name) if err != nil { return oerror.NewTrace(err) } ptrPos = append(ptrPos, wbuf.Len()) wbuf.Skip(4) // property Type err = rw.WriteByte(wbuf, byte(fld.Type)) if err != nil { return oerror.NewTrace(err) } } } wbuf.WriteByte(0) // End of Header sentinel // now write out the data values for i, fld := range docFields { currPos := wbuf.Len() wbuf.Seek(uint(ptrPos[i])) err = rw.WriteInt(wbuf, int32(currPos)) if err != nil { return oerror.NewTrace(err) } wbuf.Seek(uint(currPos)) err = serde.writeDataValue(wbuf, fld.Value, fld.Type) if err != nil { return oerror.NewTrace(err) } } return nil }