<commit_before>/*
 * Copyright 2015 <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.javersion.store.jdbc;

import static com.mysema.query.group.GroupBy.groupBy;
import static java.lang.System.arraycopy;
import static java.util.Collections.singleton;
import static java.util.Map.Entry;
import static org.javersion.store.jdbc.RevisionType.REVISION_TYPE;
import static org.springframework.transaction.annotation.Isolation.READ_COMMITTED;
import static org.springframework.transaction.annotation.Propagation.REQUIRED;
import static org.springframework.transaction.annotation.Propagation.REQUIRES_NEW;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Nullable;

import org.javersion.core.Persistent;
import org.javersion.core.Revision;
import org.javersion.core.VersionNode;
import org.javersion.core.VersionType;
import org.javersion.object.ObjectVersion;
import org.javersion.object.ObjectVersionBuilder;
import org.javersion.object.ObjectVersionGraph;
import org.javersion.path.PropertyPath;
import org.javersion.util.Check;
import org.springframework.transaction.annotation.Transactional;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.mysema.commons.lang.Pair;
import com.mysema.query.ResultTransformer;
import com.mysema.query.Tuple;
import com.mysema.query.group.Group;
import com.mysema.query.group.GroupBy;
import com.mysema.query.group.QPair;
import com.mysema.query.sql.Configuration;
import com.mysema.query.sql.SQLQuery;
import com.mysema.query.sql.SQLQueryFactory;
import com.mysema.query.sql.dml.SQLInsertClause;
import com.mysema.query.sql.types.EnumByNameType;
import com.mysema.query.types.Expression;
import com.mysema.query.types.Path;
import com.mysema.query.types.QTuple;
import com.mysema.query.types.expr.SimpleExpression;

public class ObjectVersionStoreJdbc<Id, M> {

    public static void registerTypes(String tablePrefix, Configuration configuration) {
        configuration.register(tablePrefix + "VERSION", "TYPE", new EnumByNameType<>(VersionType.class));
        configuration.register(tablePrefix + "VERSION", "REVISION", REVISION_TYPE);

        configuration.register(tablePrefix + "VERSION_PARENT", "REVISION", REVISION_TYPE);
        configuration.register(tablePrefix + "VERSION_PARENT", "PARENT_REVISION", REVISION_TYPE);

        configuration.register(tablePrefix + "VERSION_PROPERTY", "REVISION", REVISION_TYPE);
    }

    protected final Expression<Long> nextOrdinal;

    protected final JVersion<Id> jVersion;

    protected final JVersionParent jParent;

    protected final JVersionProperty jProperty;

    protected final JRepository jRepository;

    protected final SQLQueryFactory queryFactory;

    protected final Expression<?>[] versionAndParents;

    protected final QPair<Revision, Id> revisionAndDocId;

    protected final ResultTransformer<Map<Revision, List<Tuple>>> properties;

    protected static final String REPOSITORY_ID = "repository";

    protected final Map<PropertyPath, Column> versionTableProperties;

    @SuppressWarnings("unused")
    protected ObjectVersionStoreJdbc() {
        nextOrdinal = null;
        jVersion = null;
        jParent = null;
        jProperty = null;
        jRepository = null;

        versionTableProperties = null;
        versionAndParents = null;
        revisionAndDocId = null;
        properties = null;
        queryFactory = null;
    }

    public <P extends SimpleExpression<Id> & Path<Id>> ObjectVersionStoreJdbc(
            JRepository jRepository,
            Expression<Long> nextOrdinal,
            JVersion<Id> jVersion,
            JVersionParent jParent,
            JVersionProperty jProperty,
            SQLQueryFactory queryFactory) {
        this(jRepository, nextOrdinal, jVersion, jParent, jProperty, queryFactory, ImmutableMap.of());
    }

    public <P extends SimpleExpression<Id> & Path<Id>> ObjectVersionStoreJdbc(
            JRepository jRepository,
            Expression<Long> nextOrdinal,
            JVersion<Id> jVersion,
            JVersionParent jParent,
            JVersionProperty jProperty,
            SQLQueryFactory queryFactory,
            Map<PropertyPath, Column> versionTableProperties) {
        this.nextOrdinal = nextOrdinal;
        this.jRepository = jRepository;
        this.jVersion = jVersion;
        this.jParent = jParent;
        this.jProperty = jProperty;
        this.queryFactory = queryFactory;

        this.versionTableProperties = versionTableProperties;
        versionAndParents = concat(jVersion.all(), GroupBy.set(jParent.parentRevision));
        revisionAndDocId = new QPair<>(jVersion.revision, jVersion.docId.expr);
        properties = groupBy(jProperty.revision).as(GroupBy.list(new QTuple(jProperty.all())));
    }

    @Transactional(readOnly = false, isolation = READ_COMMITTED, propagation = REQUIRED)
    public void append(Id docId, VersionNode<PropertyPath, Object, M> version) {
        append(docId, singleton(version));
    }

    @Transactional(readOnly = false, isolation = READ_COMMITTED, propagation = REQUIRED)
    public void append(Id docId, Iterable<VersionNode<PropertyPath, Object, M>> versions) {
        SQLInsertClause versionBatch = queryFactory.insert(jVersion);
        SQLInsertClause parentBatch = queryFactory.insert(jParent);
        SQLInsertClause propertyBatch = queryFactory.insert(jProperty);

        for (VersionNode<PropertyPath, Object, M> version : versions) {
            addVersion(docId, version, versionBatch);<commit_msg>Defensive immutable copy of versionTableProperties constructor parameter<commit_after>/*
 * Copyright 2015 <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.javersion.store.jdbc;

import static com.mysema.query.group.GroupBy.groupBy;
import static java.lang.System.arraycopy;
import static java.util.Collections.singleton;
import static java.util.Map.Entry;
import static org.javersion.store.jdbc.RevisionType.REVISION_TYPE;
import static org.springframework.transaction.annotation.Isolation.READ_COMMITTED;
import static org.springframework.transaction.annotation.Propagation.REQUIRED;
import static org.springframework.transaction.annotation.Propagation.REQUIRES_NEW;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Nullable;

import org.javersion.core.Persistent;
import org.javersion.core.Revision;
import org.javersion.core.VersionNode;
import org.javersion.core.VersionType;
import org.javersion.object.ObjectVersion;
import org.javersion.object.ObjectVersionBuilder;
import org.javersion.object.ObjectVersionGraph;
import org.javersion.path.PropertyPath;
import org.javersion.util.Check;
import org.springframework.transaction.annotation.Transactional;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.mysema.commons.lang.Pair;
import com.mysema.query.ResultTransformer;
import com.mysema.query.Tuple;
import com.mysema.query.group.Group;
import com.mysema.query.group.GroupBy;
import com.mysema.query.group.QPair;
import com.mysema.query.sql.Configuration;
import com.mysema.query.sql.SQLQuery;
import com.mysema.query.sql.SQLQueryFactory;
import com.mysema.query.sql.dml.SQLInsertClause;
import com.mysema.query.sql.types.EnumByNameType;
import com.mysema.query.types.Expression;
import com.mysema.query.types.Path;
import com.mysema.query.types.QTuple;
import com.mysema.query.types.expr.SimpleExpression;

public class ObjectVersionStoreJdbc<Id, M> {

    public static void registerTypes(String tablePrefix, Configuration configuration) {
        configuration.register(tablePrefix + "VERSION", "TYPE", new EnumByNameType<>(VersionType.class));
        configuration.register(tablePrefix + "VERSION", "REVISION", REVISION_TYPE);

        configuration.register(tablePrefix + "VERSION_PARENT", "REVISION", REVISION_TYPE);
        configuration.register(tablePrefix + "VERSION_PARENT", "PARENT_REVISION", REVISION_TYPE);

        configuration.register(tablePrefix + "VERSION_PROPERTY", "REVISION", REVISION_TYPE);
    }

    protected final Expression<Long> nextOrdinal;

    protected final JVersion<Id> jVersion;

    protected final JVersionParent jParent;

    protected final JVersionProperty jProperty;

    protected final JRepository jRepository;

    protected final SQLQueryFactory queryFactory;

    protected final Expression<?>[] versionAndParents;

    protected final QPair<Revision, Id> revisionAndDocId;

    protected final ResultTransformer<Map<Revision, List<Tuple>>> properties;

    protected static final String REPOSITORY_ID = "repository";

    protected final Map<PropertyPath, Column> versionTableProperties;

    @SuppressWarnings("unused")
    protected ObjectVersionStoreJdbc() {
        nextOrdinal = null;
        jVersion = null;
        jParent = null;
        jProperty = null;
        jRepository = null;

        versionTableProperties = null;
        versionAndParents = null;
        revisionAndDocId = null;
        properties = null;
        queryFactory = null;
    }

    public <P extends SimpleExpression<Id> & Path<Id>> ObjectVersionStoreJdbc(
            JRepository jRepository,
            Expression<Long> nextOrdinal,
            JVersion<Id> jVersion,
            JVersionParent jParent,
            JVersionProperty jProperty,
            SQLQueryFactory queryFactory) {
        this(jRepository, nextOrdinal, jVersion, jParent, jProperty, queryFactory, ImmutableMap.of());
    }

    public <P extends SimpleExpression<Id> & Path<Id>> ObjectVersionStoreJdbc(
            JRepository jRepository,
            Expression<Long> nextOrdinal,
            JVersion<Id> jVersion,
            JVersionParent jParent,
            JVersionProperty jProperty,
            SQLQueryFactory queryFactory,
            Map<PropertyPath, Column> versionTableProperties) {
        this.nextOrdinal = nextOrdinal;
        this.jRepository = jRepository;
        this.jVersion = jVersion;
        this.jParent = jParent;
        this.jProperty = jProperty;
        this.queryFactory = queryFactory;

        this.versionTableProperties = ImmutableMap.copyOf(versionTableProperties);
        versionAndParents = concat(jVersion.all(), GroupBy.set(jParent.parentRevision));
        revisionAndDocId = new QPair<>(jVersion.revision, jVersion.docId.expr);
        properties = groupBy(jProperty.revision).as(GroupBy.list(new QTuple(jProperty.all())));
    }

    @Transactional(readOnly = false, isolation = READ_COMMITTED, propagation = REQUIRED)
    public void append(Id docId, VersionNode<PropertyPath, Object, M> version) {
        append(docId, singleton(version));
    }

    @Transactional(readOnly = false, isolation = READ_COMMITTED, propagation = REQUIRED)
    public void append(Id docId, Iterable<VersionNode<PropertyPath, Object, M>> versions) {
        SQLInsertClause versionBatch = queryFactory.insert(jVersion);
        SQLInsertClause parentBatch = queryFactory.insert(jParent);
        SQLInsertClause propertyBatch = queryFactory.insert(jProperty);

        for (VersionNode<PropertyPath, Object, M> version : versions) {
            addVersion(docId, version, versionBatch);
{'fraction_non_alphanumeric': 0.09054054054054055, 'fraction_numerical': 0.0012718600953895071, 'mean_word_length': 4.114227642276423, 'pattern_counts': {'":': 0, '<': 57, '<?xml version=': 0, '>': 57, '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': '2148443', 'n_tokens_mistral': 3498, 'n_tokens_neox': 3449, 'n_words': 809}