<|start_filename|>TypeExtensions.cs<|end_filename|>
﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

namespace LukeMapper
{
    public static class TypeExtensions
    {
        private static readonly Func<MethodInfo, IEnumerable<Type>> ParameterTypeProjection =
            method => method.GetParameters()
                            .Select(p => p.ParameterType.GetGenericTypeDefinition());

        public static MethodInfo GetGenericMethod(this Type type, string name, params Type[] parameterTypes)
        {
            return (from method in type.GetMethods()
                    where method.Name == name
                    where parameterTypes.SequenceEqual(ParameterTypeProjection(method))
                    select method).SingleOrDefault();
        }
    }
}


<|start_filename|>FeatureSupport.cs<|end_filename|>
using System.Collections.Generic;
using System.Data;
using System.Linq;

namespace LukeMapper
{
    /// <summary>
    /// Handles variances in features per DBMS
    /// </summary>
    public class FeatureSupport
    {
        /// <summary>
        /// Dictionary of supported features index by connection type name
        /// </summary>
        private static readonly Dictionary<string, FeatureSupport> FeatureList = new Dictionary<string, FeatureSupport>() {
                                                                                                                              {"sqlserverconnection", new FeatureSupport { Arrays = false}},
                                                                                                                              {"npgsqlconnection", new FeatureSupport {Arrays = true}}
                                                                                                                          };

        /// <summary>
        /// Gets the featureset based on the passed connection
        /// </summary>
        public static FeatureSupport Get(IDbConnection connection)
        {
            string name = connection.GetType().Name.ToLower();
            FeatureSupport features;
            return FeatureList.TryGetValue(name, out features) ? features : FeatureList.Values.First();
        }

        /// <summary>
        /// True if the db supports array columns e.g. Postgresql
        /// </summary>
        public bool Arrays { get; set; }
    }
}

<|start_filename|>DbString.cs<|end_filename|>
using System;
using System.Data;

namespace LukeMapper
{
    /// <summary>
    /// This class represents a SQL string, it can be used if you need to denote your parameter is a Char vs VarChar vs nVarChar vs nChar
    /// </summary>
    public sealed class DbString
    {
        /// <summary>
        /// Create a new DbString
        /// </summary>
        public DbString() { Length = -1; }
        /// <summary>
        /// Ansi vs Unicode 
        /// </summary>
        public bool IsAnsi { get; set; }
        /// <summary>
        /// Fixed length 
        /// </summary>
        public bool IsFixedLength { get; set; }
        /// <summary>
        /// Length of the string -1 for max
        /// </summary>
        public int Length { get; set; }
        /// <summary>
        /// The value of the string
        /// </summary>
        public string Value { get; set; }
        /// <summary>
        /// Add the parameter to the command... internal use only
        /// </summary>
        /// <param name="command"></param>
        /// <param name="name"></param>
        public void AddParameter(IDbCommand command, string name)
        {
            if (IsFixedLength && Length == -1)
            {
                throw new InvalidOperationException("If specifying IsFixedLength,  a Length must also be specified");
            }
            var param = command.CreateParameter();
            param.ParameterName = name;
            param.Value = (object)Value ?? DBNull.Value;
            if (Length == -1 && Value != null && Value.Length <= 4000)
            {
                param.Size = 4000;
            }
            else
            {
                param.Size = Length;
            }
            param.DbType = IsAnsi ? (IsFixedLength ? DbType.AnsiStringFixedLength : DbType.AnsiString) : (IsFixedLength ? DbType.StringFixedLength : DbType.String);
            command.Parameters.Add(param);
        }
    }
}

<|start_filename|>LukeMapper.Tests/ObjectSerialization.cs<|end_filename|>
﻿using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace LukeMapperTests
{
    [TestClass]
    public class ObjectSerialization
    {
        [TestMethod]
        public void DateTimeSerialization()
        {
            var date = DateTime.UtcNow;

            var longstring = LukeMapper.LukeMapper.ToDateString(date);

            long uttime;
            Assert.IsTrue(long.TryParse(longstring, out uttime));

            var ret = LukeMapper.LukeMapper.GetDateTime(longstring);

            AssertDatesEqual(date, ret);
        }

        private void AssertDatesEqual(DateTime a, DateTime b)
        {
            Assert.AreEqual(a.Year, b.Year);
            Assert.AreEqual(a.Month, b.Month);
            Assert.AreEqual(a.Day, b.Day);
            Assert.AreEqual(a.Hour, b.Hour);
            Assert.AreEqual(a.Minute, b.Minute);
            Assert.AreEqual(a.Second, b.Second);
        }

        [TestMethod]
        public void TrueSerialization()
        {
            var value = true;
            var serialized = value.ToString();
            var deserialized = LukeMapper.LukeMapper.GetBoolean(serialized);
            Assert.AreEqual(value,deserialized);
        }

        [TestMethod]
        public void FalseSerialization()
        {
            var value = true;
            var serialized = value.ToString();
            var deserialized = LukeMapper.LukeMapper.GetBoolean(serialized);
            Assert.AreEqual(value, deserialized);
        }
    }
}


<|start_filename|>Attributes.cs<|end_filename|>
﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Lucene.Net.Documents;
using Lucene.Net.Index;
using Lucene.Net.Search;

namespace LukeMapper
{

    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
    class LukeMapperAttribute : Attribute
    {
        /// <summary>
        /// If True, all members of the decorated class will be added into the lucene document
        /// with the options [Field.Index.NOT_ANALYZED_NO_NORMS, Field.Store.YES] provided no
        /// LukeAttribute is applied to that member
        /// </summary>
        public bool IgnoreByDefault = false;
        public Store DefaultStore = LukeMapper.DefaultStore;
        public Index DefaultIndex = LukeMapper.DefaultIndex;
    }

    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
    public class LukeAttribute : Attribute
    {
        /// <summary>
        /// How will this member be stored in the Lucene Index
        /// </summary>
        public Store Store = LukeMapper.DefaultStore;

        /// <summary>
        /// How will this member be indexed in the Lucene Index
        /// </summary>
        public Index Index = LukeMapper.DefaultIndex;

        /// <summary>
        /// If true, this member will not be added to the lucene document
        /// </summary>
        public bool Ignore = false;

        /// <summary>
        /// Custom Field Name to store/index this member as in the Lucene Index
        /// </summary>
        public string FieldName = null;
    }

    [AttributeUsage(AttributeTargets.Method)]
    public class LukeSerializerAttribute : Attribute
    {
        public string FieldName { get; set; }
        public LukeSerializerAttribute(string fieldName = null)
        {
            FieldName = fieldName;
        }
    }

    /// <summary>
    /// Is used to apply to any IEnumerable&lt;T&gt;
    /// LukeMapper will serialize the enumerable as a delimited string, with the 
    /// separated character being the Delimiter property.
    /// 
    /// Note: this is implemented using string.Join() and it is left to the user to ensure that the 
    /// delimited value is not included in the values of the list.
    /// </summary>
    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
    public class LukeDelimitedAttribute : Attribute
    {
        public string Delimeter { get; set; }
        public LukeDelimitedAttribute(string delimiter = ",")
        {
            Delimeter = delimiter;
        }
    }

    /// <summary>
    /// Expected a method with parameters of type Document, and expected to properly
    /// deserialize + set the corresponding member from the document to the current instance.
    /// </summary>
    [AttributeUsage(AttributeTargets.Method)]
    public class LukeDeserializerAttribute : Attribute
    {
        public string FieldName { get; set; }
        public LukeDeserializerAttribute(string fieldName = null)
        {
            FieldName = fieldName;
        }
    }

    //TODO: numeric fields...
    //TODO: term vectors...


    [LukeMapper]
    public class ExampleClass
    {
        public int Id { get; set; }

        public string Title { get; set; }

        [Luke(Store = Store.YES, Index = Index.ANALYZED, FieldName = "_Body")]
        public string Body { get; set; }

        //[LukeSerializer]
        //private static Document SerializeToDocument(ExampleClass obj)
        //{
        //    var doc = new Document();


        //    return doc;
        //}

        //[LukeDeserializer]
        //private static ExampleClass DeserializeDocument(Document doc)
        //{
        //}

    }



    //[LukeMapper(IgnoreByDefault = true)]
    //public class ExampleClass
    //{
    //    // doesn't get indexed/stored
    //    [Luke(Store = Store.YES)]
    //    public int Id { get; set; }
        
    //    // doesn't get stored, but is indexed in "searchtext" field
    //    [Luke(Store = Store.NO, Index = Index.ANALYZED, FieldName = "searchtext")]
    //    public string Title { get; set; }

    //    // doesn't get stored, but is indexed in "searchtext" field
    //    [Luke(Store = Store.NO, Index = Index.ANALYZED, FieldName = "searchtext")]
    //    public string Body { get; set; }

    //    // doesn't get indexed/stored
    //    public int IgnoredProperty { get; set; }
    //}

    //[LukeMapper(DefaultIndex = Index.ANALYZED)]
    //public class ExampleClass
    //{
    //    // doesn't get indexed/stored
    //    [Luke(Index = Index.NOT_ANALYZED_NO_NORMS)]
    //    public int Id { get; set; }

    //    // get's analyzed, AND stored
    //    public string Title { get; set; }

    //    // get's analyzed, AND stored
    //    public string Body { get; set; }
    //}

    //public class ExampleClass
    //{
    //    // everything get's indexed and stored by default
    //    public int Id { get; set; }
    //    public string Title { get; set; }
    //    public string Body { get; set; }

    //    //opt-in ignored per property/field
    //    [Luke(Ignore=true)]
    //    public int Ignored { get; set; }
    //}

    //public class ExampleClass
    //{
    //    // everything get's indexed and stored by default
    //    public int Id { get; set; }
    //    public string Title { get; set; }
    //    public string Body { get; set; }

    //    //opt-in ignored per property/field
    //    public int Ignored { get; set; }
    //}

    //public class TestCustomSerializerClass
    //{
    //    public int Id { get; set; }

    //    //this list would typically be ignored
    //    public List<string> CustomList { get; set; }

    //    // if you specify a serializer, it will get serialized
    //    [LukeSerializer("CustomList")]
    //    public static string CustomListToString(List<string> list)
    //    {
    //        return string.Join(",", list);
    //    }

    //    // and similarly, deserialized
    //    [LukeDeserializer("CustomList")]
    //    public static List<string> StringToCustomList(string serialized)
    //    {
    //        return serialized.Split(',').ToList();
    //    }
    //}


    //public class TestCustomSerializerClass
    //{
    //    public int Id { get; set; }

    //    // maybe you just want to index the list for search, but don't need it on .Query()
    //    [Luke(Store = Store.NO,Index = Index.ANALYZED)]
    //    public List<string> CustomList { get; set; }

    //    // in this case, only a serializer is needed
    //    [LukeSerializer("CustomList")]
    //    public static string CustomListToString(List<string> list)
    //    {
    //        return string.Join(" ", list);
    //    }
    //}


}


<|start_filename|>ExampleMethods.cs<|end_filename|>
﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Lucene.Net.Documents;

namespace LukeMapper
{
    public class ExampleMethods
    {
        public static Document MapperFunction(Poco obj)
        {
            var doc = new Document();

            //doc.Add(new Field("PropInt", obj.PropInt.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));
            //doc.Add(new Field("PropNullInt", obj.PropNullInt.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));
            //doc.Add(new Field("PropString", obj.PropString, Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));
            //doc.Add(new Field("PropDt", LukeMapper.ToDateString(obj.PropDt), Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));

            //doc.Add(new Field("Int", obj.Int.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));
            //doc.Add(new Field("NullInt", obj.NullInt.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));
            //doc.Add(new Field("String", obj.String, Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));
            //doc.Add(new Field("Dt", LukeMapper.ToDateString(obj.Dt), Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));

            //doc.Add(new Field("NullDt", obj.NullDt.HasValue ? LukeMapper.ToDateString(obj.NullDt.Value) : "", Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));
            //doc.Add(new Field("PropNullDt", obj.PropNullDt.HasValue ? LukeMapper.ToDateString(obj.PropNullDt.Value) : "", Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));

            //doc.Add(new Field("Char", obj.Char.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));
            //doc.Add(new Field("PropChar", obj.PropChar.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));
            
            //doc.Add(new Field("NullChar", obj.NullChar.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));
            //doc.Add(new Field("PropNullChar", obj.PropNullChar.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));

            doc.Add(new Field("Bl", obj.Bl.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));
            doc.Add(new Field("PropBl", obj.PropBl.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));

            doc.Add(new Field("NullBl", obj.NullBl.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));
            doc.Add(new Field("PropNullBl", obj.PropNullBl.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));

            return doc;
        }

        public static Document CustomMapperFunction(TestCustomSerializerClass obj)
        {
            var doc = new Document();

            doc.Add(new Field("CustomList", TestCustomSerializerClass.CustomListToString(obj.PropStringList), Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));

            return doc;
        }

        public static TestCustomSerializerClass CustomDeserializeFunction(Document doc)
        {
            var obj = new TestCustomSerializerClass();

            obj.PropStringList = TestCustomSerializerClass.StringToCustomList(doc.Get("CustomList"));

            return obj;
        }

        public static TestCustomSerializerClass CustomMapperFunction2(Document doc)
        {
            var obj = new TestCustomSerializerClass();

            obj.PropStringList = doc.Get("PropStringList").Split(new[] { "," }, StringSplitOptions.None).ToList();

            obj.StringList = doc.Get("StringList").Split(new[] { "," }, StringSplitOptions.None).ToList();

            obj.IntList = doc.Get("IntList").Split(new[] {","}, StringSplitOptions.None)
                .Select(int.Parse)
                .ToList();

            obj.PropIntList = doc.Get("PropIntList").Split(new[] { "," }, StringSplitOptions.None)
                .Select(int.Parse)
                .ToList();

            return obj;
        }

        public static Document CustomMapperFunction3(TestCustomSerializerClass obj)
        {
            var doc = new Document();

            doc.Add(new Field("PropStringList", string.Join(",", obj.PropStringList), Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));

            doc.Add(new Field("StringList", string.Join(",", obj.StringList), Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));

            doc.Add(new Field("IntList", string.Join(",", obj.IntList), Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));

            doc.Add(new Field("PropIntList", string.Join(",", obj.PropIntList), Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));

            return doc;
        }

    }

    public class TestCustomSerializerClass
    {
        public int Id { get; set; }

        public List<string> StringList; 
        public List<string> PropStringList { get; set; }

        public List<int> IntList;
        public List<int> PropIntList { get; set; }
            
        [LukeSerializer("CustomList")]
        public static string CustomListToString(List<string> list)
        {
            return "";
        }
        [LukeDeserializer("CustomList")]
        public static List<string> StringToCustomList(string serialized)
        {
            return new List<string>();
        }
    }

    public class Poco
    {
        public int Int;
        public int PropInt { get; set; }

        public int? NullInt;
        public int? PropNullInt { get; set; }

        public string String;
        public string PropString { get; set; }

        public DateTime Dt;
        public DateTime PropDt { get; set; }

        public DateTime? NullDt;
        public DateTime? PropNullDt { get; set; }

        public char Char;
        public char PropChar { get; set; }

        public char? NullChar;
        public char? PropNullChar { get; set; }

        public bool Bl;
        public bool PropBl { get; set; }

        public bool? NullBl;
        public bool? PropNullBl { get; set; }

    }
}
