<commit_before>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace SQLitePCL.pretty.Orm
{
    public static partial class TableMapping
    { 
        private static string InsertOrReplace<T>(this ITableMapping<T> tableMapping)
        {
            return SQLBuilder.InsertOrReplace(tableMapping.TableName, tableMapping.Columns.Select(x => x.Key));     
        }

        public static ITableMappedStatement<T> PrepareInsertOrReplaceStatement<T>(this IDatabaseConnection This, ITableMapping<T> tableMapping)
        {
            return new TableMappedStatement<T>(This.PrepareStatement(tableMapping.InsertOrReplace()), tableMapping);   
        }

        private static IEnumerable<KeyValuePair<T,T>> YieldInsertOrReplaceAll<T>(this IDatabaseConnection This, ITableMapping<T> tableMapping, IEnumerable<T> objects)
        {
            using (var insertOrReplaceStmt = This.PrepareInsertOrReplaceStatement(tableMapping))
            using (var findStmt = This.PrepareFindByRowId(tableMapping))
            {
                foreach (var obj in objects)
                {
                    insertOrReplaceStmt.Execute(obj);
                    var rowId = This.LastInsertedRowId;
                    yield return new KeyValuePair<T,T>(obj, findStmt.Query(rowId).First());
                } 
            }
        }
            
        public static T InsertOrReplace<T>(this IDatabaseConnection This, ITableMapping<T> tableMapping, T obj)
        {
            return This.YieldInsertOrReplaceAll(tableMapping, new T[] {obj}).First().Value;
        }

        // These are internal for now. Probably will be removed. More likely than not an insert will want to wrapped in a larger transaction.
        // Using the async inserts is terrible for perf as you jump threads.
        internal static Task<T> InsertOrReplaceAsync<T>(this IAsyncDatabaseConnection This, ITableMapping<T> tableMapping, T obj, CancellationToken cancellationToken)
        {
            return This.Use((x, ct) => x.InsertOrReplace(tableMapping, obj), cancellationToken);
        }

        internal static Task<T> InsertOrReplaceAsync<T>(this IAsyncDatabaseConnection This, ITableMapping<T> tableMapping, T obj)
        {
            return This.InsertOrReplaceAsync(tableMapping, obj, CancellationToken.None);
        }

        public static IReadOnlyDictionary<T,T> InsertOrReplaceAll<T>(this IDatabaseConnection This, ITableMapping<T> tableMapping, IEnumerable<T> objects)
        {
            return This.RunInTransaction(_ => 
                This.YieldInsertOrReplaceAll(tableMapping, objects).ToDictionary(kvp => kvp.Key, kvp => kvp.Value));
        }
<commit_msg>Remove the InsertOrReplaceAsync APIs, since they're probably too fine grain to be actually useful.<commit_after>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace SQLitePCL.pretty.Orm
{
    public static partial class TableMapping
    { 
        private static string InsertOrReplace<T>(this ITableMapping<T> tableMapping)
        {
            return SQLBuilder.InsertOrReplace(tableMapping.TableName, tableMapping.Columns.Select(x => x.Key));     
        }

        public static ITableMappedStatement<T> PrepareInsertOrReplaceStatement<T>(this IDatabaseConnection This, ITableMapping<T> tableMapping)
        {
            return new TableMappedStatement<T>(This.PrepareStatement(tableMapping.InsertOrReplace()), tableMapping);   
        }

        private static IEnumerable<KeyValuePair<T,T>> YieldInsertOrReplaceAll<T>(this IDatabaseConnection This, ITableMapping<T> tableMapping, IEnumerable<T> objects)
        {
            using (var insertOrReplaceStmt = This.PrepareInsertOrReplaceStatement(tableMapping))
            using (var findStmt = This.PrepareFindByRowId(tableMapping))
            {
                foreach (var obj in objects)
                {
                    insertOrReplaceStmt.Execute(obj);
                    var rowId = This.LastInsertedRowId;
                    yield return new KeyValuePair<T,T>(obj, findStmt.Query(rowId).First());
                } 
            }
        }
            
        public static T InsertOrReplace<T>(this IDatabaseConnection This, ITableMapping<T> tableMapping, T obj)
        {
            return This.YieldInsertOrReplaceAll(tableMapping, new T[] {obj}).First().Value;
        }

        public static IReadOnlyDictionary<T,T> InsertOrReplaceAll<T>(this IDatabaseConnection This, ITableMapping<T> tableMapping, IEnumerable<T> objects)
        {
            return This.RunInTransaction(_ => 
                This.YieldInsertOrReplaceAll(tableMapping, objects).ToDictionary(kvp => kvp.Key, kvp => kvp.Value));
        }

{'fraction_non_alphanumeric': 0.08508425213230705, 'fraction_numerical': 0.0, 'mean_word_length': 2.837190742218675, 'pattern_counts': {'":': 0, '<': 45, '<?xml version=': 0, '>': 54, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '1883589', 'n_tokens_mistral': 1261, 'n_tokens_neox': 1246, 'n_words': 286}