All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.kazuki.v0.store.index.SecondaryIndexTableHelper Maven / Gradle / Ivy

The newest version!
/**
 * Copyright 2014 Sunny Gleason and original author or authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.kazuki.v0.store.index;

import io.kazuki.v0.internal.hash.LongHash;
import io.kazuki.v0.internal.hash.MurmurHash;
import io.kazuki.v0.internal.helper.OpaquePaginationHelper;
import io.kazuki.v0.internal.helper.SqlParamBindings;
import io.kazuki.v0.internal.helper.SqlTypeHelper;
import io.kazuki.v0.internal.helper.StringHelper;
import io.kazuki.v0.internal.v2schema.compact.FieldTransform;
import io.kazuki.v0.store.KazukiException;
import io.kazuki.v0.store.index.query.QueryOperator;
import io.kazuki.v0.store.index.query.QueryTerm;
import io.kazuki.v0.store.index.query.ValueHolder;
import io.kazuki.v0.store.index.query.ValueType;
import io.kazuki.v0.store.keyvalue.KeyValueStoreIteration.SortDirection;
import io.kazuki.v0.store.schema.model.Attribute;
import io.kazuki.v0.store.schema.model.IndexAttribute;
import io.kazuki.v0.store.schema.model.IndexDefinition;
import io.kazuki.v0.store.schema.model.Schema;
import io.kazuki.v0.store.sequence.KeyImpl;
import io.kazuki.v0.store.sequence.SequenceService;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.inject.Inject;

import org.skife.jdbi.v2.Handle;
import org.skife.jdbi.v2.IDBI;
import org.skife.jdbi.v2.TransactionCallback;
import org.skife.jdbi.v2.TransactionStatus;
import org.skife.jdbi.v2.exceptions.UnableToExecuteStatementException;

import com.google.common.base.Throwables;

public class SecondaryIndexTableHelper {
  private final SqlTypeHelper typeHelper;
  private final LongHash longHash;
  private final SequenceService sequences;
  private final String prefix;

  @Inject
  public SecondaryIndexTableHelper(SqlTypeHelper typeHelper, SequenceService sequences) {
    this.typeHelper = typeHelper;
    this.longHash = new MurmurHash();
    this.sequences = sequences;
    this.prefix = typeHelper.getPrefix();
  }

  public String getPrefix() {
    return prefix;
  }

  public void createIndex(IDBI database, final String type, final String indexName,
      final Schema schema, final String groupName, final String storeName,
      final String partitionName) {
    database.inTransaction(new TransactionCallback() {
      @Override
      public Void inTransaction(Handle handle, TransactionStatus arg1) throws Exception {
        try {
          handle
              .createStatement(prefix + "drop_index")
              .define("table_name",
                  getTableName(type, indexName, groupName, storeName, partitionName))
              .define("index_name",
                  getIndexName(type, indexName, groupName, storeName, partitionName)).execute();
        } catch (UnableToExecuteStatementException ok) {
          // expected case in mysql - this is just best-effort anyway
        }

        handle.createStatement(
            getTableDefinition(type, indexName, schema, groupName, storeName, partitionName))
            .execute();

        handle.createStatement(
            getIndexDefinition(type, indexName, schema, groupName, storeName, partitionName))
            .execute();

        return null;
      }
    });
  }

  public void dropTableAndIndex(Handle handle, final String type, final String indexName,
      String groupName, String storeName, String partitionName) {
    handle.createStatement(getTableDrop(type, indexName, groupName, storeName, partitionName))
        .execute();

    try {
      handle.createStatement(prefix + "drop_index")
          .define("table_name", getTableName(type, indexName, groupName, storeName, partitionName))
          .define("index_name", getIndexName(type, indexName, groupName, storeName, partitionName))
          .execute();
    } catch (UnableToExecuteStatementException ok) {
      // expected case in mysql - this is just best-effort anyway
    }
  }

  public void dropTableAndIndex(IDBI database, final String type, final String indexName,
      final String groupName, final String storeName, final String partitionName) {
    database.inTransaction(new TransactionCallback() {
      @Override
      public Void inTransaction(Handle handle, TransactionStatus arg1) throws Exception {
        dropTableAndIndex(handle, type, indexName, groupName, storeName, partitionName);

        return null;
      }
    });
  }

  public String getInsertStatement(String type, String indexName, Schema schema,
      SqlParamBindings bindings, String groupName, String storeName, String partitionName) {
    IndexDefinition indexDefinition = schema.getIndexMap().get(indexName);

    List cols = new ArrayList();
    List params = new ArrayList();
    Set already = new HashSet();

    cols.add(getColumnName("id"));
    params.add(bindings.bind("id", Attribute.Type.U64));
    already.add("id");

    for (IndexAttribute attr : indexDefinition.getIndexAttributes()) {
      if (already.contains(attr.getName())) {
        continue;
      }

      cols.add(getColumnName(attr.getName()));
      params.add(bindings.bind(attr.getName(), schema.getAttribute(attr.getName()).getType()));
    }

    cols.add(typeHelper.quote("quarantined"));
    params.add(bindings.bind("quarantined", "N", Attribute.Type.CHAR_ONE));

    StringBuilder sqlBuilder = new StringBuilder();
    sqlBuilder.append("insert into ");
    sqlBuilder.append(getTableName(type, indexName, groupName, storeName, partitionName));
    sqlBuilder.append(" (");
    sqlBuilder.append(StringHelper.join(", ", cols));
    sqlBuilder.append(") values (");
    sqlBuilder.append(StringHelper.join(", ", params));
    sqlBuilder.append(")");

    return sqlBuilder.toString();
  }

  public String getUpdateStatement(String type, String indexName, Schema schema,
      SqlParamBindings bindings, String groupName, String storeName, String partitionName) {
    IndexDefinition indexDefinition = schema.getIndexMap().get(indexName);

    List sets = new ArrayList();

    for (IndexAttribute attr : indexDefinition.getIndexAttributes()) {
      if ("id".equals(attr.getName())) {
        continue;
      }

      sets.add(getColumnName(attr.getName()) + " = "
          + bindings.bind(attr.getName(), schema.getAttribute(attr.getName()).getType()));
    }

    StringBuilder sqlBuilder = new StringBuilder();
    sqlBuilder.append("update ");
    sqlBuilder.append(getTableName(type, indexName, groupName, storeName, partitionName));
    sqlBuilder.append(" set ");
    sqlBuilder.append(StringHelper.join(", ", sets));
    sqlBuilder.append(" where ");
    sqlBuilder.append(typeHelper.quote("_id"));
    sqlBuilder.append(" = ");
    sqlBuilder.append(bindings.bind("id", Attribute.Type.U64));

    return sqlBuilder.toString();
  }

  public String getDeleteStatement(String type, String indexName, SqlParamBindings bindings,
      String groupName, String storeName, String partitionName) {
    StringBuilder sqlBuilder = new StringBuilder();
    sqlBuilder.append("delete from ");
    sqlBuilder.append(getTableName(type, indexName, groupName, storeName, partitionName));
    sqlBuilder.append(" where ");
    sqlBuilder.append(typeHelper.quote("_id"));
    sqlBuilder.append(" = ");
    sqlBuilder.append(bindings.bind("id", Attribute.Type.U64));

    return sqlBuilder.toString();
  }

  public String getQuarantineStatement(String type, String indexName, SqlParamBindings bindings,
      boolean isQuarantined, String groupName, String storeName, String partitionName) {
    StringBuilder sqlBuilder = new StringBuilder();
    sqlBuilder.append("update ");
    sqlBuilder.append(getTableName(type, indexName, groupName, storeName, partitionName));
    sqlBuilder.append(" set ");
    sqlBuilder.append(typeHelper.quote("quarantined"));
    sqlBuilder.append(" = ");
    sqlBuilder.append(bindings.bind("is_quarantined", isQuarantined ? "Y" : "N",
        Attribute.Type.CHAR_ONE));
    sqlBuilder.append(" where ");
    sqlBuilder.append(typeHelper.quote("_id"));
    sqlBuilder.append(" = ");
    sqlBuilder.append(bindings.bind("id", Attribute.Type.U64));

    return sqlBuilder.toString();
  }

  public void truncateIndexTable(Handle handle, final String type, final String indexName,
      String groupName, String storeName, String partitionName) {
    String indexTableName = getTableName(type, indexName, groupName, storeName, partitionName);

    handle.createStatement(prefix + "truncate_table").define("table_name", indexTableName)
        .execute();
  }

  public String getSqlOperator(QueryOperator operator, ValueHolder value) {
    switch (operator) {
      case EQ:
        return (value.getValueType().equals(ValueType.NULL)) ? "is null" : "=";
      case NE:
        return (value.getValueType().equals(ValueType.NULL)) ? "is not null" : "<>";
      case GT:
        return ">";
      case GE:
        return ">=";
      case LT:
        return "<";
      case LE:
        return "<=";
      case IN:
        return "in";
      default:
        throw new IllegalArgumentException("Unknown operator: " + operator);
    }
  }

  public Object transformAttributeValue(Object value, IndexAttribute attr) {
    Object toBind = value;

    if (toBind != null) {
      switch (attr.getTransform()) {
        case UPPERCASE:
          toBind = toBind.toString().toUpperCase();
          break;
        case LOWERCASE:
          toBind = toBind.toString().toLowerCase();
          break;
        default:
          break;
      }
    }

    return toBind;
  }

  public boolean isConstraintViolation(UnableToExecuteStatementException e) {
    if (e.getCause() != null) {
      String message = e.getCause().getMessage().toLowerCase();

      return message.contains("constraint violation") || message.contains("duplicate entry")
          || message.contains("unique index or primary key violation");
    }

    return false;
  }

  public String getColumnName(String attributeName, boolean doQuote) {
    return doQuote ? getColumnName(attributeName) : "_" + attributeName;
  }

  public String getColumnName(String attributeName) {
    return typeHelper.quote("_" + attributeName + "");
  }

  public String getTableName(String type, String index, String groupName, String storeName,
      String partitionName) {
    try {
      Integer typeId = sequences.getTypeId(type, false);
      if (typeId == null) {
        return null;
      }

      String truncType = truncateString(type, 4);
      String truncIndex = truncateString(index, 10);

      return typeHelper.quote("_" + groupName + "_" + storeName + "__idxtbl__" + partitionName
          + "_" + String.format("%04d", typeId) + "__" + getIndexHexId(index) + "_" + truncType
          + "_" + truncIndex);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  public String getIndexName(String type, String index, String groupName, String storeName,
      String partitionName) {
    try {
      Integer typeId = sequences.getTypeId(type, false);
      if (typeId == null) {
        return null;
      }

      String truncType = truncateString(type, 4);
      String truncIndex = truncateString(index, 10);

      return typeHelper.quote("_" + groupName + "_" + storeName + "__idxidx__" + partitionName
          + "_" + String.format("%04d", typeId) + "__" + getIndexHexId(index) + "_" + truncType
          + "_" + truncIndex);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  private String getIndexHexId(String index) {
    return String.format("%016x", longHash.getLongHashCode(index));
  }

  public String getTableDrop(String type, String indexName, String groupName, String storeName,
      String partitionName) {
    StringBuilder sqlBuilder = new StringBuilder();
    sqlBuilder.append("drop table if exists ");
    sqlBuilder.append(getTableName(type, indexName, groupName, storeName, partitionName));

    return sqlBuilder.toString();
  }

  public String getIndexDrop(String type, String indexName, String groupName, String storeName,
      String partitionName) {
    StringBuilder sqlBuilder = new StringBuilder();
    sqlBuilder.append("drop index ");
    sqlBuilder.append(getIndexName(type, indexName, groupName, storeName, partitionName));
    sqlBuilder.append(" on ");
    sqlBuilder.append(getTableName(type, indexName, groupName, storeName, partitionName));

    return sqlBuilder.toString();
  }

  public String getTableDefinition(String type, String indexName, Schema schema, String groupName,
      String storeName, String partitionName) {
    IndexDefinition indexDefinition = schema.getIndexMap().get(indexName);

    if (indexDefinition == null) {
      throw new IllegalArgumentException("schema or index not found " + type + "." + indexName);
    }

    StringBuilder sqlBuilder = new StringBuilder();
    sqlBuilder.append("create table if not exists ");
    sqlBuilder.append(getTableName(type, indexName, groupName, storeName, partitionName));
    sqlBuilder.append(" (");
    sqlBuilder.append(typeHelper.quote("_id"));
    sqlBuilder.append(" ");
    sqlBuilder.append(typeHelper.getSqlType(Attribute.Type.U64));
    sqlBuilder.append(" PRIMARY KEY");

    for (IndexAttribute column : indexDefinition.getIndexAttributes()) {
      Attribute attribute = schema.getAttribute(column.getName());
      if (attribute == null && !column.getName().equals("id")) {
        throw new IllegalArgumentException("Unknown attribute : " + column.getName());
      }

      if (column.getName().equals("id")) {
        continue;
      }

      sqlBuilder.append(", ");
      sqlBuilder.append(getColumnName(column.getName()));
      sqlBuilder.append(" ");
      sqlBuilder.append(typeHelper.getSqlType(attribute.getType()));
    }

    sqlBuilder.append(", ");
    sqlBuilder.append(typeHelper.quote("quarantined"));
    sqlBuilder.append(" ");
    sqlBuilder.append(typeHelper.getSqlType(Attribute.Type.CHAR_ONE));

    sqlBuilder.append(")");
    sqlBuilder.append(typeHelper.getTableOptions());

    return sqlBuilder.toString();
  }

  public String getIndexDefinition(String type, String indexName, Schema schema, String groupName,
      String storeName, String partitionName) {
    IndexDefinition indexDefinition = schema.getIndexMap().get(indexName);

    if (indexDefinition == null) {
      throw new IllegalArgumentException("schema or index not found " + type + "." + indexName);
    }

    Iterator iter = indexDefinition.getIndexAttributes().iterator();

    List colDefs = new ArrayList();
    while (iter.hasNext()) {
      IndexAttribute column = iter.next();

      Attribute attribute = schema.getAttribute(column.getName());

      if (attribute == null && !column.getName().equals("id")) {
        throw new IllegalArgumentException("Unknown attribute : " + column.getName());
      }

      if (indexDefinition.isUnique() && column.getName().equals("id")) {
        continue;
      }

      String sortDirection =
          column.getSortDirection().equals(SortDirection.ASCENDING) ? "ASC" : "DESC";

      colDefs.add(getColumnName(column.getName()) + " " + sortDirection);
    }

    if (!indexDefinition.isUnique()) {
      colDefs.add(getColumnName("id") + " " + "ASC");
    }

    StringBuilder sqlBuilder = new StringBuilder();
    sqlBuilder.append("create ");

    if (indexDefinition.isUnique()) {
      sqlBuilder.append("unique ");
    }

    sqlBuilder.append("index ");
    sqlBuilder.append(getIndexName(type, indexName, groupName, storeName, partitionName));
    sqlBuilder.append(" on ");
    sqlBuilder.append(getTableName(type, indexName, groupName, storeName, partitionName));
    sqlBuilder.append(" (");
    sqlBuilder.append(StringHelper.join(", ", colDefs));
    sqlBuilder.append(")");

    return sqlBuilder.toString();
  }

  public String getIndexQuery(String type, String indexName, SortDirection sortDirection,
      List queryTerms, Long offset, Long pageSize, boolean includeQuarantine,
      Schema schema, SqlParamBindings bindings, String groupName, String storeName,
      String partitionName) throws Exception {
    IndexDefinition indexDef = schema.getIndex(indexName);

    if (indexDef == null) {
      throw new IllegalArgumentException("schema or index not found " + type + "." + indexName);
    }

    return getIndexQuery(type, indexName, sortTerms(indexDef, queryTerms), sortDirection, offset,
        pageSize, includeQuarantine, indexDef, schema, new FieldTransform(schema), bindings,
        groupName, storeName, partitionName);

  }

  public String getIndexQuery(String type, String indexName, Map> termMap,
      SortDirection sortDirection, Long offset, Long pageSize, boolean includeQuarantine,
      IndexDefinition indexDefinition, Schema schema, FieldTransform transform,
      SqlParamBindings bindings, String groupName, String storeName, String partitionName)
      throws Exception {
    List firstTerm = termMap.get(indexDefinition.getIndexAttributes().get(0).getName());
    if (firstTerm == null || firstTerm.isEmpty()) {
      throw new IllegalArgumentException("missing query term for first attribute of index");
    }

    List clauses = new ArrayList();
    int param = 0;

    for (IndexAttribute attribute : indexDefinition.getIndexAttributes()) {
      String attrName = attribute.getName();
      List termList = termMap.get(attrName);

      if (termList == null || termList.isEmpty()) {
        continue;
      }

      for (QueryTerm term : termList) {
        String maybeParam = "";
        QueryOperator op = term.getOperator();

        if (op.equals(QueryOperator.IN)) {
          List valueList = term.getValueList().getValueList();

          String sqlOperator = getSqlOperator(term.getOperator(), valueList.get(0));

          List paramNames = new ArrayList();

          for (ValueHolder value : valueList) {
            String boundParam =
                bindParam(attribute, schema, transform, bindings, param, attrName, value);

            if (boundParam != null) {
              maybeParam = " " + boundParam;
              paramNames.add(maybeParam);
              param += 1;
            } else {
              maybeParam = "";
            }
          }

          clauses.add(getColumnName(term.getField()) + " " + sqlOperator + "("
              + StringHelper.join(", ", paramNames) + ")");
        } else {
          String boundParam =
              bindParam(attribute, schema, transform, bindings, param, attrName, term.getValue());

          if (boundParam != null) {
            maybeParam = " " + boundParam;
            param += 1;
          }

          clauses.add(getColumnName(term.getField()) + " "
              + getSqlOperator(term.getOperator(), term.getValue()) + maybeParam);
        }
      }
    }

    List sortOrders = new ArrayList();
    for (IndexAttribute attr : indexDefinition.getIndexAttributes()) {
      String colName = getColumnName(attr.getName());

      String colSortDirection = null;

      if (sortDirection.equals(attr.getSortDirection())) {
        colSortDirection = sortDirection.equals(SortDirection.ASCENDING) ? "ASC" : "DESC";
      } else {
        colSortDirection = sortDirection.equals(SortDirection.DESCENDING) ? "DESC" : "ASC";
      }

      sortOrders.add(colName + " " + colSortDirection);
    }

    sortOrders.add(getColumnName("id") + " "
        + (sortDirection.equals(SortDirection.ASCENDING) ? "ASC" : "DESC"));

    offset = offset != null ? offset : 0L;
    Long limit = pageSize != null ? pageSize + 1L : -1;

    StringBuilder sqlBuilder = new StringBuilder();
    sqlBuilder.append("select ");
    sqlBuilder.append(typeHelper.quote("_id"));
    sqlBuilder.append(" from ");
    sqlBuilder.append(getTableName(type, indexName, groupName, storeName, partitionName));
    sqlBuilder.append(" where ");
    if (!includeQuarantine) {
      sqlBuilder.append(typeHelper.quote("quarantined"));
      sqlBuilder.append(" = 'N' AND ");
    }
    sqlBuilder.append(StringHelper.join(" AND ", clauses));
    sqlBuilder.append(" order by ");
    sqlBuilder.append(StringHelper.join(", ", sortOrders));
    sqlBuilder.append(" limit ");
    sqlBuilder.append(limit);
    sqlBuilder.append(" offset ");
    sqlBuilder.append(offset);

    return sqlBuilder.toString();
  }

  public String getIndexAllQuery(String type, String token, Long pageSize, boolean includeQuarantine)
      throws Exception {
    StringBuilder sqlBuilder = new StringBuilder();
    sqlBuilder.append("select ");
    sqlBuilder.append(typeHelper.quote("_key_id"));
    sqlBuilder.append(" as ");
    sqlBuilder.append(typeHelper.quote("_id"));
    sqlBuilder.append(" from ");
    sqlBuilder.append(typeHelper.quote("_key_values"));
    sqlBuilder.append(" where ");
    sqlBuilder.append(typeHelper.quote("_key_type"));
    sqlBuilder.append(" = ");
    sqlBuilder.append(sequences.getTypeId(type, false));
    sqlBuilder.append(" AND ");
    if (!includeQuarantine) {
      sqlBuilder.append(typeHelper.quote("_is_deleted"));
      sqlBuilder.append(" = 'N'");
    } else {
      sqlBuilder.append(typeHelper.quote("_is_deleted"));
      sqlBuilder.append(" != 'Y'");
    }
    sqlBuilder.append(" order by ");
    sqlBuilder.append(typeHelper.quote("_id"));
    sqlBuilder.append(" limit ");
    sqlBuilder.append(pageSize + 1L);
    sqlBuilder.append(" offset ");
    sqlBuilder.append(OpaquePaginationHelper.decodeOpaqueCursor(token));

    return sqlBuilder.toString();
  }

  public String computeIndexKey(String type, String indexName, IndexDefinition indexDefinition,
      Map value) {
    StringBuilder theKey = new StringBuilder();

    try {
      theKey.append("idx:");
      theKey.append(getUniqueIndexIdentifier(type, indexName));
      theKey.append(":");

      Iterator indexAttrIter = indexDefinition.getIndexAttributes().iterator();

      while (indexAttrIter.hasNext()) {
        IndexAttribute attr = indexAttrIter.next();

        String attrName = attr.getName();
        if ("id".equals(attrName)) {
          continue;
        }

        Object attrValue = value.get(attrName);
        Object transformed = (attrValue == null) ? null : transformAttributeValue(attrValue, attr);

        String attrValueString =
            (transformed != null) ? URLEncoder.encode(transformed.toString(), "UTF-8") : "$";

        theKey.append(attrValueString);

        if (indexAttrIter.hasNext()) {
          theKey.append("|");
        }
      }
    } catch (Exception shouldntHappen) {
      throw new RuntimeException(shouldntHappen);
    }

    return theKey.toString();
  }

  public Map> sortTerms(IndexDefinition indexDef, List terms)
      throws KazukiException {
    Map> termMap = new LinkedHashMap>();

    Set termFields = new HashSet();

    for (QueryTerm term : terms) {
      String attrName = term.getField();
      termFields.add(attrName);

      if (!indexDef.getAttributeNames().contains(attrName)) {
        throw new KazukiException("'" + attrName + "' not in index");
      }
    }

    for (IndexAttribute attribute : indexDef.getIndexAttributes()) {
      String attrName = attribute.getName();

      if (indexDef.isUnique() && !attrName.equals("id") && !termFields.contains(attrName)) {
        throw new KazukiException("unique index query must specify all fields");
      }

      for (QueryTerm term : terms) {
        if (term.getField().equals(attrName)) {
          List attrTerms = termMap.get(attrName);
          if (attrTerms == null) {
            attrTerms = new ArrayList();
            termMap.put(attrName, attrTerms);
          }

          attrTerms.add(term);
        }
      }
    }

    return termMap;
  }

  public static String getUniqueIndexKey(String type, Schema schema, String indexName,
      Map valMap) {
    IndexDefinition indexDef = schema.getIndex(indexName);
    StringBuilder builder = new StringBuilder();

    builder.append(type);
    builder.append(".");
    builder.append(indexName);
    builder.append(":");

    for (IndexAttribute attr : indexDef.getIndexAttributes()) {
      try {
        builder.append("/");
        builder.append(URLEncoder.encode(String.valueOf(valMap.get(attr.getName())), "UTF-8"));
      } catch (UnsupportedEncodingException e) {
        throw Throwables.propagate(e);
      }
    }

    return builder.toString();
  }

  private String bindParam(IndexAttribute attribute, Schema schema, FieldTransform transform,
      SqlParamBindings bindings, int param, String attrName, ValueHolder value)
      throws KazukiException {
    if (!value.getValueType().equals(ValueType.NULL)) {
      Object instance = value.getValue();
      Object transformed = transform.transformValue(attrName, instance);

      if (transformed != null) {
        transformed = transformed.toString();
      }

      if (attrName.equals("id")) {
        try {
          transformed = KeyImpl.valueOf(transformed.toString());
        } catch (Exception e) {
          throw new KazukiException("invalid id: '" + instance.toString() + "'");
        }
      }

      return bindings.bind(
          "p" + param,
          transformAttributeValue(transformed, attribute),
          "id".equals(attribute.getName()) ? Attribute.Type.U64 : schema.getAttributeMap()
              .get(attribute.getName()).getType());
    }

    return null;
  }

  private String getUniqueIndexIdentifier(String type, String index) throws Exception {
    return String.format("%04d", sequences.getTypeId(type, false)) + "__" + getIndexHexId(index);
  }

  private String truncateString(String value, int desired) {
    int len = value.length();

    return len >= desired ? value.substring(0, desired) : value;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy