@Test
  public void testCommandAlterDocument() {
    running(
        fakeApplication(),
        () -> {
          try {
            DbHelper.open("1234567890", TEST_USER, TEST_USER);
            ObjectNode cmd = MAPPER.createObjectNode();
            ObjectNode p = MAPPER.createObjectNode();
            p.put("id", sGenIds.get(0));
            p.put("collection", TEST_COLLECTION);

            cmd.put(ScriptCommand.RESOURCE, "documents");
            cmd.put(ScriptCommand.NAME, "get");

            cmd.put(ScriptCommand.PARAMS, p);

            JsonNode node = CommandRegistry.execute(cmd, null);
            assertNotNull(node);
            assertTrue(node.isObject());
            ObjectNode doc = node.deepCopy();
            doc.put("extra", "extra");

            ObjectNode upd = MAPPER.createObjectNode();
            upd.put(ScriptCommand.RESOURCE, "documents");
            upd.put(ScriptCommand.NAME, "put");

            ObjectNode params = MAPPER.createObjectNode();
            params.put("collection", TEST_COLLECTION);
            params.put("id", doc.get("id").asText());
            params.put("data", doc);
            upd.put(ScriptCommand.PARAMS, params);
            JsonNode res = CommandRegistry.execute(upd, null);
            assertNotNull(res);
            assertTrue(res.isObject());
            assertNotNull(res.get("extra"));
            assertEquals(res.get("id"), doc.get("id"));
            assertEquals("extra", res.get("extra").asText());
          } catch (Throwable t) {
            fail(ExceptionUtils.getFullStackTrace(t));
          } finally {
            DbHelper.close(DbHelper.getConnection());
          }
        });
  }
  @Override
  public boolean update(JsonDoc doc, FieldTreeNode contextMd, Path contextPath) {
    boolean ret = false;
    Path absPath = new Path(contextPath, arrayField);
    JsonNode node = doc.get(absPath);
    int insertTo = insertionIndex;
    if (node == null || node instanceof NullNode) {
      doc.modify(absPath, node = factory.arrayNode(), true);
    }
    if (node instanceof ArrayNode) {
      ArrayNode arrayNode = (ArrayNode) node;
      for (RValueData rvalueData : values) {
        LOGGER.debug("add element to {} rvalue:{}", absPath, rvalueData);
        Object newValue = null;
        Type newValueType = null;
        JsonNode newValueNode = null;
        if (rvalueData.refPath != null) {
          JsonNode refNode = doc.get(new Path(contextPath, rvalueData.refPath));
          if (refNode != null) {
            newValueNode = refNode.deepCopy();
            newValue = rvalueData.refType.fromJson(newValueNode);
            newValueType = rvalueData.refType;
          }
        } else if (rvalueData.value != null) {
          newValue = rvalueData.value.getValue();
          newValueNode =
              newValue instanceof JsonNode
                  ? (JsonNode) newValue
                  : fieldMd.getElement().getType().toJson(factory, newValue);
          newValueType = fieldMd.getElement().getType();
        } else if (rvalueData.rvalueType == RValueExpression.RValueType._null) {
          newValueNode = factory.nullNode();
        }
        LOGGER.debug(
            "newValueType:{}, newValue:{}, newValueNode:{} ", newValueType, newValue, newValueNode);

        if (insertTo >= 0) {
          // If we're inserting, make sure we have that many elements
          while (arrayNode.size() < insertTo) {
            arrayNode.addNull();
          }

          if (arrayNode.size() > insertTo) {
            arrayNode.insert(insertTo, newValueNode);
          } else {
            arrayNode.add(newValueNode);
          }
          insertTo++;
        } else {
          arrayNode.add(newValueNode);
        }
        ret = true;
      }
      if (ret) {
        // We have to rewrite the array indexes in arraySizeField using
        // the context path
        MutablePath p = new MutablePath(arraySizeField);
        p.rewriteIndexes(contextPath);
        LOGGER.debug("Setting {} = {}", p, arrayNode.size());
        doc.modify(p, factory.numberNode(arrayNode.size()), false);
      }
    }
    return ret;
  }
 /**
  * Add a key/value pair to this message
  *
  * <p>This is the main method. All other put methods call this one.
  *
  * <p>Note that if the key is {@code null}, the content is <b>ignored</b>.
  *
  * @param key the key
  * @param value the value as a {@link JsonNode}
  * @return this
  */
 public ProcessingMessage put(final String key, final JsonNode value) {
   if (key == null) return this;
   if (value == null) return putNull(key);
   map.put(key, value.deepCopy());
   return this;
 }