Пример #1
0
  @Override
  public final void from(Object source, Field<?>... f) {
    if (source == null) return;

    // [#1987] Distinguish between various types to load data from
    // Maps are loaded using a {field-name -> value} convention
    if (source instanceof Map) {
      fromMap((Map<String, ?>) source, f);
    }

    // Arrays are loaded through index mapping
    else if (source instanceof Object[]) {
      fromArray((Object[]) source, f);
    }

    // All other types are expected to be POJOs
    else {
      Class<?> type = source.getClass();

      try {
        boolean useAnnotations = hasColumnAnnotations(configuration(), type);

        for (Field<?> field : f) {
          List<java.lang.reflect.Field> members;
          Method method;

          // Annotations are available and present
          if (useAnnotations) {
            members = getAnnotatedMembers(configuration(), type, field.getName());
            method = getAnnotatedGetter(configuration(), type, field.getName());
          }

          // No annotations are present
          else {
            members = getMatchingMembers(configuration(), type, field.getName());
            method = getMatchingGetter(configuration(), type, field.getName());
          }

          // Use only the first applicable method or member
          if (method != null) {
            Utils.setValue(this, field, method.invoke(source));
          } else if (members.size() > 0) {
            from(source, members.get(0), field);
          }
        }
      }

      // All reflection exceptions are intercepted
      catch (Exception e) {
        throw new MappingException("An error ocurred when mapping record from " + type, e);
      }
    }
  }
Пример #2
0
  @Override
  public final Document intoXML() {
    final int size = getFields().size();

    try {
      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
      DocumentBuilder builder = factory.newDocumentBuilder();
      Document document = builder.newDocument();

      Element eResult = document.createElement("result");
      eResult.setAttribute("xmlns", "http://www.jooq.org/xsd/jooq-export-2.6.0.xsd");
      document.appendChild(eResult);

      Element eFields = document.createElement("fields");
      eResult.appendChild(eFields);

      for (Field<?> field : getFields()) {
        Element eField = document.createElement("field");
        eField.setAttribute("name", field.getName());
        eField.setAttribute("type", field.getDataType().getTypeName().toUpperCase());
        eFields.appendChild(eField);
      }

      Element eRecords = document.createElement("records");
      eResult.appendChild(eRecords);

      for (Record record : this) {
        Element eRecord = document.createElement("record");
        eRecords.appendChild(eRecord);

        for (int index = 0; index < size; index++) {
          Field<?> field = getField(index);
          Object value = record.getValue(index);

          Element eValue = document.createElement("value");
          eValue.setAttribute("field", field.getName());
          eRecord.appendChild(eValue);

          if (value != null) {
            eValue.setTextContent(format0(value));
          }
        }
      }

      return document;
    } catch (ParserConfigurationException ignore) {
      throw new RuntimeException(ignore);
    }
  }
Пример #3
0
  @Override
  public final String formatXML() {
    final int size = getFields().size();

    StringBuilder sb = new StringBuilder();

    sb.append("<result xmlns=\"http://www.jooq.org/xsd/jooq-export-2.6.0.xsd\">");
    sb.append("<fields>");

    for (Field<?> field : getFields()) {
      sb.append("<field name=\"");
      sb.append(escapeXML(field.getName()));
      sb.append("\" ");
      sb.append("type=\"");
      sb.append(field.getDataType().getTypeName().toUpperCase());
      sb.append("\"/>");
    }

    sb.append("</fields>");
    sb.append("<records>");

    for (Record record : this) {
      sb.append("<record>");

      for (int index = 0; index < size; index++) {
        Field<?> field = getField(index);
        Object value = record.getValue(index);

        sb.append("<value field=\"");
        sb.append(escapeXML(field.getName()));
        sb.append("\"");

        if (value == null) {
          sb.append("/>");
        } else {
          sb.append(">");
          sb.append(escapeXML(format0(value)));
          sb.append("</value>");
        }
      }

      sb.append("</record>");
    }

    sb.append("</records>");
    sb.append("</result>");

    return sb.toString();
  }
Пример #4
0
  @Override
  public final Map<String, Object> intoMap() {
    Map<String, Object> map = new LinkedHashMap<String, Object>();

    int size = fields.size();
    for (int i = 0; i < size; i++) {
      Field<?> field = fields.field(i);

      if (map.put(field.getName(), getValue(i)) != null) {
        throw new InvalidResultException(
            "Field " + field.getName() + " is not unique in Record : " + this);
      }
    }

    return map;
  }
Пример #5
0
  @Override
  public final String formatJSON() {
    List<Map<String, String>> f = new ArrayList<Map<String, String>>();
    List<List<Object>> r = new ArrayList<List<Object>>();

    Map<String, String> fieldMap;
    for (Field<?> field : fields) {
      fieldMap = new LinkedHashMap<String, String>();
      fieldMap.put("name", field.getName());
      fieldMap.put("type", field.getDataType().getTypeName().toUpperCase());

      f.add(fieldMap);
    }

    for (Record record : this) {
      List<Object> list = new ArrayList<Object>();

      for (int index = 0; index < fields.fields.length; index++) {
        list.add(record.getValue(index));
      }

      r.add(list);
    }

    Map<String, List<?>> map = new LinkedHashMap<String, List<?>>();

    map.put("fields", f);
    map.put("records", r);

    return JSONObject.toJSONString(map);
  }
Пример #6
0
  @Override
  public final String formatCSV(char delimiter, String nullString) {
    StringBuilder sb = new StringBuilder();

    String sep1 = "";
    for (Field<?> field : fields) {
      sb.append(sep1);
      sb.append(formatCSV0(field.getName(), ""));

      sep1 = Character.toString(delimiter);
    }

    sb.append("\n");

    for (Record record : this) {
      String sep2 = "";

      for (int index = 0; index < fields.fields.length; index++) {
        sb.append(sep2);
        sb.append(formatCSV0(record.getValue(index), nullString));

        sep2 = Character.toString(delimiter);
      }

      sb.append("\n");
    }

    return sb.toString();
  }
Пример #7
0
  @Override
  public final String formatHTML() {
    StringBuilder sb = new StringBuilder();

    sb.append("<table>");
    sb.append("<thead>");
    sb.append("<tr>");

    for (Field<?> field : fields) {
      sb.append("<th>");
      sb.append(field.getName());
      sb.append("</th>");
    }

    sb.append("</tr>");
    sb.append("</thead>");
    sb.append("<tbody>");

    for (Record record : this) {
      sb.append("<tr>");

      for (int index = 0; index < fields.fields.length; index++) {
        sb.append("<td>");
        sb.append(format0(record.getValue(index), false));
        sb.append("</td>");
      }

      sb.append("</tr>");
    }

    sb.append("</tbody>");
    sb.append("</table>");

    return sb.toString();
  }
Пример #8
0
 private String[] getTableColumnNames() {
   if (databaseDescriptor == null) {
     return new String[0];
   }
   Set<String> columnNameSet = new HashSet<String>();
   for (Table<?> table : databaseDescriptor.getSchema().getTables()) {
     for (Field<?> field : table.getFields()) {
       String columnName = field.getName();
       columnNameSet.add(columnName);
     }
   }
   String[] columnNames = columnNameSet.toArray(new String[0]);
   Arrays.sort(columnNames, String.CASE_INSENSITIVE_ORDER);
   return columnNames;
 }
Пример #9
0
  private static final Fields init(String alias, Class<?> arrayType) {
    List<Field<?>> result = new ArrayList<Field<?>>();

    // [#1114] VARRAY/TABLE of OBJECT have more than one field
    if (UDTRecord.class.isAssignableFrom(arrayType)) {
      try {
        UDTRecord<?> record = (UDTRecord<?>) arrayType.newInstance();
        for (Field<?> f : record.fields()) {
          result.add(fieldByName(f.getDataType(), alias, f.getName()));
        }
      } catch (Exception e) {
        throw new DataTypeException("Bad UDT Type : " + arrayType, e);
      }
    }

    // Simple array types have a synthetic field called "COLUMN_VALUE"
    else {
      result.add(fieldByName(Factory.getDataType(arrayType), alias, "COLUMN_VALUE"));
    }

    return new Fields(result);
  }
Пример #10
0
    ImmutablePOJOMapperWithConstructorProperties(
        Constructor<E> constructor, ConstructorProperties properties) {
      this.constructor = constructor;
      this.propertyNames = Arrays.asList(properties.value());
      this.useAnnotations = hasColumnAnnotations(configuration, type);
      this.parameterTypes = constructor.getParameterTypes();
      this.parameterValues = new Object[parameterTypes.length];
      this.members = new List[fields.length];
      this.methods = new Method[fields.length];
      this.propertyIndexes = new Integer[fields.length];

      for (int i = 0; i < fields.length; i++) {
        Field<?> field = fields[i];
        String name = field.getName();
        String nameLC = StringUtils.toCamelCaseLC(name);

        // Annotations are available and present
        if (useAnnotations) {
          members[i] = getAnnotatedMembers(configuration, type, name);
          methods[i] = getAnnotatedGetter(configuration, type, name);
        }

        // No annotations are present
        else {
          members[i] = getMatchingMembers(configuration, type, name);
          methods[i] = getMatchingGetter(configuration, type, name);
        }

        // [#3911] Liberal interpretation of the @ConstructorProperties specs:
        // We also accept properties that don't have a matching getter or member
        for (int j = 0; j < propertyNames.size(); j++) {
          if (name.equals(propertyNames.get(j)) || nameLC.equals(propertyNames.get(j))) {
            propertyIndexes[i] = j;
            break;
          }
        }
      }
    }
Пример #11
0
  @Override
  public final String formatHTML() {
    final int size = getFields().size();

    StringBuilder sb = new StringBuilder();

    sb.append("<table>");
    sb.append("<thead>");
    sb.append("<tr>");

    for (Field<?> field : getFields()) {
      sb.append("<th>");
      sb.append(field.getName());
      sb.append("</th>");
    }

    sb.append("</tr>");
    sb.append("</thead>");
    sb.append("<tbody>");

    for (Record record : this) {
      sb.append("<tr>");

      for (int index = 0; index < size; index++) {
        sb.append("<td>");
        sb.append(format0(record.getValue(index)));
        sb.append("</td>");
      }

      sb.append("</tr>");
    }

    sb.append("</tbody>");
    sb.append("</table>");

    return sb.toString();
  }
Пример #12
0
  @Override
  protected final void prepare(ExecuteContext ctx) throws SQLException {
    Connection connection = ctx.connection();

    // Just in case, always set Sybase ASE statement mode to return
    // Generated keys if client code wants to SELECT @@identity afterwards
    if (ctx.configuration().dialect() == SQLDialect.ASE) {
      ctx.statement(connection.prepareStatement(ctx.sql(), Statement.RETURN_GENERATED_KEYS));
      return;
    }

    // Normal statement preparing if no values should be returned
    else if (returning.isEmpty()) {
      super.prepare(ctx);
      return;
    }

    // Values should be returned from the INSERT
    else {
      switch (ctx.configuration().dialect()) {

          // Postgres uses the RETURNING clause in SQL
        case FIREBIRD:
        case POSTGRES:
          // SQLite will select last_insert_rowid() after the INSER
        case SQLITE:
          // Sybase will select @@identity after the INSERT
        case CUBRID:
        case SYBASE:
          super.prepare(ctx);
          return;

          // Some dialects can only return AUTO_INCREMENT values
          // Other values have to be fetched in a second step
          // [#1260] TODO CUBRID supports this, but there's a JDBC bug
        case ASE:
        case DERBY:
        case H2:
        case INGRES:
        case MYSQL:
        case SQLSERVER:
          ctx.statement(connection.prepareStatement(ctx.sql(), Statement.RETURN_GENERATED_KEYS));
          return;

          // The default is to return all requested fields directly
        case DB2:
        case HSQLDB:
        case ORACLE:
        default:
          {
            List<String> names = new ArrayList<String>();

            for (Field<?> field : returning) {
              names.add(field.getName());
            }

            ctx.statement(
                connection.prepareStatement(ctx.sql(), names.toArray(new String[names.size()])));
            return;
          }
      }
    }
  }
Пример #13
0
    MutablePOJOMapper(Constructor<? extends E> constructor, E instance) {
      this.constructor = accessible(constructor);
      this.useAnnotations = hasColumnAnnotations(configuration, type);
      this.members = new List[fields.length];
      this.methods = new List[fields.length];
      this.nested = new HashMap<String, List<RecordMapper<R, Object>>>();
      this.instance = instance;

      Map<String, Field<?>[]> nestedFields = new HashMap<String, Field<?>[]>();
      for (int i = 0; i < fields.length; i++) {
        Field<?> field = fields[i];
        String name = field.getName();

        // Annotations are available and present
        if (useAnnotations) {
          members[i] = getAnnotatedMembers(configuration, type, name);
          methods[i] = getAnnotatedSetters(configuration, type, name);
        }

        // No annotations are present
        else {
          int dot = name.indexOf('.');

          // A nested mapping is applied
          if (dot > -1) {
            String prefix = name.substring(0, dot);

            Field<?>[] f = nestedFields.get(prefix);
            if (f == null) {
              f = nCopies(fields.length, field("")).toArray(new Field[fields.length]);
              nestedFields.put(prefix, f);
            }

            f[i] = field(name(name.substring(prefix.length() + 1)), field.getDataType());

            members[i] = Collections.emptyList();
            methods[i] = Collections.emptyList();
          }

          // A top-level mapping is applied
          else {
            members[i] = getMatchingMembers(configuration, type, name);
            methods[i] = getMatchingSetters(configuration, type, name);
          }
        }
      }

      for (Entry<String, Field<?>[]> entry : nestedFields.entrySet()) {
        String prefix = entry.getKey();
        List<RecordMapper<R, Object>> list = new ArrayList<RecordMapper<R, Object>>();

        for (java.lang.reflect.Field member : getMatchingMembers(configuration, type, prefix)) {
          list.add(
              new RemovingPrefixRecordMapper(
                  new DefaultRecordMapper<R, Object>(
                      new Fields<R>(entry.getValue()), member.getType(), null, configuration),
                  fields,
                  prefix));
        }

        for (Method method : getMatchingSetters(configuration, type, prefix)) {
          list.add(
              new RemovingPrefixRecordMapper(
                  new DefaultRecordMapper<R, Object>(
                      new Fields<R>(entry.getValue()),
                      method.getParameterTypes()[0],
                      null,
                      configuration),
                  fields,
                  prefix));
        }

        nested.put(prefix, list);
      }
    }
Пример #14
0
  Neg(Field<T> field, ExpressionOperator operator) {
    super(operator.toSQL() + field.getName(), field.getDataType());

    this.operator = operator;
    this.field = field;
  }
Пример #15
0
  @Override
  public final String format(int maxRecords) {
    final int COL_MIN_WIDTH = 4;
    final int COL_MAX_WIDTH = 50;

    // Numeric columns have greater max width because values are aligned
    final int NUM_COL_MAX_WIDTH = 100;

    // The max number of records that will be considered for formatting purposes
    final int MAX_RECORDS = min(50, maxRecords);

    // Get max decimal places for numeric type columns
    final int size = getFields().size();
    final int[] decimalPlaces = new int[size];
    final int[] widths = new int[size];

    for (int index = 0; index < size; index++) {
      Field<?> f = getField(index);

      if (Number.class.isAssignableFrom(f.getType())) {
        List<Integer> decimalPlacesList = new ArrayList<Integer>();

        // Initialize
        decimalPlacesList.add(0);

        // Collect all decimal places for the column values
        String value;
        for (int i = 0; i < min(MAX_RECORDS, size()); i++) {
          value = format0(getValue(i, index));
          decimalPlacesList.add(getDecimalPlaces(value));
        }

        // Find max
        decimalPlaces[index] = Collections.max(decimalPlacesList);
      }
    }

    // Get max column widths
    int colMaxWidth;
    for (int index = 0; index < size; index++) {
      Field<?> f = getField(index);

      // Is number column?
      boolean isNumCol = Number.class.isAssignableFrom(f.getType());

      colMaxWidth = isNumCol ? NUM_COL_MAX_WIDTH : COL_MAX_WIDTH;

      // Collect all widths for the column
      List<Integer> widthList = new ArrayList<Integer>();

      // Add column name width first
      widthList.add(min(colMaxWidth, max(COL_MIN_WIDTH, f.getName().length())));

      // Add column values width
      String value;
      for (int i = 0; i < min(MAX_RECORDS, size()); i++) {
        value = format0(getValue(i, index));
        // Align number values before width is calculated
        if (isNumCol) {
          value = alignNumberValue(decimalPlaces[index], value);
        }

        widthList.add(min(colMaxWidth, value.length()));
      }

      // Find max
      widths[index] = Collections.max(widthList);
    }

    // Begin the writing
    // ---------------------------------------------------------------------
    StringBuilder sb = new StringBuilder();

    // Write top line
    sb.append("+");
    for (int index = 0; index < size; index++) {
      sb.append(rightPad("", widths[index], "-"));
      sb.append("+");
    }

    // Write headers
    sb.append("\n|");
    for (int index = 0; index < size; index++) {
      Field<?> f = getField(index);
      String padded;

      if (Number.class.isAssignableFrom(f.getType())) {
        padded = leftPad(f.getName(), widths[index]);
      } else {
        padded = rightPad(f.getName(), widths[index]);
      }

      sb.append(abbreviate(padded, widths[index]));
      sb.append("|");
    }

    // Write separator
    sb.append("\n+");
    for (int index = 0; index < size; index++) {
      sb.append(rightPad("", widths[index], "-"));
      sb.append("+");
    }

    // Write columns
    for (int i = 0; i < min(maxRecords, size()); i++) {
      sb.append("\n|");

      for (int index = 0; index < size; index++) {
        Field<?> f = getField(index);
        String value = format0(getValue(i, index)).replace("\n", "{lf}").replace("\r", "{cr}");

        String padded;
        if (Number.class.isAssignableFrom(f.getType())) {
          // Align number value before left pad
          value = alignNumberValue(decimalPlaces[index], value);

          // Left pad
          padded = leftPad(value, widths[index]);
        } else {
          // Right pad
          padded = rightPad(value, widths[index]);
        }

        sb.append(abbreviate(padded, widths[index]));
        sb.append("|");
      }
    }

    // Write bottom line
    if (size() > 0) {
      sb.append("\n+");

      for (int index = 0; index < size; index++) {
        sb.append(rightPad("", widths[index], "-"));
        sb.append("+");
      }
    }

    // Write truncation message, if applicable
    if (maxRecords < size()) {
      sb.append("\n|...");
      sb.append(size() - maxRecords);
      sb.append(" record(s) truncated...");
    }

    return sb.toString();
  }
Пример #16
0
    private Table<Record> select(Configuration configuration) {
      List<Field<?>> groupingFields = new ArrayList<Field<?>>();
      List<Field<?>> aliasedGroupingFields = new ArrayList<Field<?>>();
      List<Field<?>> aggregatedFields = new ArrayList<Field<?>>();

      Table<?> pivot = table.as("pivot_outer");

      // Clearly, the API should be improved to make this more object-
      // oriented...

      // This loop finds all fields that are used in aggregate
      // functions. They're excluded from the GROUP BY clause
      for (Field<?> field : aggregateFunctions) {
        if (field instanceof Function) {
          for (QueryPart argument : ((Function<?>) field).getArguments()) {
            if (argument instanceof Field) {
              aggregatedFields.add((Field<?>) argument);
            }
          }
        }
      }

      // This loop finds all fields qualify for GROUP BY clauses
      for (Field<?> field : table.fields()) {
        if (!aggregatedFields.contains(field)) {
          if (!on.equals(field)) {
            aliasedGroupingFields.add(pivot.field(field));
            groupingFields.add(field);
          }
        }
      }

      // The product {aggregateFunctions} x {in}
      List<Field<?>> aggregationSelects = new ArrayList<Field<?>>();
      for (Field<?> inField : in) {
        for (Field<?> aggregateFunction : aggregateFunctions) {
          Condition join = trueCondition();

          for (Field<?> field : groupingFields) {
            join = join.and(condition(pivot, field));
          }

          @SuppressWarnings("unchecked")
          Select<?> aggregateSelect =
              using(configuration)
                  .select(aggregateFunction)
                  .from(table)
                  .where(on.equal((Field<T>) inField))
                  .and(join);

          aggregationSelects.add(
              aggregateSelect.asField(inField.getName() + "_" + aggregateFunction.getName()));
        }
      }

      // This is the complete select
      Table<Record> select =
          using(configuration)
              .select(aliasedGroupingFields)
              .select(aggregationSelects)
              .from(pivot)
              .where(pivot.field(on).in(in.toArray(new Field[0])))
              .groupBy(aliasedGroupingFields)
              .asTable();

      return select;
    }