@Override
  public AtlasVertex preCreate(AtlasStructDef structDef) throws AtlasBaseException {
    if (LOG.isDebugEnabled()) {
      LOG.debug("==> AtlasStructDefStoreV1.preCreate({})", structDef);
    }

    AtlasType type = typeRegistry.getType(structDef.getName());

    if (type.getTypeCategory() != AtlasType.TypeCategory.STRUCT) {
      throw new AtlasBaseException(
          AtlasErrorCode.TYPE_MATCH_FAILED, structDef.getName(), TypeCategory.STRUCT.name());
    }

    AtlasVertex ret = typeDefStore.findTypeVertexByName(structDef.getName());

    if (ret != null) {
      throw new AtlasBaseException(AtlasErrorCode.TYPE_ALREADY_EXISTS, structDef.getName());
    }

    ret = typeDefStore.createTypeVertex(structDef);

    AtlasStructDefStoreV1.updateVertexPreCreate(
        structDef, (AtlasStructType) type, ret, typeDefStore);

    if (LOG.isDebugEnabled()) {
      LOG.debug("<== AtlasStructDefStoreV1.preCreate({}): {}", structDef, ret);
    }

    return ret;
  }
  @Override
  public AtlasStructDef updateByGuid(String guid, AtlasStructDef structDef)
      throws AtlasBaseException {
    if (LOG.isDebugEnabled()) {
      LOG.debug("==> AtlasStructDefStoreV1.updateByGuid({})", guid);
    }

    AtlasType type = typeRegistry.getTypeByGuid(guid);

    if (type.getTypeCategory() != AtlasType.TypeCategory.STRUCT) {
      throw new AtlasBaseException(
          AtlasErrorCode.TYPE_MATCH_FAILED, structDef.getName(), TypeCategory.STRUCT.name());
    }

    AtlasVertex vertex = typeDefStore.findTypeVertexByGuidAndCategory(guid, TypeCategory.STRUCT);

    if (vertex == null) {
      throw new AtlasBaseException(AtlasErrorCode.TYPE_GUID_NOT_FOUND, guid);
    }

    AtlasStructDefStoreV1.updateVertexPreUpdate(
        structDef, (AtlasStructType) type, vertex, typeDefStore);
    AtlasStructDefStoreV1.updateVertexAddReferences(structDef, vertex, typeDefStore);

    AtlasStructDef ret = toStructDef(vertex);

    if (LOG.isDebugEnabled()) {
      LOG.debug("<== AtlasStructDefStoreV1.updateByGuid({}): {}", guid, ret);
    }

    return ret;
  }
  private static String toJsonFromAttributeDef(
      AtlasAttributeDef attributeDef, AtlasStructType structType) {
    boolean isForeignKey = structType.isForeignKeyAttribute(attributeDef.getName());
    boolean isMappedFromRef = structType.isMappedFromRefAttribute(attributeDef.getName());
    String reverseAttribName = null;

    if (isForeignKey) { // check if the referenced entity has foreignKeyRef to this attribute
      AtlasType attribType = structType.getAttributeType(attributeDef.getName());

      if (attribType.getTypeCategory() == AtlasType.TypeCategory.ARRAY) {
        attribType = ((AtlasArrayType) attribType).getElementType();
      }

      if (attribType.getTypeCategory() == AtlasType.TypeCategory.ENTITY) {
        reverseAttribName =
            ((AtlasStructType) attribType)
                .getMappedFromRefAttribute(structType.getTypeName(), attributeDef.getName());
      }
    }

    boolean isComposite =
        isMappedFromRef || (isForeignKey && StringUtils.isBlank(reverseAttribName));

    Map<String, Object> attribInfo = new HashMap<>();

    attribInfo.put("name", attributeDef.getName());
    attribInfo.put("dataType", attributeDef.getTypeName());
    attribInfo.put("isUnique", attributeDef.isUnique());
    attribInfo.put("isIndexable", attributeDef.isIndexable());
    attribInfo.put("isComposite", isComposite);
    attribInfo.put("reverseAttributeName", reverseAttribName);
    Map<String, Object> multiplicity = new HashMap<>();
    multiplicity.put("lower", attributeDef.getValuesMinCount());
    multiplicity.put("upper", attributeDef.getValuesMaxCount());
    multiplicity.put(
        "isUnique", AtlasAttributeDef.Cardinality.SET.equals(attributeDef.getCardinality()));

    attribInfo.put("multiplicity", AtlasType.toJson(multiplicity));

    return AtlasType.toJson(attribInfo);
  }