public static String createTableDefinition(TableInfo tableInfo) {
    final ArrayList<String> definitions = new ArrayList<String>();

    for (Field field : tableInfo.getFields()) {
      String definition = createColumnDefinition(tableInfo, field);
      if (!TextUtils.isEmpty(definition)) {
        definitions.add(definition);
      }
    }

    return String.format(
        "CREATE TABLE IF NOT EXISTS %s (%s);",
        tableInfo.getTableName(), TextUtils.join(", ", definitions));
  }
  public static String createIndexDefinition(TableInfo tableInfo) {
    final ArrayList<String> definitions = new ArrayList<String>();

    for (Field field : tableInfo.getFields()) {
      String definition = createIndexColumnDefinition(tableInfo, field);
      if (!TextUtils.isEmpty(definition)) {
        definitions.add(definition);
      }
    }
    if (definitions.isEmpty()) return null;

    return String.format(
        "CREATE INDEX IF NOT EXISTS %s on %s(%s);",
        "index_" + tableInfo.getTableName(),
        tableInfo.getTableName(),
        TextUtils.join(",", definitions));
  }
  @SuppressWarnings("unchecked")
  public static String createIndexColumnDefinition(TableInfo tableInfo, Field field) {
    StringBuilder definition = new StringBuilder();

    Class<?> type = field.getType();
    final String name = tableInfo.getColumnName(field);
    final Column column = field.getAnnotation(Column.class);

    if (column.index()) {
      definition.append(name);
    }

    return definition.toString();
  }
  @SuppressWarnings("unchecked")
  public static String createColumnDefinition(TableInfo tableInfo, Field field) {
    StringBuilder definition = new StringBuilder();

    Class<?> type = field.getType();
    final String name = tableInfo.getColumnName(field);
    final TypeSerializer typeSerializer = Cache.getParserForType(field.getType());
    final Column column = field.getAnnotation(Column.class);

    if (typeSerializer != null) {
      type = typeSerializer.getSerializedType();
    }

    if (TYPE_MAP.containsKey(type)) {
      definition.append(name);
      definition.append(" ");
      definition.append(TYPE_MAP.get(type).toString());
    } else if (ReflectionUtils.isModel(type)) {
      definition.append(name);
      definition.append(" ");
      definition.append(SQLiteType.INTEGER.toString());
    } else if (ReflectionUtils.isSubclassOf(type, Enum.class)) {
      definition.append(name);
      definition.append(" ");
      definition.append(SQLiteType.TEXT.toString());
    }

    if (!TextUtils.isEmpty(definition)) {
      if (column.length() > -1) {
        definition.append("(");
        definition.append(column.length());
        definition.append(")");
      }

      if (name.equals("Id")) {
        definition.append(" PRIMARY KEY AUTOINCREMENT");
      }

      if (column.notNull()) {
        definition.append(" NOT NULL ON CONFLICT ");
        definition.append(column.onNullConflict().toString());
      }

      if (column.unique()) {
        definition.append(" UNIQUE ON CONFLICT ");
        definition.append(column.onUniqueConflict().toString());
      }

      if (FOREIGN_KEYS_SUPPORTED && ReflectionUtils.isModel(type)) {
        definition.append(" REFERENCES ");
        definition.append(Cache.getTableInfo((Class<? extends Model>) type).getTableName());
        definition.append("(Id)");
        definition.append(" ON DELETE ");
        definition.append(column.onDelete().toString().replace("_", " "));
        definition.append(" ON UPDATE ");
        definition.append(column.onUpdate().toString().replace("_", " "));
      }
    } else {
      Log.e("No type mapping for: " + type.toString());
    }

    return definition.toString();
  }