<commit_before>﻿using Silk.Data.Modelling;
using Silk.Data.Modelling.Mapping;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace Silk.Data.SQL.ORM.Schema
{
	/// <summary>
	/// Builds the schema components for a specific entity type.
	/// </summary>
	public interface IEntitySchemaBuilder
	{
		/// <summary>
		/// Creates the IEntitySchemaAssemblage that will be used to construct the EntitySchema populated with any declared fields that are SQL primitives and don't require any joins.
		/// </summary>
		/// <returns></returns>
		IEntitySchemaAssemblage CreateAssemblage();

		/// <summary>
		/// Builds the completed entity schema.
		/// </summary>
		/// <returns></returns>
		EntitySchema BuildSchema();

		Dictionary<ISchemaField, FieldOperations> BuildFieldOperations();
	}

	/// <summary>
	/// Builds the schema components for entities of type T.
	/// </summary>
	public class EntitySchemaBuilder<T> : IEntitySchemaBuilder
		where T : class
	{
		private readonly TypeModel<T> _entityTypeModel = TypeModel.GetModelOf<T>();
		private readonly EntitySchemaDefinition<T> _entitySchemaDefinition;
		private readonly IReadOnlyCollection<IEntitySchemaAssemblage> _entitySchemaAssemblages;
		private EntitySchemaAssemblage<T> _entitySchemaAssemblage;
		private (ISchemaField<T> Field, ISchemaFieldAssemblage<T> Assemblage, FieldOperations<T> Operations)[] _builtFields;
		private int _joinCount;
		private readonly List<(ISchemaField<T>, FieldOperations<T>)> _fieldOperationsPairs
			= new List<(ISchemaField<T>, FieldOperations<T>)>();

		public EntitySchemaBuilder(
			EntitySchemaDefinition<T> entitySchemaDefinition,
			IReadOnlyCollection<IEntitySchemaAssemblage> entitySchemaAssemblages
			)
		{
			_entitySchemaDefinition = entitySchemaDefinition;
			_entitySchemaAssemblages = entitySchemaAssemblages;
		}

		public IEntitySchemaAssemblage CreateAssemblage()
		{
			_entitySchemaAssemblage = new EntitySchemaAssemblage<T>(
				!string.IsNullOrWhiteSpace(_entitySchemaDefinition.TableName) ?
					_entitySchemaDefinition.TableName :
					typeof(T).Name,
				_entitySchemaDefinition, this
				);
			EntityTypeVisitor.Visit(_entityTypeModel, _entitySchemaDefinition, VisitCallback);
			return _entitySchemaAssemblage;

			void VisitCallback(IPropertyField propertyField, Span<string> path)
			{
				if (path.Length != 1 || !SqlTypeHelper.IsSqlPrimitiveType(propertyField.FieldType))
					return;

				FindOrCreateField(propertyField, path, null);
			}
		}

		public EntitySchema BuildSchema()
		{
			CreateJoins();
			_builtFields = BuildSchemaFields();
			var fields = _builtFields.Select(q => q.Field).ToArray();
			var table = new Table(_entitySchemaAssemblage.TableName,
				fields.Select(q => q.Column).ToArray());
			var joins = new EntityFieldJoin[0];
			var indexes = GetSchemaIndexes(table, fields);
			var entitySchema = new EntitySchema<T>(
				table, fields,
				joins, indexes
				);
			return entitySchema;
		}

		public Dictionary<ISchemaField, FieldOperations> BuildFieldOperations()
		{
			if (_builtFields == null)
				throw new InvalidOperationException("Schema is not yet built, call BuildSchema() before calling BuildFieldOperations().");
			return _builtFields.Select(q => new
			{
				Field = q.Field,
				Operations = q.Operations
			}).ToDictionary(q => (ISchemaField)q.Field, q => (FieldOperations)q.Operations);
		}

		private void CreateJoins()
		{
			var joinStack = new Stack<EntityJoinBuilder>();
			EntityTypeVisitor.Visit(_entityTypeModel, _entitySchemaDefinition, Callback);

			void Callback(IPropertyField propertyField, Span<string> path)<commit_msg>Populate Table only with columns stored in the table.<commit_after>﻿using Silk.Data.Modelling;
using Silk.Data.Modelling.Mapping;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace Silk.Data.SQL.ORM.Schema
{
	/// <summary>
	/// Builds the schema components for a specific entity type.
	/// </summary>
	public interface IEntitySchemaBuilder
	{
		/// <summary>
		/// Creates the IEntitySchemaAssemblage that will be used to construct the EntitySchema populated with any declared fields that are SQL primitives and don't require any joins.
		/// </summary>
		/// <returns></returns>
		IEntitySchemaAssemblage CreateAssemblage();

		/// <summary>
		/// Builds the completed entity schema.
		/// </summary>
		/// <returns></returns>
		EntitySchema BuildSchema();

		Dictionary<ISchemaField, FieldOperations> BuildFieldOperations();
	}

	/// <summary>
	/// Builds the schema components for entities of type T.
	/// </summary>
	public class EntitySchemaBuilder<T> : IEntitySchemaBuilder
		where T : class
	{
		private readonly TypeModel<T> _entityTypeModel = TypeModel.GetModelOf<T>();
		private readonly EntitySchemaDefinition<T> _entitySchemaDefinition;
		private readonly IReadOnlyCollection<IEntitySchemaAssemblage> _entitySchemaAssemblages;
		private EntitySchemaAssemblage<T> _entitySchemaAssemblage;
		private (ISchemaField<T> Field, ISchemaFieldAssemblage<T> Assemblage, FieldOperations<T> Operations)[] _builtFields;
		private int _joinCount;
		private readonly List<(ISchemaField<T>, FieldOperations<T>)> _fieldOperationsPairs
			= new List<(ISchemaField<T>, FieldOperations<T>)>();

		public EntitySchemaBuilder(
			EntitySchemaDefinition<T> entitySchemaDefinition,
			IReadOnlyCollection<IEntitySchemaAssemblage> entitySchemaAssemblages
			)
		{
			_entitySchemaDefinition = entitySchemaDefinition;
			_entitySchemaAssemblages = entitySchemaAssemblages;
		}

		public IEntitySchemaAssemblage CreateAssemblage()
		{
			_entitySchemaAssemblage = new EntitySchemaAssemblage<T>(
				!string.IsNullOrWhiteSpace(_entitySchemaDefinition.TableName) ?
					_entitySchemaDefinition.TableName :
					typeof(T).Name,
				_entitySchemaDefinition, this
				);
			EntityTypeVisitor.Visit(_entityTypeModel, _entitySchemaDefinition, VisitCallback);
			return _entitySchemaAssemblage;

			void VisitCallback(IPropertyField propertyField, Span<string> path)
			{
				if (path.Length != 1 || !SqlTypeHelper.IsSqlPrimitiveType(propertyField.FieldType))
					return;

				FindOrCreateField(propertyField, path, null);
			}
		}

		public EntitySchema BuildSchema()
		{
			CreateJoins();
			_builtFields = BuildSchemaFields();
			var fields = _builtFields.Select(q => q.Field).ToArray();
			var table = new Table(_entitySchemaAssemblage.TableName,
				fields.Where(q => q.FieldType != FieldType.JoinedField).Select(q => q.Column).ToArray());
			var joins = new EntityFieldJoin[0];
			var indexes = GetSchemaIndexes(table, fields);
			var entitySchema = new EntitySchema<T>(
				table, fields,
				joins, indexes
				);
			return entitySchema;
		}

		public Dictionary<ISchemaField, FieldOperations> BuildFieldOperations()
		{
			if (_builtFields == null)
				throw new InvalidOperationException("Schema is not yet built, call BuildSchema() before calling BuildFieldOperations().");
			return _builtFields.Select(q => new
			{
				Field = q.Field,
				Operations = q.Operations
			}).ToDictionary(q => (ISchemaField)q.Field, q => (FieldOperations)q.Operations);
		}

		private void CreateJoins()
		{
			var joinStack = new Stack<EntityJoinBuilder>();
			EntityTypeVisitor.Visit(_entityTypeModel, _entitySchemaDefinition, Callback);

			void Callback(IPropertyField propertyField, Span<string> path)
{'fraction_non_alphanumeric': 0.10093610093610093, 'fraction_numerical': 0.000542667209333876, 'mean_word_length': 4.846153846153846, 'pattern_counts': {'":': 0, '<': 75, '<?xml version=': 0, '>': 86, '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': '6711835', 'n_tokens_mistral': 2374, 'n_tokens_neox': 2114, 'n_words': 493}