<commit_before>/*
 *  Copyright 2009-2013 <NAME>
 *
 *  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 org.ujorm.orm.metaModel;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.StringTokenizer;
import org.ujorm.Key;
import org.ujorm.Ujo;
import org.ujorm.core.KeyFactory;
import org.ujorm.core.UjoManager;
import org.ujorm.core.annot.Immutable;
import org.ujorm.implementation.orm.RelationToOne;
import org.ujorm.orm.ColumnWrapper;
import org.ujorm.orm.DbType;
import org.ujorm.orm.ForeignKey;
import org.ujorm.orm.ITypeService;
import org.ujorm.orm.OrmUjo;
import org.ujorm.orm.SqlDialect;
import org.ujorm.orm.TypeService;
import org.ujorm.orm.annot.Column;
import org.ujorm.orm.annot.Comment;
import org.ujorm.orm.ao.UjoStatement;

/**
 * Database column metadata
 * @author <NAME>
 * @composed 1 - * DbType
 */
@Immutable
public final class MetaColumn extends MetaRelation2Many implements ColumnWrapper {
    private static final Class<MetaColumn> CLASS = MetaColumn.class;

    /** Property Factory */
    private static final KeyFactory<MetaColumn> fa = KeyFactory.CamelBuilder.get(CLASS);
    /** DB primary key */
    public static final Key<MetaColumn,Boolean> PRIMARY_KEY = fa.newKey("primaryKey", false);
    /** Database Type */
    public static final Key<MetaColumn,DbType> DB_TYPE = fa.newKey("dbType", DbType.Automatic);
    /** Column NOT-NULL */
    public static final Key<MetaColumn,Boolean> MANDATORY = fa.newKey("mandatory", false);
    /** Column value length */
    public static final Key<MetaColumn,Integer> MAX_LENGTH = fa.newKey("maxLength", -1);
    /** Column value precision */
    public static final Key<MetaColumn,Integer> PRECISION = fa.newKey("precision", -1);
    /** DB Default value */
    public static final Key<MetaColumn,String> DEFAULT_VALUE = fa.newKey("default", "");
    /** A name of the non-unique database index for the column, where the same index can contain more columns.
     * If a single column of the index is marked as unique, so the entire index will be unique. */
    public static final Key<MetaColumn,String> INDEX = fa.newKey("index", "");
    /** A name of the unique database index for the column, where the same index can contain more columns.
     * If a single column of the index is marked as unique, so the entire index will be unique. */
    public static final Key<MetaColumn,String> UNIQUE_INDEX = fa.newKey("uniqueIndex", "");
    /** A name of the constraint for the case a foreign key */
    public static final Key<MetaColumn,String> CONSTRAINT_NAME = fa.newKey("constraintName", "");
    /** Convert, save and read application data from/to the database */
    public static final Key<MetaColumn,Class<? extends ITypeService>> CONVERTER = fa.newClassKey("converter", ITypeService.class);
    /** Comment of the database column */
    public static final Key<MetaColumn,String> COMMENT = fa.newKey("comment", Comment.NULL);
    /** The property initialization */
    static{fa.lock();}

    /** If current column is a foreign key than related model is a related table column (primarky key by default). */
    private List<MetaColumn> relatedModel;
    /** Foreign column names. */
    private String[] foreignNames = null;
    private static final String[] EMPTY_NAMES = new String[0];
    /** A <b>Java Type Code<b> to a quick JDBC management.
     * @see TypeService#getTypeCode(org.ujorm.orm.metaModel.MetaColumn)
     */
    private char typeCode;
    private boolean foreignKey;
    /** Type converter. Value is Notnull allvays. */
    final private ITypeService converter;


    public MetaColumn() {
        this(null);
    }

    public MetaColumn(ITypeService converter) {
        this.converter = converter;
    }

    public MetaColumn(MetaTable table, Key tableProperty, MetaColumn param) {
        super(table, tableProperty, param);
        this.foreignKey = isTypeOf(OrmUjo.class);

        Field field = UjoManager.getInstance().getPropertyField(table.getType(), tableProperty);
        Column column = field!=null ? field.getAnnotation(Column.class) : null;

        if (param!=null) {
            changeDefault(this, PRIMARY_KEY, PRIMARY_KEY.of(param));
            changeDefault(this, MANDATORY  , MANDATORY.of(param));
            changeDefault(this, MAX_LENGTH , MAX_LENGTH.of(param));
            changeDefault(this, PRECISION  , PRECISION.of(param));
            changeDefault(this, DB_TYPE    , DB_TYPE.of(param));
            changeDefault(this, INDEX      , INDEX.of(param));
            changeDefault(this, UNIQUE_INDEX,UNIQUE_INDEX.of(param));
            changeDefault(this, COMMENT    , COMMENT.of(param));
            changeDefault(this, CONVERTER  , CONVERTER.of(param));
        }
        if (column!=null) {
            changeDefault(this, PRIMARY_KEY, column.pk());
            changeDefault(this, MANDATORY  , column.mandatory());
            changeDefault(this, MAX_LENGTH , column.length());
            changeDefault(this, PRECISION  , column.precision());
            changeDefault(this, DB_TYPE    , column.type());
            changeDefault(this, INDEX      , column.index());
            changeDefault(this, UNIQUE_INDEX,column.uniqueIndex());
            changeDefault(this, CONSTRAINT_NAME, column.constraintName());
            changeDefault(this, CONVERTER  , column.converter());
        }

        // Assign Comments:
        if (field!=null) {
            Comment comment = field.getAnnotation(Comment.class);
            if (comment!=null) changeDefault(this, COMMENT  , comment.value());
        }

        // Assign the Converter:
        final Class converterType = CONVERTER.isDefault(this) ? null : CONVERTER.of(this);
        converter = getHandler().getParameters().getConverter(converterType);

        // DB Type must be assigned after to create the converter instance:
        if (DB_TYPE.isDefault(this)) {<commit_msg>Dabase constrains NOT NULL and the LENGTH of VARCHAR can be assigned form a key Validator. The Validator value have got a lower priority than an annotations.<commit_after>/*
 *  Copyright 2009-2013 <NAME>
 *
 *  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 org.ujorm.orm.metaModel;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.StringTokenizer;
import org.ujorm.Key;
import org.ujorm.Ujo;
import org.ujorm.Validator;
import org.ujorm.core.KeyFactory;
import org.ujorm.core.UjoManager;
import org.ujorm.core.annot.Immutable;
import org.ujorm.implementation.orm.RelationToOne;
import org.ujorm.orm.ColumnWrapper;
import org.ujorm.orm.DbType;
import org.ujorm.orm.ForeignKey;
import org.ujorm.orm.ITypeService;
import org.ujorm.orm.OrmUjo;
import org.ujorm.orm.SqlDialect;
import org.ujorm.orm.TypeService;
import org.ujorm.orm.annot.Column;
import org.ujorm.orm.annot.Comment;
import org.ujorm.orm.ao.UjoStatement;
import org.ujorm.validator.ValidatorUtils;

/**
 * Database column metadata
 * @author <NAME>
 * @composed 1 - * DbType
 */
@Immutable
public final class MetaColumn extends MetaRelation2Many implements ColumnWrapper {
    private static final Class<MetaColumn> CLASS = MetaColumn.class;

    /** Property Factory */
    private static final KeyFactory<MetaColumn> fa = KeyFactory.CamelBuilder.get(CLASS);
    /** DB primary key */
    public static final Key<MetaColumn,Boolean> PRIMARY_KEY = fa.newKey("primaryKey", false);
    /** Database Type */
    public static final Key<MetaColumn,DbType> DB_TYPE = fa.newKey("dbType", DbType.Automatic);
    /** Column NOT-NULL */
    public static final Key<MetaColumn,Boolean> MANDATORY = fa.newKey("mandatory", false);
    /** Column value length */
    public static final Key<MetaColumn,Integer> MAX_LENGTH = fa.newKey("maxLength", -1);
    /** Column value precision */
    public static final Key<MetaColumn,Integer> PRECISION = fa.newKey("precision", -1);
    /** DB Default value */
    public static final Key<MetaColumn,String> DEFAULT_VALUE = fa.newKey("default", "");
    /** A name of the non-unique database index for the column, where the same index can contain more columns.
     * If a single column of the index is marked as unique, so the entire index will be unique. */
    public static final Key<MetaColumn,String> INDEX = fa.newKey("index", "");
    /** A name of the unique database index for the column, where the same index can contain more columns.
     * If a single column of the index is marked as unique, so the entire index will be unique. */
    public static final Key<MetaColumn,String> UNIQUE_INDEX = fa.newKey("uniqueIndex", "");
    /** A name of the constraint for the case a foreign key */
    public static final Key<MetaColumn,String> CONSTRAINT_NAME = fa.newKey("constraintName", "");
    /** Convert, save and read application data from/to the database */
    public static final Key<MetaColumn,Class<? extends ITypeService>> CONVERTER = fa.newClassKey("converter", ITypeService.class);
    /** Comment of the database column */
    public static final Key<MetaColumn,String> COMMENT = fa.newKey("comment", Comment.NULL);
    /** The property initialization */
    static{fa.lock();}

    /** If current column is a foreign key than related model is a related table column (primarky key by default). */
    private List<MetaColumn> relatedModel;
    /** Foreign column names. */
    private String[] foreignNames = null;
    private static final String[] EMPTY_NAMES = new String[0];
    /** A <b>Java Type Code<b> to a quick JDBC management.
     * @see TypeService#getTypeCode(org.ujorm.orm.metaModel.MetaColumn)
     */
    private char typeCode;
    private boolean foreignKey;
    /** Type converter. Value is Notnull allvays. */
    final private ITypeService converter;


    public MetaColumn() {
        this(null);
    }

    public MetaColumn(ITypeService converter) {
        this.converter = converter;
    }

    public MetaColumn(MetaTable table, Key tableProperty, MetaColumn param) {
        super(table, tableProperty, param);
        this.foreignKey = isTypeOf(OrmUjo.class);

        Field field = UjoManager.getInstance().getPropertyField(table.getType(), tableProperty);
        Column column = field!=null ? field.getAnnotation(Column.class) : null;

        if (param!=null) {
            changeDefault(this, PRIMARY_KEY, PRIMARY_KEY.of(param));
            changeDefault(this, MANDATORY  , MANDATORY.of(param));
            changeDefault(this, MAX_LENGTH , MAX_LENGTH.of(param));
            changeDefault(this, PRECISION  , PRECISION.of(param));
            changeDefault(this, DB_TYPE    , DB_TYPE.of(param));
            changeDefault(this, INDEX      , INDEX.of(param));
            changeDefault(this, UNIQUE_INDEX,UNIQUE_INDEX.of(param));
            changeDefault(this, COMMENT    , COMMENT.of(param));
            changeDefault(this, CONVERTER  , CONVERTER.of(param));
        }
        if (column!=null) {
            changeDefault(this, PRIMARY_KEY, column.pk());
            changeDefault(this, MANDATORY  , column.mandatory());
            changeDefault(this, MAX_LENGTH , column.length());
            changeDefault(this, PRECISION  , column.precision());
            changeDefault(this, DB_TYPE    , column.type());
            changeDefault(this, INDEX      , column.index());
            changeDefault(this, UNIQUE_INDEX,column.uniqueIndex());
            changeDefault(this, CONSTRAINT_NAME, column.constraintName());
            changeDefault(this, CONVERTER  , column.converter());
        }
        
        final Validator validator = tableProperty.getValidator();
        if (validator != null) {
            changeDefault(this, MANDATORY , ValidatorUtils.isMandatoryValidator(validator));
            changeDefault(this, MAX_LENGTH, ValidatorUtils.getMaxLength(validator));
        }

        // Assign Comments:
        if (field!=null) {
            Comment comment = field.getAnnotation(Comment.class);
            if (comment!=null) changeDefault(this, COMMENT  , comment.value());
        }

        // Assign the Converter:
        final Class converterType = CONVERTER.isDefault(this) ? null : CONVERTER.of(this);
        converter = getHandler().getParameters().getConverter(converterType);

        // DB Type must be assigned after to create the converter instance:
        if (DB_TYPE.isDefault(this)) {
{'fraction_non_alphanumeric': 0.10804001482030381, 'fraction_numerical': 0.0025194516487587995, 'mean_word_length': 3.356358941252421, 'pattern_counts': {'":': 0, '<': 41, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3635154', 'n_tokens_mistral': 3818, 'n_tokens_neox': 3751, 'n_words': 1113}