public void testIndexMapRemove() {
    final ODocument docOne = new ODocument();
    docOne.save();

    final ODocument docTwo = new ODocument();
    docTwo.save();

    final ODocument docThree = new ODocument();
    docThree.save();

    Map<String, ORID> map = new HashMap<String, ORID>();

    map.put("key1", docOne.getIdentity());
    map.put("key2", docTwo.getIdentity());

    final ODocument document = new ODocument("LinkMapIndexTestClass");
    document.field("linkMap", map);
    document.save();
    document.delete();

    final List<ODocument> resultByKey =
        database.command(new OCommandSQL("select key, rid from index:mapIndexTestKey")).execute();

    Assert.assertNotNull(resultByKey);
    Assert.assertEquals(resultByKey.size(), 0);

    final List<ODocument> resultByValue =
        database.command(new OCommandSQL("select key, rid from index:mapIndexTestValue")).execute();

    Assert.assertNotNull(resultByValue);
    Assert.assertEquals(resultByValue.size(), 0);
  }
  @Override
  public void deleteByRelationType(IRelationType relationType) {
    // delete source reference pointing to relation type
    OSQLSynchQuery<ODocument> query =
        new OSQLSynchQuery<>("select * from Relation where relationType = " + relationType.getId());
    List<ODocument> result = db.command(query).execute();

    // remove relation and link
    for (ODocument document : result) {
      ODocument relationLink = getRelationLink(document, true);
      if (relationLink != null && db.load(relationLink.getIdentity()) != null)
        relationLink.delete();

      document.delete();
    }
  }
  public void testIndexMapRemoveInTxRollback() throws Exception {
    final ODocument docOne = new ODocument();
    docOne.save();

    final ODocument docTwo = new ODocument();
    docTwo.save();

    Map<String, ORID> map = new HashMap<String, ORID>();

    map.put("key1", docOne.getIdentity());
    map.put("key2", docTwo.getIdentity());

    final ODocument document = new ODocument("LinkMapIndexTestClass");
    document.field("linkMap", map);
    document.save();

    database.begin();
    document.delete();
    database.rollback();

    final List<ODocument> resultByKey =
        database.command(new OCommandSQL("select key, rid from index:mapIndexTestKey")).execute();

    Assert.assertNotNull(resultByKey);
    Assert.assertEquals(resultByKey.size(), 2);
    for (ODocument d : resultByKey) {
      Assert.assertTrue(d.containsField("key"));
      Assert.assertTrue(d.containsField("rid"));

      if (!d.field("key").equals("key1") && !d.field("key").equals("key2")) {
        Assert.fail("Unknown key found: " + d.field("key"));
      }
    }

    final List<ODocument> resultByValue =
        database.command(new OCommandSQL("select key, rid from index:mapIndexTestValue")).execute();

    Assert.assertNotNull(resultByValue);
    Assert.assertEquals(resultByValue.size(), 2);
    for (ODocument d : resultByValue) {
      Assert.assertTrue(d.containsField("key"));
      Assert.assertTrue(d.containsField("rid"));

      if (!d.field("key").equals(docOne.getIdentity())
          && !d.field("key").equals(docTwo.getIdentity())) {
        Assert.fail("Unknown key found: " + d.field("key"));
      }
    }
  }
  protected void deleteDocument(
      final int threadId,
      final int iCycle,
      final String dbUrl,
      final String className,
      final int iSkip) {
    final ODatabaseDocumentTx db = getDatabase(dbUrl);
    for (int retry = 0; retry < MAX_RETRY; ++retry) {
      ODocument doc = null;
      try {
        List<OIdentifiable> result =
            db.query(
                new OSQLSynchQuery<Object>(
                    "select from " + className + " skip " + iSkip + " limit 1"));

        if (result == null || result.isEmpty())
          log(threadId, iCycle, dbUrl, " delete no item " + iSkip + " because out of range");
        else {
          doc = result.get(0).getRecord();
          doc.delete();
          log(threadId, iCycle, dbUrl, " deleted item " + iSkip + " RID=" + result.get(0));
        }
        break;
      } catch (OConcurrentModificationException e) {
        log(
            threadId,
            iCycle,
            dbUrl,
            " concurrent delete against record "
                + doc
                + ", reload it and retry "
                + retry
                + "/"
                + MAX_RETRY
                + "...");
        if (doc != null) doc.reload(null, true);
      } catch (ORecordNotFoundException e) {
        log(threadId, iCycle, dbUrl, " delete no item " + iSkip + " because not found");
      } finally {
        db.close();
      }
    }
  }
  @Override
  public boolean save(IRelation entity) {
    try {
      // sanity: we need from and to entity to do this!
      if (entity.getFromEntity() == null || entity.getToEntity() == null) {
        logger.error("From and/or to-entity not set in relation: Not saving!");
        return false;
      }

      initDb();

      // process before saving
      entity = processBeforeSaving(entity);

      // create document - call special method
      ODocument document = reallyConvertToDocument(entity);

      ODocument relationLink = getRelationLink(document, false);
      if (relationLink == null) { // no relation yet => create new one
        // create edge and set it to document
        List<OIdentifiable> edgeList =
            repositoryFactory
                .getDb()
                .command(
                    new OCommandSQL(
                        "create edge IsRelation from "
                            + entity.getFromEntity().getId()
                            + " to "
                            + entity.getToEntity().getId()))
                .execute();
        document.field("relationLink", (ORecordId) edgeList.get(0).getIdentity());

        if (logger.isTraceEnabled())
          logger.trace("Created brank new IsRelation edge: " + edgeList.get(0).toString());
      } else {
        // check whether relation has changed
        String oldFromId = relationLink.field("out", ORecordId.class).toString();
        String oldToId = relationLink.field("in", ORecordId.class).toString();

        String newFromId = entity.getFromEntity().getId();
        String newToId = entity.getToEntity().getId();

        // check equality
        if (!oldFromId.equals(newFromId) || !oldToId.equals(newToId)) {
          // delete old edge and create new one
          relationLink.delete();

          List<OrientEdge> edgeList =
              repositoryFactory
                  .getDb()
                  .command(
                      new OCommandSQL(
                          "create edge IsRelation from "
                              + entity.getFromEntity().getId()
                              + " to "
                              + entity.getToEntity().getId()))
                  .execute();
          document.field("relationLink", (ORecordId) edgeList.get(0).getId());

          if (logger.isTraceEnabled())
            logger.trace(
                "Replace IsRelation edge: "
                    + edgeList.get(0).toString()
                    + " (was: "
                    + relationLink.toString()
                    + ")");
        }
      }

      // save
      ODocument updated = db.save(document);

      // process after saving
      processAfterSaving(updated, entity);

      if (logger.isInfoEnabled()) logger.info("Saved entity: " + entity.toString());

      return true;
    } catch (Exception e) {
      logger.error("Exception thrown while saving entity.", e);
    }

    return false;
  }