func (e *Elasticsearch) applyOp(msg *message.Msg) (*message.Msg, error) { if msg.Op == message.Command { err := e.runCommand(msg) if err != nil { e.pipe.Err <- NewError(ERROR, e.path, fmt.Sprintf("elasticsearch error (%s)", err), msg.Data) } return msg, nil } // TODO there might be some inconsistency here. elasticsearch uses the _id field for an primary index, // and we're just mapping it to a string here. id, err := msg.IDString("_id") if err != nil { id = "" } _, _type, err := msg.SplitNamespace() if err != nil { e.pipe.Err <- NewError(ERROR, e.path, fmt.Sprintf("unable to determine type from msg.Namespace (%s)", msg.Namespace), msg) return msg, nil } switch msg.Op { case message.Delete: e.indexer.Delete(e.index, _type, id, false) err = nil default: err = e.indexer.Index(e.index, _type, id, "", "", nil, msg.Data, false) } if err != nil { e.pipe.Err <- NewError(ERROR, e.path, fmt.Sprintf("elasticsearch error (%s)", err), msg.Data) } return msg, nil }
// applyOp applies one operation to the database func (r *Rethinkdb) applyOp(msg *message.Msg) (*message.Msg, error) { var ( resp gorethink.WriteResponse err error ) _, msgTable, err := msg.SplitNamespace() if err != nil { r.pipe.Err <- NewError(ERROR, r.path, fmt.Sprintf("rethinkdb error (msg namespace improperly formatted, must be database.table, got %s)", msg.Namespace), msg.Data) return msg, nil } if !msg.IsMap() { r.pipe.Err <- NewError(ERROR, r.path, "rethinkdb error (document must be a json document)", msg.Data) return msg, nil } doc := msg.Map() switch msg.Op { case message.Delete: id, err := msg.IDString("id") if err != nil { r.pipe.Err <- NewError(ERROR, r.path, "rethinkdb error (cannot delete an object with a nil id)", msg.Data) return msg, nil } resp, err = gorethink.Table(msgTable).Get(id).Delete().RunWrite(r.client) case message.Insert: resp, err = gorethink.Table(msgTable).Insert(doc).RunWrite(r.client) case message.Update: resp, err = gorethink.Table(msgTable).Insert(doc, gorethink.InsertOpts{Conflict: "replace"}).RunWrite(r.client) } if err != nil { r.pipe.Err <- NewError(ERROR, r.path, "rethinkdb error (%s)", err) return msg, nil } err = r.handleResponse(&resp) if err != nil { r.pipe.Err <- NewError(ERROR, r.path, "rethinkdb error (%s)", err) } return msg, nil }
// writeMessage writes one message to the destination mongo, or sends an error down the pipe // TODO this can be cleaned up. I'm not sure whether this should pipe the error, or whether the // caller should pipe the error func (m *Mongodb) writeMessage(msg *message.Msg) (*message.Msg, error) { _, msgColl, err := msg.SplitNamespace() if err != nil { m.pipe.Err <- NewError(ERROR, m.path, fmt.Sprintf("mongodb error (msg namespace improperly formatted, must be database.collection, got %s)", msg.Namespace), msg.Data) return msg, nil } collection := m.mongoSession.DB(m.database).C(msgColl) if !msg.IsMap() { m.pipe.Err <- NewError(ERROR, m.path, fmt.Sprintf("mongodb error (document must be a bson document, got %T instead)", msg.Data), msg.Data) return msg, nil } doc := &SyncDoc{ Doc: msg.Map(), Collection: msgColl, } if m.bulk { m.bulkWriteChannel <- doc } else if msg.Op == message.Delete { err := collection.Remove(doc.Doc) if err != nil { m.pipe.Err <- NewError(ERROR, m.path, fmt.Sprintf("mongodb error removing (%s)", err.Error()), msg.Data) } } else { err := collection.Insert(doc.Doc) if mgo.IsDup(err) { err = collection.Update(bson.M{"_id": doc.Doc["_id"]}, doc.Doc) } if err != nil { m.pipe.Err <- NewError(ERROR, m.path, fmt.Sprintf("mongodb error (%s)", err.Error()), msg.Data) } } return msg, nil }