├── .gitignore ├── .idea └── .idea.Simple1C │ ├── .idea │ ├── .name │ ├── modules.xml │ └── vcs.xml │ └── riderModule.iml ├── Assemblies └── Metadata1C.dll ├── Generator ├── CsProjectFileUpdater.cs ├── EntryPoint.cs ├── Generator.csproj └── Properties │ └── AssemblyInfo.cs ├── LICENSE.txt ├── Simple1C.sln ├── Simple1C.sln.DotSettings ├── Simple1C ├── DataContextFactory.cs ├── Impl │ ├── Call.cs │ ├── Com │ │ ├── ComHelpers.cs │ │ └── DispatchObject.cs │ ├── ComDataContext.cs │ ├── ComObjectMapper.cs │ ├── ComValueSource.cs │ ├── ConfigurationName.cs │ ├── EntityController.cs │ ├── EntityHelpers.cs │ ├── EnumMapItem.cs │ ├── Generation │ │ ├── ConfigurationItem.cs │ │ ├── ConfigurationItemDescriptor.cs │ │ ├── GenerationContext.cs │ │ ├── ObjectModelGenerator.cs │ │ └── Rendering │ │ │ ├── ClassFileModel.cs │ │ │ ├── ClassFileTemplate.cs │ │ │ ├── ClassFileTemplate.tt │ │ │ ├── ClassModel.cs │ │ │ ├── ConstantFileModel.cs │ │ │ ├── ConstantFileTemplate.cs │ │ │ ├── ConstantFileTemplate.tt │ │ │ ├── EnumFileModel.cs │ │ │ ├── EnumFileTemplate.cs │ │ │ ├── EnumFileTemplate.tt │ │ │ ├── EnumItemModel.cs │ │ │ ├── GenerateHelpers.cs │ │ │ └── PropertyModel.cs │ ├── GlobalContext.cs │ ├── Helpers │ │ ├── AttributesCache.cs │ │ ├── ByteArrayHelpers.cs │ │ ├── DictionaryExtensions.cs │ │ ├── EnumAttributesCache.cs │ │ ├── EnumerableExtensions.cs │ │ ├── Evaluator.cs │ │ ├── ListFactory.cs │ │ ├── LogHelpers.cs │ │ ├── MemberAccessor │ │ │ ├── BoxingCaster.cs │ │ │ ├── Caster.cs │ │ │ ├── FieldAccessorFactory.cs │ │ │ ├── IAccessMember.cs │ │ │ ├── IMemberAccessor.cs │ │ │ ├── MappingMemberAccessor.cs │ │ │ ├── MemberAccessor.cs │ │ │ ├── MemberAccessorFactory.cs │ │ │ ├── PropertyAccessorFactory.cs │ │ │ ├── TypeMismatchException.cs │ │ │ ├── UnboxingCaster.cs │ │ │ └── UntypedMemberAccessor.cs │ │ ├── NameValueCollectionHelpers.cs │ │ ├── PathHelpers.cs │ │ ├── ReflectionHelpers.cs │ │ ├── RelinqHelpers.cs │ │ └── StringHelpers.cs │ ├── IValueSource.cs │ ├── InMemoryDataContext.cs │ ├── MappingSource.cs │ ├── Metadata.cs │ ├── MetadataAccessor.cs │ ├── MetadataHelpers.cs │ ├── MetadataRequisite.cs │ ├── ObservedValue.cs │ ├── ParametersConverter.cs │ ├── ProjectionMapperFactory.cs │ ├── Queriables │ │ ├── BuiltQuery.cs │ │ ├── ConvertEnumCmd.cs │ │ ├── ConvertUniqueIdentifierCmd.cs │ │ ├── FilterPredicateAnalyzer.cs │ │ ├── IConvertParameterCmd.cs │ │ ├── IRelinqQueryable.cs │ │ ├── MemberAccessBuilder.cs │ │ ├── Ordering.cs │ │ ├── ParameterizingExpressionVisitor.cs │ │ ├── Projection.cs │ │ ├── PropertiesExtractingVisitor.cs │ │ ├── QueryBuilder.cs │ │ ├── QueryField.cs │ │ ├── QueryModelVisitor.cs │ │ ├── RelinqQueryExecutor.cs │ │ ├── RelinqQueryProvider.cs │ │ ├── RelinqQueryable.cs │ │ ├── SelectedProperty.cs │ │ └── SelectedPropertyItem.cs │ ├── Queries │ │ ├── QueryResult.cs │ │ ├── QueryResultSelection.cs │ │ ├── ValueTable.cs │ │ ├── ValueTableColumn.cs │ │ ├── ValueTableColumnCollection.cs │ │ └── ValueTableRow.cs │ ├── SimpleTypeInfo.cs │ ├── Sql │ │ ├── MsSqlBulkCopyWriter.cs │ │ ├── SchemaMapping │ │ │ ├── EnumMapping.cs │ │ │ ├── IMappingSource.cs │ │ │ ├── PostgreeSqlSchemaStore.cs │ │ │ ├── PropertyLauout.cs │ │ │ ├── PropertyMapping.cs │ │ │ ├── PropertyNames.cs │ │ │ ├── Simple1cSchemaCreator.cs │ │ │ ├── SingleLayout.cs │ │ │ ├── TableMapping.cs │ │ │ ├── TableType.cs │ │ │ └── UnionLayout.cs │ │ ├── SqlAccess │ │ │ ├── AbstractSqlDatabase.cs │ │ │ ├── DatabaseHelpers.cs │ │ │ ├── InMemoryDataReader.cs │ │ │ ├── MssqlDatabase.cs │ │ │ ├── Parsing │ │ │ │ ├── ColumnReferenceTableNameResolver.cs │ │ │ │ ├── ElementsHolder.cs │ │ │ │ ├── Identifier.cs │ │ │ │ ├── ParseHelpers.cs │ │ │ │ ├── QueryGrammar.cs │ │ │ │ └── QueryParser.cs │ │ │ ├── PostgreeSqlDatabase.cs │ │ │ └── Syntax │ │ │ │ ├── AggregateFunctionExpression.cs │ │ │ │ ├── AggregationFunction.cs │ │ │ │ ├── AndExpression.cs │ │ │ │ ├── BinaryExpression.cs │ │ │ │ ├── CaseElement.cs │ │ │ │ ├── CaseExpression.cs │ │ │ │ ├── CastExpression.cs │ │ │ │ ├── ColumnReferenceExpression.cs │ │ │ │ ├── DatePart.cs │ │ │ │ ├── EqualityExpression.cs │ │ │ │ ├── GroupByClause.cs │ │ │ │ ├── IColumnSource.cs │ │ │ │ ├── ISqlElement.cs │ │ │ │ ├── InExpression.cs │ │ │ │ ├── IsNullExpression.cs │ │ │ │ ├── IsReferenceExpression.cs │ │ │ │ ├── JoinClause.cs │ │ │ │ ├── JoinKind.cs │ │ │ │ ├── KnownQueryFunction.cs │ │ │ │ ├── ListExpression.cs │ │ │ │ ├── LiteralExpression.cs │ │ │ │ ├── OperatorPrecedenceAttribute.cs │ │ │ │ ├── OperatorSynonymsAttribute.cs │ │ │ │ ├── OrderByClause.cs │ │ │ │ ├── ParameterExpression.cs │ │ │ │ ├── QueryFunctionExpression.cs │ │ │ │ ├── SelectClause.cs │ │ │ │ ├── SelectFieldExpression.cs │ │ │ │ ├── SqlBinaryOperator.cs │ │ │ │ ├── SqlQuery.cs │ │ │ │ ├── SqlType.cs │ │ │ │ ├── SubqueryClause.cs │ │ │ │ ├── SubqueryTable.cs │ │ │ │ ├── TableDeclarationClause.cs │ │ │ │ ├── UnaryExpression.cs │ │ │ │ ├── UnaryOperator.cs │ │ │ │ ├── UnionClause.cs │ │ │ │ ├── UnionType.cs │ │ │ │ └── ValueLiteralExpression.cs │ │ └── Translation │ │ │ ├── QueryEntities │ │ │ ├── EnumSqlBuilder.cs │ │ │ ├── NameGenerator.cs │ │ │ ├── QueryEntity.cs │ │ │ ├── QueryEntityProperty.cs │ │ │ ├── QueryEntityRegistry.cs │ │ │ ├── QueryEntityTree.cs │ │ │ ├── QueryField.cs │ │ │ ├── QueryRoot.cs │ │ │ └── SelectPart.cs │ │ │ ├── QueryToSqlTranslator.cs │ │ │ ├── SqlFormatter.cs │ │ │ ├── SqlHelpers.cs │ │ │ ├── SqlVisitor.cs │ │ │ └── Visitors │ │ │ ├── AddAreaToJoinConditionVisitor.cs │ │ │ ├── ColumnReferenceRewriter.cs │ │ │ ├── DeduceEntityTypeFromIsReferenceExpressionVisitor.cs │ │ │ ├── GenericVisitor.cs │ │ │ ├── IsReferenceExpressionRewriter.cs │ │ │ ├── ObjectNameCheckingVisitor.cs │ │ │ ├── QueryFunctionRewriter.cs │ │ │ ├── SubqueryVisitor.cs │ │ │ ├── TableDeclarationRewriter.cs │ │ │ ├── TableDeclarationVisitor.cs │ │ │ └── ValueLiteralRewriter.cs │ ├── SyncList.cs │ ├── TypeInfo.cs │ └── TypeRegistry.cs ├── Interface │ ├── ConfigurationScope.cs │ ├── Connection1CType.cs │ ├── ConnectionStringBuilder.cs │ ├── DataContextExtensions.cs │ ├── GlobalContextFactory.cs │ ├── IDataContext.cs │ ├── ObjectModel │ │ ├── Abstract1CEntity.cs │ │ ├── ConfigurationScopeAttribute.cs │ │ ├── Constant.cs │ │ ├── MaxLengthAttribute.cs │ │ ├── ObjectPresentationAttribute.cs │ │ ├── Requisite.cs │ │ └── SynonymAttribute.cs │ ├── ObjectPresentation.cs │ ├── Sql │ │ ├── IWriter.cs │ │ ├── QuerySource.cs │ │ └── RowAccessor.cs │ ├── Synonym.cs │ └── Функции.cs ├── Properties │ └── AssemblyInfo.cs ├── Simple1C.csproj ├── Sql.cs └── packages.config ├── Tests ├── Class1.cs ├── CsProjectFileUpdaterTest.cs ├── Helpers │ ├── ProcessesHelpers.cs │ ├── Robocopy.cs │ ├── TestBase.cs │ └── Testing1CConnector.cs ├── InMemoryDataContextTest.cs ├── Integration │ ├── COMDataContextTest.cs │ ├── COMDataContextTestBase.cs │ ├── CharacteristicsTest.cs │ ├── ConstantsTest.cs │ ├── DataContextManagementTest.cs │ ├── InformationRegisterTest.cs │ ├── ProjectionTest.cs │ ├── SaveTest.cs │ ├── SaveValidationsIntegrationTest.cs │ ├── TableSectionsTest.cs │ └── UniqueIdentifierTest.cs ├── Properties │ └── AssemblyInfo.cs ├── QueryBuilderTest.cs ├── Sql │ ├── BasicTest.cs │ ├── EnumsTest.cs │ ├── FunctionReplacementTest.cs │ ├── LiteralsTest.cs │ ├── NestedPropertiesTest.cs │ ├── ParserTest.cs │ ├── SubqueryTest.cs │ └── TranslationTestBase.cs ├── SynonymTest.cs ├── TestEntities │ ├── AccountingDocument.cs │ ├── AdvanceWay.cs │ ├── Bank.cs │ ├── BankAccount.cs │ ├── Banks.cs │ ├── Counterpart.cs │ ├── CounterpartContractKind.cs │ ├── CounterpartyContract.cs │ ├── EnumConverter.cs │ ├── IncomingOperationKind.cs │ ├── LegalForm.cs │ ├── NdsRate.cs │ ├── NomenclatureItem.cs │ └── TestObjectsManager.cs ├── Tests.csproj ├── packages.config └── ФункцииTest.cs ├── build.cmd ├── generate.cmd ├── nuget ├── publish.cmd └── simple1C.nuspec ├── readme.md └── todo /.gitignore: -------------------------------------------------------------------------------- 1 | *.user 2 | *.suo 3 | *.mdb 4 | *.userprefs 5 | bin/ 6 | bin.tests/ 7 | obj/ 8 | packages/ 9 | *.nupkg 10 | *.designer.cs 11 | *.Designer.cs 12 | 13 | #rider user-local files (according to https://intellij-support.jetbrains.com/hc/en-us/articles/206544839-How-to-manage-projects-under-Version-Control-Systems) 14 | **/.idea/workspace.xml 15 | **/.idea/tasks.xml 16 | -------------------------------------------------------------------------------- /.idea/.idea.Simple1C/.idea/.name: -------------------------------------------------------------------------------- 1 | Simple1C -------------------------------------------------------------------------------- /.idea/.idea.Simple1C/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/.idea.Simple1C/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/.idea.Simple1C/riderModule.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Assemblies/Metadata1C.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivan816/simple-1c/f2e5ce78b98f70f30039fd3de79308a59d432fc2/Assemblies/Metadata1C.dll -------------------------------------------------------------------------------- /Generator/Generator.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {20486119-897F-44BA-893D-A0E4A0649FD9} 8 | Exe 9 | Properties 10 | Generator 11 | Generator 12 | v4.5 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | ..\bin\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | 26 | 27 | pdbonly 28 | true 29 | ..\bin\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | {bb1a4406-ad17-4089-9d6b-33d4452fde4c} 50 | Simple1C 51 | 52 | 53 | 54 | 61 | -------------------------------------------------------------------------------- /Generator/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Generator")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Generator")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("c354c5da-c534-44f9-89a6-d2fd9f8b3abf")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Gusev Petr, Ivan Medvedev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Simple1C.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.21005.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Simple1C", "Simple1C\Simple1C.csproj", "{BB1A4406-AD17-4089-9D6B-33D4452FDE4C}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{49A6C3B8-E307-4C44-B4B9-F33FD4FB9216}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Generator", "Generator\Generator.csproj", "{20486119-897F-44BA-893D-A0E4A0649FD9}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {BB1A4406-AD17-4089-9D6B-33D4452FDE4C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {BB1A4406-AD17-4089-9D6B-33D4452FDE4C}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {BB1A4406-AD17-4089-9D6B-33D4452FDE4C}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {BB1A4406-AD17-4089-9D6B-33D4452FDE4C}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {49A6C3B8-E307-4C44-B4B9-F33FD4FB9216}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {49A6C3B8-E307-4C44-B4B9-F33FD4FB9216}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {49A6C3B8-E307-4C44-B4B9-F33FD4FB9216}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {49A6C3B8-E307-4C44-B4B9-F33FD4FB9216}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {20486119-897F-44BA-893D-A0E4A0649FD9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {20486119-897F-44BA-893D-A0E4A0649FD9}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {20486119-897F-44BA-893D-A0E4A0649FD9}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {20486119-897F-44BA-893D-A0E4A0649FD9}.Release|Any CPU.Build.0 = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | EndGlobal 35 | -------------------------------------------------------------------------------- /Simple1C.sln.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | True 3 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> 4 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> 5 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> -------------------------------------------------------------------------------- /Simple1C/DataContextFactory.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using Simple1C.Impl; 3 | using Simple1C.Interface; 4 | 5 | namespace Simple1C 6 | { 7 | public static class DataContextFactory 8 | { 9 | public static IDataContext CreateCOM(object globalContext, Assembly mappingsAssembly) 10 | { 11 | return new ComDataContext(globalContext, mappingsAssembly); 12 | } 13 | 14 | public static IDataContext CreateInMemory(Assembly mappingsAssembly) 15 | { 16 | return new InMemoryDataContext(mappingsAssembly); 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Call.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Simple1C.Impl.Com; 3 | 4 | namespace Simple1C.Impl 5 | { 6 | internal static class Call 7 | { 8 | public static string ПолноеИмя(object comObject) 9 | { 10 | return Convert.ToString(ComHelpers.Invoke(comObject, "ПолноеИмя")); 11 | } 12 | 13 | public static string Имя(object comObject) 14 | { 15 | return StringProp(comObject, "Имя"); 16 | } 17 | 18 | public static string Синоним(object comObject) 19 | { 20 | return StringProp(comObject, "Синоним"); 21 | } 22 | 23 | public static object Получить(object comObject, int index) 24 | { 25 | return ComHelpers.Invoke(comObject, "Получить", index); 26 | } 27 | 28 | public static int Количество(object comObject) 29 | { 30 | return Convert.ToInt32(ComHelpers.Invoke(comObject, "Количество")); 31 | } 32 | 33 | public static int IntProp(object comObject, string name) 34 | { 35 | return Convert.ToInt32(ComHelpers.GetProperty(comObject, name)); 36 | } 37 | 38 | public static string StringProp(object comObject, string name) 39 | { 40 | return Convert.ToString(ComHelpers.GetProperty(comObject, name)); 41 | } 42 | 43 | public static bool IsEmpty(object comObject) 44 | { 45 | return (bool) ComHelpers.Invoke(comObject, "IsEmpty"); 46 | } 47 | 48 | public static object НайтиПоТипу(object metadata, object typeObject) 49 | { 50 | return ComHelpers.Invoke(metadata, "НайтиПоТипу", typeObject); 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Com/DispatchObject.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace Simple1C.Impl.Com 5 | { 6 | internal class DispatchObject 7 | { 8 | private readonly object comObject; 9 | 10 | protected DispatchObject(object comObject) 11 | { 12 | this.comObject = comObject; 13 | } 14 | 15 | protected string GetString(string property) 16 | { 17 | var value = Get(property); 18 | return Convert.IsDBNull(value) ? null : Convert.ToString(value); 19 | } 20 | 21 | protected object Get(string property) 22 | { 23 | return ComHelpers.GetProperty(comObject, property); 24 | } 25 | 26 | protected void Set(string property, object value) 27 | { 28 | ComHelpers.SetProperty(comObject, property, value); 29 | } 30 | 31 | protected object Invoke(string name, params object[] args) 32 | { 33 | return ComHelpers.Invoke(comObject, name, args); 34 | } 35 | 36 | protected object ComObject() 37 | { 38 | return comObject; 39 | } 40 | 41 | protected void Dispose() 42 | { 43 | Marshal.FinalReleaseComObject(comObject); 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /Simple1C/Impl/ComValueSource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Simple1C.Impl.Com; 3 | 4 | namespace Simple1C.Impl 5 | { 6 | internal class ComValueSource : IValueSource 7 | { 8 | private readonly ComObjectMapper comObjectMapper; 9 | private readonly object comObject; 10 | 11 | internal ComValueSource(object comObject, ComObjectMapper comObjectMapper, bool writable) 12 | { 13 | this.comObjectMapper = comObjectMapper; 14 | this.comObject = comObject; 15 | Writable = writable; 16 | } 17 | 18 | public object GetBackingStorage() 19 | { 20 | return comObject; 21 | } 22 | 23 | public bool Writable { get; private set; } 24 | 25 | bool IValueSource.TryLoadValue(string name, Type type, out object result) 26 | { 27 | var isUniqueIdentifier = name == EntityHelpers.idPropertyName && type == typeof(Guid?); 28 | var propertyValue = isUniqueIdentifier 29 | ? ComHelpers.Invoke(comObject, name) 30 | : ComHelpers.GetProperty(comObject, name); 31 | result = comObjectMapper.MapFrom1C(propertyValue, type); 32 | return true; 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /Simple1C/Impl/EntityHelpers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Simple1C.Interface.ObjectModel; 3 | 4 | namespace Simple1C.Impl 5 | { 6 | internal static class EntityHelpers 7 | { 8 | public const string idPropertyName = "УникальныйИдентификатор"; 9 | 10 | public static bool IsTableSection(Type type) 11 | { 12 | return type.Name.StartsWith("ТабличнаяЧасть"); 13 | } 14 | 15 | public static bool IsConstant(Type type) 16 | { 17 | return type.BaseType != null && 18 | type.BaseType.IsGenericType && 19 | type.BaseType.GetGenericTypeDefinition() == typeof(Constant<>); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /Simple1C/Impl/EnumMapItem.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Impl 2 | { 3 | internal class EnumMapItem 4 | { 5 | public object value; 6 | public int index; 7 | } 8 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Generation/ConfigurationItem.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Impl.Generation 2 | { 3 | internal class ConfigurationItem 4 | { 5 | public ConfigurationItem(ConfigurationName name, object comObject) 6 | { 7 | Name = name; 8 | ComObject = comObject; 9 | } 10 | 11 | public ConfigurationName Name { get; private set; } 12 | public object ComObject { get; private set; } 13 | } 14 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Generation/ConfigurationItemDescriptor.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Impl.Generation 2 | { 3 | internal class ConfigurationItemDescriptor 4 | { 5 | public string[] AttributePropertyNames { get; set; } 6 | public bool HasTableSections { get; set; } 7 | public bool HasStandardTableSections { get; set; } 8 | } 9 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Generation/GenerationContext.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.IO; 3 | using Simple1C.Impl.Helpers; 4 | 5 | namespace Simple1C.Impl.Generation 6 | { 7 | internal class GenerationContext 8 | { 9 | private readonly string rootDirectoryFullPath; 10 | private readonly HashSet seen = new HashSet(); 11 | private readonly List writtenFiles = new List(); 12 | 13 | public GenerationContext(string rootDirectoryFullPath) 14 | { 15 | this.rootDirectoryFullPath = rootDirectoryFullPath; 16 | ItemsToProcess = new Queue(); 17 | } 18 | 19 | public Queue ItemsToProcess { get; private set; } 20 | 21 | public void Write(ConfigurationName name, string content) 22 | { 23 | var fileFullPath = Path.Combine(rootDirectoryFullPath, name.Scope.ToString(), name.Name) + ".cs"; 24 | var directoryFullPath = PathHelpers.GetDirectoryName(fileFullPath); 25 | if (!Directory.Exists(directoryFullPath)) 26 | Directory.CreateDirectory(directoryFullPath); 27 | File.WriteAllText(fileFullPath, content); 28 | writtenFiles.Add(fileFullPath); 29 | } 30 | 31 | public IEnumerable GetWrittenFiles() 32 | { 33 | return writtenFiles; 34 | } 35 | 36 | public void EnqueueIfNeeded(ConfigurationItem item) 37 | { 38 | if (seen.Add(item.Name)) 39 | ItemsToProcess.Enqueue(item); 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Generation/Rendering/ClassFileModel.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Impl.Generation.Rendering 2 | { 3 | internal class ClassFileModel 4 | { 5 | public string Namespace { get; set; } 6 | public ClassModel MainClass { get; set; } 7 | } 8 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Generation/Rendering/ClassFileTemplate.tt: -------------------------------------------------------------------------------- 1 | <#@ template language="C#" visibility="internal" #> 2 | <#@ assembly name="System.Core" #> 3 | <#@ import namespace="System.Linq" #> 4 | <#@ import namespace="System.Text" #> 5 | <#@ import namespace="System.Collections.Generic" #> 6 | using System; 7 | using System.Collections.Generic; 8 | using Simple1C.Interface; 9 | using Simple1C.Interface.ObjectModel; 10 | 11 | namespace <#=Model.Namespace#> 12 | { 13 | <# 14 | PushIndent("\t"); 15 | RenderClass(Model.MainClass); 16 | PopIndent(); 17 | #> 18 | } 19 | <#+ 20 | public ClassFileModel Model { get; set; } 21 | 22 | private void RenderClass(ClassModel model) 23 | { 24 | #> 25 | <#+if(model.ConfigurationScope.HasValue) 26 | {#> 27 | [ConfigurationScope(ConfigurationScope.<#=model.ConfigurationScope.Value.ToString()#>)] 28 | <#+}#> 29 | <#+if(model.Synonym != null) 30 | {#> 31 | [Synonym("<#=model.Synonym#>")] 32 | <#+}#> 33 | <#+if(model.ObjectPresentation != null) 34 | {#> 35 | [ObjectPresentation("<#=model.ObjectPresentation#>")] 36 | <#+}#> 37 | public partial class <#=model.Name#> : Abstract1CEntity 38 | { 39 | <#+for(var i = 0; i < model.Properties.Count; i++) 40 | { 41 | var prop = model.Properties[i]; 42 | if(i != 0) 43 | Write("\r\n"); 44 | #> private Requisite<<#=prop.Type#>> <#=prop.FieldName#>; 45 | <#+if(prop.MaxLength.HasValue) {#> [MaxLength(<#=prop.MaxLength.Value#>)] 46 | <#+}#> public <#=prop.Type#> <#=prop.PropertyName#> 47 | { 48 | get { return Controller.GetValue(ref <#=prop.FieldName#>, "<#=prop.PropertyName#>"); } 49 | set { Controller.SetValue(ref <#=prop.FieldName#>, "<#=prop.PropertyName#>", value); } 50 | } 51 | <#+}#><#+if(model.NestedClasses != null) 52 | foreach(var nestedClass in model.NestedClasses) 53 | { 54 | Write("\r\n"); 55 | PushIndent("\t"); 56 | RenderClass(nestedClass); 57 | PopIndent(); 58 | }#> 59 | } 60 | <#+}#> -------------------------------------------------------------------------------- /Simple1C/Impl/Generation/Rendering/ClassModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Simple1C.Interface; 3 | 4 | namespace Simple1C.Impl.Generation.Rendering 5 | { 6 | internal class ClassModel 7 | { 8 | public ClassModel() 9 | { 10 | Properties = new List(); 11 | NestedClasses = new List(); 12 | } 13 | 14 | public string Name { get; set; } 15 | public ConfigurationScope? ConfigurationScope { get; set; } 16 | public string Synonym { get; set; } 17 | public string ObjectPresentation { get; set; } 18 | public List Properties { get; private set; } 19 | public List NestedClasses { get; private set; } 20 | } 21 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Generation/Rendering/ConstantFileModel.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Impl.Generation.Rendering 2 | { 3 | internal class ConstantFileModel 4 | { 5 | public string Namespace { get; set; } 6 | public string Name { get; set; } 7 | public string Synonym { get; set; } 8 | public string Type { get; set; } 9 | public int? MaxLength { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Generation/Rendering/ConstantFileTemplate.tt: -------------------------------------------------------------------------------- 1 | <#@ template language="C#" visibility="internal" #> 2 | <#@ assembly name="System.Core" #> 3 | using System; 4 | using Simple1C.Interface.ObjectModel; 5 | 6 | namespace <#=Model.Namespace#> 7 | { 8 | [Synonym("<#=Model.Synonym#>")] 9 | <#if(Model.MaxLength.HasValue) {#> [MaxLength(<#=Model.MaxLength.Value#>)] 10 | <#}#> public class <#=Model.Name#> : Constant<<#=Model.Type#>> 11 | { 12 | } 13 | }<#+ 14 | public ConstantFileModel Model { get; set; } 15 | #> -------------------------------------------------------------------------------- /Simple1C/Impl/Generation/Rendering/EnumFileModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Simple1C.Impl.Generation.Rendering 4 | { 5 | internal class EnumFileModel 6 | { 7 | public EnumFileModel() 8 | { 9 | Items = new List(); 10 | } 11 | 12 | public string Namespace { get; set; } 13 | public string Name { get; set; } 14 | public List Items { get; private set; } 15 | } 16 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Generation/Rendering/EnumFileTemplate.tt: -------------------------------------------------------------------------------- 1 | <#@ template language="C#" visibility="internal" #> 2 | <#@ assembly name="System.Core" #> 3 | <#@ import namespace="System.Linq" #> 4 | <#@ import namespace="System.Text" #> 5 | <#@ import namespace="System.Collections.Generic" #> 6 | using System; 7 | using Simple1C.Interface.ObjectModel; 8 | 9 | namespace <#=Model.Namespace#> 10 | { 11 | public enum <#=Model.Name#> 12 | {<#for(var i = 0; i < Model.Items.Count; i++) 13 | { 14 | var item = Model.Items[i];#> 15 | 16 | [Synonym("<#=item.Synonym#>")] <#=item.Name#><#if(i != Model.Items.Count - 1){#>,<#}#><#}#> 17 | 18 | } 19 | }<#+ 20 | public EnumFileModel Model { get; set; } 21 | #> -------------------------------------------------------------------------------- /Simple1C/Impl/Generation/Rendering/EnumItemModel.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Impl.Generation.Rendering 2 | { 3 | public class EnumItemModel 4 | { 5 | public string Name { get; set; } 6 | public string Synonym { get; set; } 7 | } 8 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Generation/Rendering/GenerateHelpers.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Impl.Generation.Rendering 2 | { 3 | internal static class GenerateHelpers 4 | { 5 | public static string EscapeString(string input) 6 | { 7 | return input == null ? null : input.Replace("\\", "\\\\").Replace("\"", "\\\""); 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Generation/Rendering/PropertyModel.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Impl.Generation.Rendering 2 | { 3 | internal class PropertyModel 4 | { 5 | public string PropertyName { get; set; } 6 | public int? MaxLength { get; set; } 7 | 8 | public string FieldName 9 | { 10 | get { return char.ToLower(PropertyName[0]) + PropertyName.Substring(1); } 11 | } 12 | 13 | public string Type { get; set; } 14 | } 15 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Helpers/AttributesCache.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Reflection; 4 | 5 | namespace Simple1C.Impl.Helpers 6 | { 7 | public class AttributesCache 8 | { 9 | private static readonly ConcurrentDictionary cache = new ConcurrentDictionary(); 10 | 11 | private static readonly Func createDelegate = 12 | key => key.attributeProvider.GetCustomAttributes(key.attributeType, key.inherit); 13 | 14 | public static object GetCustomAttributes(ICustomAttributeProvider attributeProvider, Type attributeType, 15 | bool inherit) 16 | { 17 | return cache.GetOrAdd(new Key(attributeProvider, attributeType, inherit), createDelegate); 18 | } 19 | 20 | public static T GetCustomAttribute(ICustomAttributeProvider attributeProvider, bool inherit) 21 | { 22 | var attributes = (T[]) GetCustomAttributes(attributeProvider, typeof(T), inherit); 23 | if (attributes.Length == 0) 24 | { 25 | const string messageFormat = "[{0}] has no attribute [{1}]"; 26 | throw new ArgumentOutOfRangeException(string.Format(messageFormat, 27 | FormatName(attributeProvider), typeof(T).Name)); 28 | } 29 | if (attributes.Length > 1) 30 | { 31 | const string messageFormat = "[{0}] has more then one attribute [{1}]"; 32 | throw new ArgumentOutOfRangeException(string.Format(messageFormat, 33 | FormatName(attributeProvider), typeof(T).Name)); 34 | } 35 | return attributes[0]; 36 | } 37 | 38 | private static string FormatName(ICustomAttributeProvider attributeProvider) 39 | { 40 | var t = (Type) attributeProvider; 41 | if (t != null) 42 | return t.FormatName(); 43 | var m = (MemberInfo) attributeProvider; 44 | if (m != null) 45 | return m.DeclaringType.FormatName() + "." + m.Name; 46 | return attributeProvider.ToString(); 47 | } 48 | 49 | private struct Key : IEquatable 50 | { 51 | public readonly ICustomAttributeProvider attributeProvider; 52 | public readonly Type attributeType; 53 | public readonly bool inherit; 54 | 55 | public Key(ICustomAttributeProvider attributeProvider, Type attributeType, bool inherit) 56 | { 57 | this.attributeProvider = attributeProvider; 58 | this.attributeType = attributeType; 59 | this.inherit = inherit; 60 | } 61 | 62 | public bool Equals(Key other) 63 | { 64 | var localInherit = inherit; 65 | return attributeProvider.Equals(other.attributeProvider) && 66 | attributeType == other.attributeType && 67 | localInherit.Equals(other.inherit); 68 | } 69 | 70 | public override bool Equals(object obj) 71 | { 72 | if (ReferenceEquals(null, obj)) return false; 73 | return obj is Key && Equals((Key) obj); 74 | } 75 | 76 | public override int GetHashCode() 77 | { 78 | unchecked 79 | { 80 | var hashCode = (attributeProvider != null ? attributeProvider.GetHashCode() : 0); 81 | hashCode = (hashCode*397) ^ (attributeType != null ? attributeType.GetHashCode() : 0); 82 | var localInherit = inherit; 83 | hashCode = (hashCode*397) ^ localInherit.GetHashCode(); 84 | return hashCode; 85 | } 86 | } 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Helpers/ByteArrayHelpers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Simple1C.Impl.Helpers 4 | { 5 | internal static class ByteArrayHelpers 6 | { 7 | public static string ToHex(this byte[] bytes) 8 | { 9 | var hex = BitConverter.ToString(bytes); 10 | return hex.Replace("-", ""); 11 | } 12 | 13 | //http://stackoverflow.com/questions/623104/byte-to-hex-string/623184#623184 14 | public static byte[] FromHex(string hex, int offset = 0) 15 | { 16 | var bytes = new byte[(hex.Length - offset) / 2]; 17 | for (int bx = 0, sx = 0; bx < bytes.Length; ++bx, ++sx) 18 | { 19 | var c = hex[sx + offset]; 20 | bytes[bx] = (byte)((c > '9' ? (c > 'Z' ? c - 'a' + 10 : c - 'A' + 10) : c - '0') << 4); 21 | c = hex[++sx + offset]; 22 | bytes[bx] |= (byte)(c > '9' ? (c > 'Z' ? c - 'a' + 10 : c - 'A' + 10) : c - '0'); 23 | } 24 | return bytes; 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Helpers/DictionaryExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Simple1C.Impl.Helpers 5 | { 6 | internal static class DictionaryExtensions 7 | { 8 | public static TValue GetOrAdd(this IDictionary dictionary, TKey key, 9 | Func valueFactory) 10 | { 11 | TValue result; 12 | if (!dictionary.TryGetValue(key, out result)) 13 | dictionary.Add(key, result = valueFactory(key)); 14 | return result; 15 | } 16 | 17 | public static TValue GetOrDefault(this IDictionary dictionary, TKey key) 18 | { 19 | TValue result; 20 | return dictionary.TryGetValue(key, out result) ? result : default(TValue); 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Helpers/EnumAttributesCache.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Reflection; 6 | 7 | namespace Simple1C.Impl.Helpers 8 | { 9 | internal static class EnumAttributesCache 10 | where TAttribute : Attribute 11 | { 12 | private static readonly ConcurrentDictionary> enumToItems = 13 | new ConcurrentDictionary>(); 14 | 15 | public static TAttribute GetAttribute(TEnum enumItem) 16 | where TEnum : struct 17 | { 18 | return GetAttributeUnsafe(enumItem); 19 | } 20 | 21 | public static TAttribute GetAttributeUnsafe(object enumItem) 22 | { 23 | TAttribute result; 24 | if (!GetAllAttributes(enumItem.GetType()) 25 | .TryGetValue(enumItem.ToString(), out result)) 26 | throw new ArgumentOutOfRangeException( 27 | "enumItem", string.Format("enum [{0}] has no [{1}] for [{2}]", 28 | enumItem.GetType().FullName, typeof(TAttribute).Name, enumItem)); 29 | return result; 30 | } 31 | 32 | public static IDictionary GetAllAttributes(Type enumType) 33 | { 34 | return enumToItems.GetOrAdd(enumType, GetEnumItems); 35 | } 36 | 37 | private static IDictionary GetEnumItems(Type enumType) 38 | { 39 | return enumType 40 | .GetFields() 41 | .Where(item => !item.IsSpecialName) 42 | .Select(item => new {item.Name, Attr = GetEnumItemAttribute(item)}) 43 | .Where(x => x.Attr != null) 44 | .ToDictionary(x => x.Name, x => x.Attr); 45 | } 46 | 47 | private static TAttribute GetEnumItemAttribute(FieldInfo enumItem) 48 | { 49 | return (TAttribute) enumItem 50 | .GetCustomAttributes(typeof(TAttribute), false) 51 | .FirstOrDefault(); 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Helpers/EnumerableExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | namespace Simple1C.Impl.Helpers 5 | { 6 | internal static class EnumerableExtensions 7 | { 8 | public static string JoinStrings(this IEnumerable source, string separator) 9 | { 10 | return string.Join(separator, source); 11 | } 12 | 13 | public static IEnumerable NotNull(this IEnumerable source) where T : class 14 | { 15 | return source.Where(x => x != null); 16 | } 17 | 18 | public static HashSet ToSet(this IEnumerable source, IEqualityComparer comparer = null) 19 | { 20 | return new HashSet(source, comparer); 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Helpers/ListFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Concurrent; 4 | using System.Collections.Generic; 5 | 6 | namespace Simple1C.Impl.Helpers 7 | { 8 | internal static class ListFactory 9 | { 10 | private static readonly ConcurrentDictionary factories = 11 | new ConcurrentDictionary(); 12 | 13 | private static readonly Func createFactory = CreateFactory; 14 | 15 | public static IList Create(Type itemType, IList source, int capacity) 16 | { 17 | return factories.GetOrAdd(itemType, createFactory).Create(source, capacity); 18 | } 19 | 20 | private static IFactory CreateFactory(Type itemType) 21 | { 22 | return (IFactory) Activator.CreateInstance(typeof (Factory<>).MakeGenericType(itemType)); 23 | } 24 | 25 | private interface IFactory 26 | { 27 | IList Create(IList source, int capacity); 28 | } 29 | 30 | private class Factory : IFactory 31 | { 32 | public IList Create(IList source, int capacity) 33 | { 34 | return source == null 35 | ? new List(capacity) 36 | : new List((IEnumerable) source); 37 | } 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Helpers/LogHelpers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | 4 | namespace Simple1C.Impl.Helpers 5 | { 6 | internal static class LogHelpers 7 | { 8 | public static void LogWithTiming(string description, Action action) 9 | { 10 | Console.Out.WriteLine(description); 11 | var s = Stopwatch.StartNew(); 12 | action(); 13 | s.Stop(); 14 | Console.Out.WriteLine("done, took [{0}] millis", s.ElapsedMilliseconds); 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Helpers/MemberAccessor/BoxingCaster.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection.Emit; 3 | 4 | namespace Simple1C.Impl.Helpers.MemberAccessor 5 | { 6 | internal class BoxingCaster : Caster 7 | { 8 | public BoxingCaster(Type outputType, Type memberType) 9 | : base(outputType, memberType) {} 10 | 11 | protected override void EmitNullableCast(ILGenerator ilGenerator, Type nullableType) 12 | { 13 | ilGenerator.Emit(OpCodes.Newobj, nullableType.GetConstructor(new[] { memberType })); 14 | } 15 | 16 | protected override void EmitValueTypeCast(ILGenerator ilGenerator) 17 | { 18 | ilGenerator.Emit(OpCodes.Box, memberType); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Helpers/MemberAccessor/Caster.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection.Emit; 3 | 4 | namespace Simple1C.Impl.Helpers.MemberAccessor 5 | { 6 | public abstract class Caster 7 | { 8 | protected readonly Type memberType; 9 | protected readonly Type outputType; 10 | 11 | protected Caster(Type outputType, Type memberType) 12 | { 13 | this.outputType = outputType; 14 | this.memberType = memberType; 15 | } 16 | 17 | protected abstract void EmitNullableCast(ILGenerator ilGenerator, Type nullableType); 18 | 19 | protected abstract void EmitValueTypeCast(ILGenerator ilGenerator); 20 | 21 | public void EmitCast(ILGenerator ilGenerator) 22 | { 23 | if (outputType == memberType) 24 | return; 25 | 26 | if (!outputType.IsAssignableFrom(memberType)) 27 | throw new TypeMismatchException(outputType, memberType); 28 | 29 | if (memberType.IsValueType && !outputType.IsValueType) 30 | EmitValueTypeCast(ilGenerator); 31 | 32 | if (outputType.IsNullableOf(memberType)) 33 | EmitNullableCast(ilGenerator, outputType); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Helpers/MemberAccessor/FieldAccessorFactory.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Reflection.Emit; 3 | 4 | namespace Simple1C.Impl.Helpers.MemberAccessor 5 | { 6 | internal class FieldAccessorFactory: MemberAccessorFactory 7 | { 8 | private readonly FieldInfo fieldInfo; 9 | 10 | public FieldAccessorFactory(FieldInfo fieldInfo): base(fieldInfo) 11 | { 12 | this.fieldInfo = fieldInfo; 13 | } 14 | 15 | protected override bool TryEmitSet(ILGenerator ilGenerator) 16 | { 17 | if (!fieldInfo.IsStatic) 18 | ilGenerator.Emit(OpCodes.Ldarg_0); 19 | ilGenerator.Emit(OpCodes.Ldarg_1); 20 | EmitUnboxingCast(fieldInfo.FieldType, ilGenerator); 21 | ilGenerator.Emit(fieldInfo.IsStatic ? OpCodes.Stsfld : OpCodes.Stfld, fieldInfo); 22 | ilGenerator.Emit(OpCodes.Ret); 23 | return true; 24 | } 25 | 26 | protected override bool TryEmitGet(ILGenerator ilGenerator) 27 | { 28 | EmitLoadTarget(ilGenerator, fieldInfo); 29 | ilGenerator.Emit(fieldInfo.IsStatic ? OpCodes.Ldsfld : OpCodes.Ldfld, fieldInfo); 30 | EmitBoxingCast(fieldInfo.FieldType, ilGenerator); 31 | ilGenerator.Emit(OpCodes.Ret); 32 | return true; 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Helpers/MemberAccessor/IAccessMember.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Impl.Helpers.MemberAccessor 2 | { 3 | public interface IAccessMember 4 | { 5 | void Set(object entity, object value); 6 | object Get(object entity); 7 | } 8 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Helpers/MemberAccessor/IMemberAccessor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Simple1C.Impl.Helpers.MemberAccessor 4 | { 5 | public interface IMemberAccessor: IAccessMember 6 | { 7 | bool CanGet { get; } 8 | bool CanSet { get; } 9 | Type MemberType { get; } 10 | } 11 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Helpers/MemberAccessor/MappingMemberAccessor.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Impl.Helpers.MemberAccessor 2 | { 3 | internal class MappingMemberAccessor: IAccessMember 4 | { 5 | private readonly IAccessMember parent; 6 | private readonly IAccessMember child; 7 | 8 | public MappingMemberAccessor(IAccessMember parent, IAccessMember child) 9 | { 10 | this.parent = parent; 11 | this.child = child; 12 | } 13 | 14 | public void Set(object entity, object value) 15 | { 16 | var parentValue = parent.Get(entity); 17 | if (parentValue != null) 18 | child.Set(parentValue, value); 19 | } 20 | 21 | public object Get(object entity) 22 | { 23 | var parentValue = parent.Get(entity); 24 | return parentValue == null ? null : child.Get(parentValue); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Helpers/MemberAccessor/MemberAccessor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Linq; 4 | using System.Reflection; 5 | 6 | namespace Simple1C.Impl.Helpers.MemberAccessor 7 | { 8 | internal class MemberAccessor: IMemberAccessor 9 | { 10 | private readonly Func getter; 11 | private readonly Action setter; 12 | 13 | public MemberAccessor(Func getter, Action setter, Type memberType) 14 | { 15 | this.getter = getter; 16 | this.setter = setter; 17 | MemberType = memberType; 18 | } 19 | 20 | public void Set(object target, TOutput value) 21 | { 22 | if (setter == null) 23 | throw new InvalidOperationException(); 24 | setter(target, value); 25 | } 26 | 27 | public void Set(object target, object value) 28 | { 29 | Set(target, (TOutput) value); 30 | } 31 | 32 | object IAccessMember.Get(object entity) 33 | { 34 | return Get(entity); 35 | } 36 | 37 | public bool CanGet 38 | { 39 | get { return getter != null; } 40 | } 41 | 42 | public bool CanSet 43 | { 44 | get { return setter != null; } 45 | } 46 | 47 | public Type MemberType { get; private set; } 48 | 49 | public TOutput Get(object target) 50 | { 51 | if (getter == null) 52 | throw new InvalidOperationException(); 53 | return getter(target); 54 | } 55 | 56 | private static readonly ConcurrentDictionary> cache = 57 | new ConcurrentDictionary>(); 58 | 59 | public static MemberAccessor Get(MemberInfo memberInfo) 60 | { 61 | return cache.GetOrAdd(memberInfo, m => MemberAccessorFactory.Create(ToDeclaring(m)).CreateAccessor()); 62 | } 63 | 64 | private static MemberInfo ToDeclaring(MemberInfo memberInfo) 65 | { 66 | return memberInfo.DeclaringType 67 | .GetMember(memberInfo.Name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static) 68 | .Single(x => x.DeclaringType == memberInfo.DeclaringType && x.MemberType == memberInfo.MemberType); 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Helpers/MemberAccessor/MemberAccessorFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using System.Reflection.Emit; 4 | 5 | namespace Simple1C.Impl.Helpers.MemberAccessor 6 | { 7 | internal abstract class MemberAccessorFactory 8 | { 9 | private readonly MemberInfo member; 10 | 11 | protected MemberAccessorFactory(MemberInfo member) 12 | { 13 | this.member = member; 14 | } 15 | 16 | protected static void EmitBoxingCast(Type memberType, ILGenerator ilGenerator) 17 | { 18 | var caster = new BoxingCaster(typeof (TOutput), memberType); 19 | caster.EmitCast(ilGenerator); 20 | } 21 | 22 | protected static void EmitUnboxingCast(Type memberType, ILGenerator ilGenerator) 23 | { 24 | var caster = new UnboxingCaster(typeof (TOutput), memberType); 25 | caster.EmitCast(ilGenerator); 26 | } 27 | 28 | public static MemberAccessorFactory Create(MemberInfo memberInfo) 29 | { 30 | if (memberInfo is FieldInfo) 31 | return new FieldAccessorFactory(memberInfo as FieldInfo); 32 | if (memberInfo is PropertyInfo) 33 | return new PropertyAccessorFactory(memberInfo as PropertyInfo); 34 | throw new Exception("Invalid member info"); 35 | } 36 | 37 | protected static void EmitLoadTarget(ILGenerator ilGenerator, MemberInfo member) 38 | { 39 | if (member.IsStatic()) 40 | return; 41 | ilGenerator.Emit(OpCodes.Ldarg_0); 42 | var declaringType = member.DeclaringType; 43 | if (!declaringType.IsValueType) 44 | return; 45 | ilGenerator.Emit(OpCodes.Unbox_Any, declaringType); 46 | ilGenerator.DeclareLocal(declaringType); 47 | ilGenerator.Emit(OpCodes.Stloc_0); 48 | ilGenerator.Emit(OpCodes.Ldloca_S, 0); 49 | } 50 | 51 | public MemberAccessor CreateAccessor() 52 | { 53 | return new MemberAccessor(CreateGetter(), CreateSetter(), member.MemberType()); 54 | } 55 | 56 | private Action CreateSetter() 57 | { 58 | var method = CreateSettingMethod(); 59 | return TryEmitSet(method.GetILGenerator()) ? CreateSettingDelegate(method) : null; 60 | } 61 | 62 | private Func CreateGetter() 63 | { 64 | var method = CreateGettingMethod(); 65 | return TryEmitGet(method.GetILGenerator()) ? CreateGettingDelegate(method) : null; 66 | } 67 | 68 | #region Protected interface 69 | 70 | protected abstract bool TryEmitSet(ILGenerator ilGenerator); 71 | protected abstract bool TryEmitGet(ILGenerator ilGenerator); 72 | 73 | #endregion 74 | 75 | #region Helpers 76 | 77 | private static Action CreateSettingDelegate(DynamicMethod dynamicMethod) 78 | { 79 | return (Action) dynamicMethod.CreateDelegate(typeof (Action)); 80 | } 81 | 82 | private static Func CreateGettingDelegate(DynamicMethod dynamicMethod) 83 | { 84 | return (Func) dynamicMethod.CreateDelegate(typeof (Func)); 85 | } 86 | 87 | private static DynamicMethod CreateSettingMethod() 88 | { 89 | return new DynamicMethod("", 90 | null, 91 | new[] { typeof (object), typeof (TOutput) }, 92 | typeof (MemberAccessor), 93 | true); 94 | } 95 | 96 | private static DynamicMethod CreateGettingMethod() 97 | { 98 | return new DynamicMethod("", 99 | typeof (TOutput), 100 | new[] { typeof (object) }, 101 | typeof (MemberAccessor), 102 | true); 103 | } 104 | 105 | #endregion 106 | } 107 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Helpers/MemberAccessor/PropertyAccessorFactory.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Reflection.Emit; 3 | 4 | namespace Simple1C.Impl.Helpers.MemberAccessor 5 | { 6 | internal class PropertyAccessorFactory: MemberAccessorFactory 7 | { 8 | private readonly PropertyInfo propertyInfo; 9 | 10 | public PropertyAccessorFactory(PropertyInfo propertyInfo): base(propertyInfo) 11 | { 12 | this.propertyInfo = propertyInfo; 13 | } 14 | 15 | protected override bool TryEmitSet(ILGenerator ilGenerator) 16 | { 17 | var setter = propertyInfo.GetSetMethod(true); 18 | if (setter == null) 19 | return false; 20 | if (!propertyInfo.IsStatic()) 21 | ilGenerator.Emit(OpCodes.Ldarg_0); 22 | ilGenerator.Emit(OpCodes.Ldarg_1); 23 | EmitUnboxingCast(propertyInfo.PropertyType, ilGenerator); 24 | ilGenerator.Emit(OpCodes.Call, setter); 25 | ilGenerator.Emit(OpCodes.Ret); 26 | return true; 27 | } 28 | 29 | protected override bool TryEmitGet(ILGenerator ilGenerator) 30 | { 31 | var getter = propertyInfo.GetGetMethod(true); 32 | if (getter == null) 33 | return false; 34 | EmitLoadTarget(ilGenerator, propertyInfo); 35 | ilGenerator.Emit(OpCodes.Call, getter); 36 | EmitBoxingCast(propertyInfo.PropertyType, ilGenerator); 37 | ilGenerator.Emit(OpCodes.Ret); 38 | return true; 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Helpers/MemberAccessor/TypeMismatchException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Simple1C.Impl.Helpers.MemberAccessor 4 | { 5 | internal class TypeMismatchException : Exception 6 | { 7 | public TypeMismatchException(Type first, Type second) 8 | : base(string.Format("Типы '{0}' и '{1}' несовместимы", first.FullName, second.FullName)) 9 | { 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Helpers/MemberAccessor/UnboxingCaster.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection.Emit; 3 | 4 | namespace Simple1C.Impl.Helpers.MemberAccessor 5 | { 6 | internal class UnboxingCaster: Caster 7 | { 8 | public UnboxingCaster(Type outputType, Type memberType): base(outputType, memberType) 9 | { 10 | } 11 | 12 | protected override void EmitNullableCast(ILGenerator ilGenerator, Type nullableType) 13 | { 14 | ilGenerator.DeclareLocal(outputType); 15 | ilGenerator.Emit(OpCodes.Stloc_0); 16 | ilGenerator.Emit(OpCodes.Ldloca_S, 0); 17 | ilGenerator.Emit(OpCodes.Call, nullableType.GetProperty("Value").GetGetMethod()); 18 | } 19 | 20 | protected override void EmitValueTypeCast(ILGenerator ilGenerator) 21 | { 22 | ilGenerator.Emit(OpCodes.Unbox_Any, memberType); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Helpers/MemberAccessor/UntypedMemberAccessor.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | namespace Simple1C.Impl.Helpers.MemberAccessor 4 | { 5 | internal class UntypedMemberAccessor 6 | { 7 | public static IMemberAccessor Create(MemberInfo memberInfo) 8 | { 9 | return MemberAccessor.Get(memberInfo); 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Helpers/NameValueCollectionHelpers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.Specialized; 4 | 5 | namespace Simple1C.Impl.Helpers 6 | { 7 | internal static class NameValueCollectionHelpers 8 | { 9 | public static NameValueCollection ParseCommandLine(IEnumerable args) 10 | { 11 | var result = new NameValueCollection(); 12 | var state = CommandLineParsingState.WaitingTerm; 13 | string key = null; 14 | foreach (var argument in args) 15 | switch (state) 16 | { 17 | case CommandLineParsingState.WaitingTerm: 18 | if (IsKey(argument)) 19 | { 20 | key = GetKey(argument); 21 | state = CommandLineParsingState.WaitingValue; 22 | } 23 | else 24 | throw new InvalidOperationException( 25 | string.Format("Expected term (must start from '-' or '/') but actual was '{0}'", 26 | argument)); 27 | break; 28 | case CommandLineParsingState.WaitingValue: 29 | if (IsKey(argument)) 30 | { 31 | result.Add(key, "true"); 32 | key = GetKey(argument); 33 | state = CommandLineParsingState.WaitingValue; 34 | } 35 | else 36 | { 37 | result.Add(key, argument); 38 | key = null; 39 | state = CommandLineParsingState.WaitingTerm; 40 | } 41 | break; 42 | } 43 | if (state == CommandLineParsingState.WaitingValue) 44 | result.Add(key, "true"); 45 | return result; 46 | } 47 | 48 | private static bool IsKey(string argument) 49 | { 50 | return argument.StartsWith("-") || argument.StartsWith("/"); 51 | } 52 | 53 | private static string GetKey(string argument) 54 | { 55 | return argument.Substring(1); 56 | } 57 | 58 | private enum CommandLineParsingState 59 | { 60 | WaitingTerm, 61 | WaitingValue 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Helpers/RelinqHelpers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Linq; 4 | using Remotion.Linq.Parsing.ExpressionVisitors.Transformation; 5 | using Remotion.Linq.Parsing.Structure; 6 | using Remotion.Linq.Parsing.Structure.NodeTypeProviders; 7 | using Simple1C.Impl.Queriables; 8 | 9 | namespace Simple1C.Impl.Helpers 10 | { 11 | internal static class RelinqHelpers 12 | { 13 | private static IQueryParser queryParser; 14 | 15 | public static IQueryProvider CreateQueryProvider(TypeRegistry typeRegistry, 16 | Func execute) 17 | { 18 | if (queryParser == null) 19 | queryParser = CreateQueryParser(); 20 | return new RelinqQueryProvider(queryParser, 21 | new RelinqQueryExecutor(typeRegistry, execute)); 22 | } 23 | 24 | private static IQueryParser CreateQueryParser() 25 | { 26 | var nodeTypeProvider = new CompoundNodeTypeProvider(new INodeTypeProvider[] 27 | { 28 | MethodInfoBasedNodeTypeRegistry.CreateFromRelinqAssembly() 29 | }); 30 | var transformerRegistry = ExpressionTransformerRegistry.CreateDefault(); 31 | var expressionTreeParser = new ExpressionTreeParser(nodeTypeProvider, 32 | ExpressionTreeParser.CreateDefaultProcessor(transformerRegistry)); 33 | return new QueryParser(expressionTreeParser); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Helpers/StringHelpers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Simple1C.Impl.Helpers 5 | { 6 | internal static class StringHelpers 7 | { 8 | public static bool EqualsIgnoringCase(this string s1, string s2) 9 | { 10 | return string.Equals(s1, s2, StringComparison.OrdinalIgnoreCase); 11 | } 12 | 13 | public static bool ContainsIgnoringCase(this string s1, string s2) 14 | { 15 | return s1.IndexOf(s2, StringComparison.OrdinalIgnoreCase) >= 0; 16 | } 17 | 18 | public static string ExcludeSuffix(this string s1, string suffix) 19 | { 20 | return s1 != null && s1.EndsWith(suffix) 21 | ? s1.Substring(0, s1.Length - suffix.Length) 22 | : s1; 23 | } 24 | 25 | public static IEnumerable ParseLinesWithTabs(string source, Func, T> func) 26 | { 27 | var lines = source.Split(new[] {"\r\n"}, StringSplitOptions.RemoveEmptyEntries); 28 | var items = new List(); 29 | string headerLine = null; 30 | foreach (var s in lines) 31 | { 32 | if (s[0] == '\t') 33 | items.Add(s.Substring(1)); 34 | else 35 | { 36 | if (headerLine != null) 37 | { 38 | yield return func(headerLine, items); 39 | items.Clear(); 40 | } 41 | headerLine = s; 42 | } 43 | } 44 | if (headerLine != null) 45 | yield return func(headerLine, items); 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /Simple1C/Impl/IValueSource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Simple1C.Impl 4 | { 5 | public interface IValueSource 6 | { 7 | object GetBackingStorage(); 8 | bool Writable { get; } 9 | bool TryLoadValue(string name, Type type, out object result); 10 | } 11 | } -------------------------------------------------------------------------------- /Simple1C/Impl/MappingSource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Reflection; 4 | 5 | namespace Simple1C.Impl 6 | { 7 | internal class MappingSource 8 | { 9 | private static readonly ConcurrentDictionary mappingsCache = 10 | new ConcurrentDictionary(); 11 | 12 | public static MappingSource Map(GlobalContext globalContext, Assembly assembly) 13 | { 14 | MappingSource result; 15 | var connectionString = globalContext.GetConnectionString(); 16 | if (!mappingsCache.TryGetValue(connectionString, out result)) 17 | mappingsCache.TryAdd(connectionString, result = new MappingSource(assembly)); 18 | else if (!ReferenceEquals(result.TypeRegistry.Assembly, assembly)) 19 | { 20 | const string messageFormat = "can't map [{0}] to [{1}] because it's already mapped to [{2}]"; 21 | throw new InvalidOperationException(string.Format(messageFormat, connectionString, 22 | assembly.GetName().Name, result.TypeRegistry.Assembly.GetName().Name)); 23 | } 24 | return result; 25 | } 26 | 27 | public MappingSource(Assembly assembly) 28 | { 29 | MetadataCache = new ConcurrentDictionary(); 30 | EnumMappingsCache = new ConcurrentDictionary(); 31 | TypeRegistry = new TypeRegistry(assembly); 32 | } 33 | 34 | public ConcurrentDictionary MetadataCache { get; private set; } 35 | public ConcurrentDictionary EnumMappingsCache { get; private set; } 36 | public TypeRegistry TypeRegistry { get; private set; } 37 | } 38 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Metadata.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace Simple1C.Impl 6 | { 7 | internal class Metadata 8 | { 9 | private readonly Dictionary requisiteByName; 10 | 11 | public Metadata(string fullname, MetadataRequisite[] requisites) 12 | { 13 | Fullname = fullname; 14 | Requisites = requisites; 15 | requisiteByName = requisites.ToDictionary(x => x.Name ?? ""); 16 | } 17 | 18 | public string Fullname { get; private set; } 19 | public MetadataRequisite[] Requisites { get; private set; } 20 | 21 | public void Validate(string name, object value) 22 | { 23 | var requisite = requisiteByName[name ?? ""]; 24 | if (!requisite.MaxLength.HasValue) 25 | return; 26 | var stringValue = value as string; 27 | if (stringValue == null) 28 | throw new InvalidOperationException("assertion failure"); 29 | if (stringValue.Length <= requisite.MaxLength.Value) 30 | return; 31 | const string messageFormat = "[{0}{1}] value [{2}] length [{3}] " + 32 | "is greater than configured max [{4}]"; 33 | throw new InvalidOperationException(string.Format(messageFormat, 34 | Fullname, string.IsNullOrEmpty(name) ? name : "." + name, 35 | stringValue, stringValue.Length, requisite.MaxLength.Value)); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /Simple1C/Impl/MetadataAccessor.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Simple1C.Impl.Com; 3 | using Simple1C.Interface; 4 | 5 | namespace Simple1C.Impl 6 | { 7 | internal class MetadataAccessor 8 | { 9 | private readonly MappingSource mappingSource; 10 | private readonly GlobalContext globalContext; 11 | 12 | public MetadataAccessor(MappingSource mappingSource, GlobalContext globalContext) 13 | { 14 | this.mappingSource = mappingSource; 15 | this.globalContext = globalContext; 16 | } 17 | 18 | public Metadata GetMetadata(ConfigurationName configurationName) 19 | { 20 | Metadata result; 21 | if (!mappingSource.MetadataCache.TryGetValue(configurationName, out result)) 22 | { 23 | result = CreateMetadata(configurationName); 24 | mappingSource.MetadataCache.TryAdd(configurationName, result); 25 | } 26 | return result; 27 | } 28 | 29 | private Metadata CreateMetadata(ConfigurationName name) 30 | { 31 | var metadata = globalContext.FindMetaByName(name); 32 | if (name.Scope == ConfigurationScope.Константы) 33 | return new Metadata(name.Fullname, new[] 34 | { 35 | new MetadataRequisite {MaxLength = GetMaxLength(metadata.ComObject)} 36 | }); 37 | var descriptor = MetadataHelpers.GetDescriptor(name.Scope); 38 | var attributes = MetadataHelpers.GetAttributes(metadata.ComObject, descriptor).ToArray(); 39 | var result = new MetadataRequisite[attributes.Length]; 40 | for (var i = 0; i < attributes.Length; i++) 41 | { 42 | var attr = attributes[i]; 43 | result[i] = new MetadataRequisite 44 | { 45 | Name = Call.Имя(attr), 46 | MaxLength = GetMaxLength(attr) 47 | }; 48 | } 49 | return new Metadata(name.Fullname, result); 50 | } 51 | 52 | private int? GetMaxLength(object attribute) 53 | { 54 | var type = ComHelpers.GetProperty(attribute, "Тип"); 55 | var typesObject = ComHelpers.Invoke(type, "Типы"); 56 | var typesCount = Call.Количество(typesObject); 57 | if (typesCount != 1) 58 | return null; 59 | var typeObject = Call.Получить(typesObject, 0); 60 | var stringPresentation = globalContext.String(typeObject); 61 | if (stringPresentation != "Строка") 62 | return null; 63 | var квалификаторыСтроки = ComHelpers.GetProperty(type, "КвалификаторыСтроки"); 64 | var result = Call.IntProp(квалификаторыСтроки, "Длина"); 65 | if (result == 0) 66 | return null; 67 | return result; 68 | } 69 | } 70 | } -------------------------------------------------------------------------------- /Simple1C/Impl/MetadataRequisite.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Impl 2 | { 3 | internal class MetadataRequisite 4 | { 5 | public string Name { get; set; } 6 | public int? MaxLength { get; set; } 7 | } 8 | } -------------------------------------------------------------------------------- /Simple1C/Impl/ObservedValue.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | 3 | namespace Simple1C.Impl 4 | { 5 | internal struct ObservedValue 6 | { 7 | public IList originalList; 8 | public object value; 9 | } 10 | } -------------------------------------------------------------------------------- /Simple1C/Impl/ParametersConverter.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivan816/simple-1c/f2e5ce78b98f70f30039fd3de79308a59d432fc2/Simple1C/Impl/ParametersConverter.cs -------------------------------------------------------------------------------- /Simple1C/Impl/Queriables/BuiltQuery.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Simple1C.Impl.Queriables 5 | { 6 | internal class BuiltQuery 7 | { 8 | private BuiltQuery(Type entityType) 9 | { 10 | EntityType = entityType; 11 | } 12 | 13 | public BuiltQuery(Type entityType, string queryText, 14 | Dictionary parameters, Projection projection, bool isCount) 15 | { 16 | EntityType = entityType; 17 | QueryText = queryText; 18 | Parameters = parameters; 19 | Projection = projection; 20 | IsCount = isCount; 21 | } 22 | 23 | public static BuiltQuery Constant(Type entityType) 24 | { 25 | return new BuiltQuery(entityType) {IsQueryForConstant = true}; 26 | } 27 | 28 | public Type EntityType { get; private set; } 29 | public string QueryText { get; private set; } 30 | public Dictionary Parameters { get; private set; } 31 | public Projection Projection { get; private set; } 32 | public bool IsCount { get; private set; } 33 | public bool IsQueryForConstant { get; private set; } 34 | } 35 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Queriables/ConvertEnumCmd.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Simple1C.Impl.Queriables 4 | { 5 | internal class ConvertEnumCmd : IConvertParameterCmd 6 | { 7 | public int valueIndex; 8 | public Type enumType; 9 | } 10 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Queriables/ConvertUniqueIdentifierCmd.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Simple1C.Impl.Queriables 4 | { 5 | internal class ConvertUniqueIdentifierCmd : IConvertParameterCmd 6 | { 7 | public Guid id; 8 | public Type entityType; 9 | } 10 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Queriables/IConvertParameterCmd.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Impl.Queriables 2 | { 3 | internal interface IConvertParameterCmd 4 | { 5 | } 6 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Queriables/IRelinqQueryable.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Impl.Queriables 2 | { 3 | public interface IRelinqQueryable 4 | { 5 | string SourceName { get; } 6 | } 7 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Queriables/MemberAccessBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq.Expressions; 4 | using System.Reflection; 5 | using Remotion.Linq.Clauses; 6 | using Remotion.Linq.Clauses.Expressions; 7 | using Remotion.Linq.Parsing; 8 | using Simple1C.Interface; 9 | 10 | namespace Simple1C.Impl.Queriables 11 | { 12 | internal class MemberAccessBuilder : RelinqExpressionVisitor 13 | { 14 | private readonly Dictionary querySourceMapping = 15 | new Dictionary(); 16 | 17 | private readonly List members = new List(); 18 | private string sourceName; 19 | private bool isLocal; 20 | 21 | private static readonly MethodInfo presentationMethodInfo = typeof(Функции).GetMethod("Представление", 22 | BindingFlags.Static | BindingFlags.Public); 23 | 24 | public QueryField GetFieldOrNull(Expression expression) 25 | { 26 | members.Clear(); 27 | isLocal = false; 28 | var type = expression.Type; 29 | var xMethodCall = expression as MethodCallExpression; 30 | var isPresentation = xMethodCall != null && xMethodCall.Method == presentationMethodInfo; 31 | if (isPresentation) 32 | expression = xMethodCall.Arguments[0]; 33 | xMethodCall = expression as MethodCallExpression; 34 | var isGetType = xMethodCall != null && xMethodCall.Object != null 35 | && xMethodCall.Method.Name == "GetType" 36 | && xMethodCall.Arguments.Count == 0 37 | && xMethodCall.Type == typeof(Type); 38 | if (isGetType) 39 | expression = xMethodCall.Object; 40 | Visit(expression); 41 | return isLocal ? null : new QueryField(sourceName, members, isPresentation, isGetType, type); 42 | } 43 | 44 | public void Map(IQuerySource source, string value) 45 | { 46 | querySourceMapping[source] = value; 47 | } 48 | 49 | public override Expression Visit(Expression node) 50 | { 51 | if (isLocal) 52 | return node; 53 | 54 | var isMembersChain = node is MemberExpression || 55 | node is QuerySourceReferenceExpression || 56 | node.NodeType == ExpressionType.Convert; 57 | if (isMembersChain) 58 | return base.Visit(node); 59 | 60 | isLocal = true; 61 | return node; 62 | } 63 | 64 | protected override Expression VisitMember(MemberExpression node) 65 | { 66 | Visit(node.Expression); 67 | members.Add(node.Member.Name); 68 | return node; 69 | } 70 | 71 | protected override Expression VisitQuerySourceReference(QuerySourceReferenceExpression expression) 72 | { 73 | sourceName = querySourceMapping[expression.ReferencedQuerySource]; 74 | return base.VisitQuerySourceReference(expression); 75 | } 76 | } 77 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Queriables/Ordering.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Impl.Queriables 2 | { 3 | internal class Ordering 4 | { 5 | public QueryField Field { get; set; } 6 | public bool IsAsc { get; set; } 7 | } 8 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Queriables/ParameterizingExpressionVisitor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq.Expressions; 3 | using Remotion.Linq.Parsing; 4 | 5 | namespace Simple1C.Impl.Queriables 6 | { 7 | internal class ParameterizingExpressionVisitor : RelinqExpressionVisitor 8 | { 9 | private int parameterIndex; 10 | private ParameterExpression xParameter; 11 | 12 | public Expression Parameterize(Expression expression, ParameterExpression xTargetParameter) 13 | { 14 | parameterIndex = 0; 15 | xParameter = xTargetParameter; 16 | return Visit(expression); 17 | } 18 | 19 | protected override Expression VisitConstant(ConstantExpression node) 20 | { 21 | return EmitParameterAccess(node.Type); 22 | } 23 | 24 | protected override Expression VisitMember(MemberExpression node) 25 | { 26 | return EmitParameterAccess(node.Type); 27 | } 28 | 29 | private Expression EmitParameterAccess(Type type) 30 | { 31 | var xArrayItem = Expression.ArrayIndex(xParameter, Expression.Constant(parameterIndex)); 32 | var result = Expression.Convert(xArrayItem, type); 33 | parameterIndex++; 34 | return result; 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Queriables/Projection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using System.Text; 4 | using Simple1C.Impl.Helpers; 5 | 6 | namespace Simple1C.Impl.Queriables 7 | { 8 | internal class Projection 9 | { 10 | public QueryField[] fields; 11 | public SelectedProperty[] properties; 12 | public Type resultType; 13 | public ConstructorInfo ctor; 14 | public MemberInfo[] initMembers; 15 | 16 | public string GetSelection() 17 | { 18 | var b = new StringBuilder(); 19 | foreach (var queryField in fields) 20 | { 21 | b.Append(queryField.Expression); 22 | b.Append(" КАК "); 23 | b.Append(queryField.Alias); 24 | b.Append(','); 25 | } 26 | b.Length = b.Length - 1; 27 | return b.ToString(); 28 | } 29 | 30 | public string GetCacheKey() 31 | { 32 | var b = new StringBuilder(); 33 | if (resultType != null) 34 | b.Append(resultType.FormatName()); 35 | b.Append('-'); 36 | foreach (var t in fields) 37 | { 38 | b.Append(t.Alias); 39 | b.Append('-'); 40 | } 41 | return b.ToString(); 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Queriables/PropertiesExtractingVisitor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq.Expressions; 4 | using System.Reflection; 5 | using Remotion.Linq.Clauses.Expressions; 6 | using Remotion.Linq.Parsing; 7 | using Simple1C.Interface; 8 | 9 | namespace Simple1C.Impl.Queriables 10 | { 11 | internal class PropertiesExtractingVisitor : RelinqExpressionVisitor 12 | { 13 | private readonly MemberAccessBuilder memberAccessBuilder; 14 | private readonly List fields = new List(); 15 | private readonly List items = new List(); 16 | private Expression xRoot; 17 | private bool rootIsSingleItem; 18 | 19 | private static readonly MethodInfo presentationMethodInfo = typeof(Функции) 20 | .GetMethod("Представление", BindingFlags.Static | BindingFlags.Public); 21 | 22 | public PropertiesExtractingVisitor(MemberAccessBuilder memberAccessBuilder) 23 | { 24 | this.memberAccessBuilder = memberAccessBuilder; 25 | } 26 | 27 | public QueryField[] GetFields() 28 | { 29 | var result = fields.ToArray(); 30 | fields.Clear(); 31 | return result; 32 | } 33 | 34 | public SelectedProperty GetProperty(Expression expression) 35 | { 36 | xRoot = expression; 37 | rootIsSingleItem = false; 38 | items.Clear(); 39 | Visit(xRoot); 40 | return new SelectedProperty 41 | { 42 | expression = expression, 43 | needLocalEval = !rootIsSingleItem, 44 | items = items.ToArray(), 45 | }; 46 | } 47 | 48 | protected override Expression VisitQuerySourceReference(QuerySourceReferenceExpression node) 49 | { 50 | return VisitMember(node, base.VisitQuerySourceReference); 51 | } 52 | 53 | protected override Expression VisitConstant(ConstantExpression node) 54 | { 55 | rootIsSingleItem = ReferenceEquals(node, xRoot); 56 | items.Add(new SelectedPropertyItem(node.Value, -1)); 57 | return node; 58 | } 59 | 60 | protected override Expression VisitMethodCall(MethodCallExpression node) 61 | { 62 | if (node.Method == presentationMethodInfo) 63 | return VisitMember(node, m => Visit(node.Arguments[0])); 64 | if (node.Object != null && node.Method.Name == "GetType" && node.Arguments.Count == 0 && 65 | node.Type == typeof(Type)) 66 | return VisitMember(node, m => Visit(node.Object)); 67 | return base.VisitMethodCall(node); 68 | } 69 | 70 | protected override Expression VisitMember(MemberExpression node) 71 | { 72 | return VisitMember(node, base.VisitMember); 73 | } 74 | 75 | private Expression VisitMember(T node, Func baseCaller) where T:Expression 76 | { 77 | var queryField = memberAccessBuilder.GetFieldOrNull(node); 78 | if (queryField == null) 79 | return baseCaller(node); 80 | rootIsSingleItem = ReferenceEquals(node, xRoot); 81 | var fieldIndex = -1; 82 | for (var i = 0; i < fields.Count; i++) 83 | if (fields[i].Alias == queryField.Alias) 84 | { 85 | fieldIndex = i; 86 | break; 87 | } 88 | if (fieldIndex < 0) 89 | { 90 | fields.Add(queryField); 91 | fieldIndex = fields.Count - 1; 92 | } 93 | items.Add(new SelectedPropertyItem(null, fieldIndex)); 94 | return node; 95 | } 96 | } 97 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Queriables/QueryField.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Simple1C.Impl.Com; 4 | 5 | namespace Simple1C.Impl.Queriables 6 | { 7 | internal class QueryField 8 | { 9 | private readonly bool isUniqueIdentifier; 10 | 11 | public QueryField(string sourceName, List pathItems, bool needPresentation, bool needType, Type type) 12 | { 13 | Type = type; 14 | PathItems = pathItems.Count == 0 ? new[] {"Ссылка"} : pathItems.ToArray(); 15 | isUniqueIdentifier = PathItems[PathItems.Length - 1] == EntityHelpers.idPropertyName; 16 | if (isUniqueIdentifier) 17 | PathItems[PathItems.Length - 1] = "Ссылка"; 18 | Expression = sourceName + "." + string.Join(".", PathItems); 19 | Alias = Expression.Replace('.', '_'); 20 | if (isUniqueIdentifier) 21 | Alias = Alias + "_ИД"; 22 | if (needType) 23 | { 24 | Expression = "ТИПЗНАЧЕНИЯ(" + Expression + ")"; 25 | Alias = Alias + "_ТИПЗНАЧЕНИЯ"; 26 | } 27 | if (needPresentation) 28 | { 29 | Expression = "ПРЕДСТАВЛЕНИЕ(" + Expression + ")"; 30 | Alias = Alias + "_ПРЕДСТАВЛЕНИЕ"; 31 | } 32 | } 33 | 34 | public object GetValue(object queryResultRow) 35 | { 36 | var result = ComHelpers.GetProperty(queryResultRow, Alias); 37 | if (isUniqueIdentifier) 38 | result = result == null || result == DBNull.Value 39 | ? null 40 | : ComHelpers.Invoke(result, EntityHelpers.idPropertyName); 41 | return result; 42 | } 43 | 44 | public string[] PathItems { get; private set; } 45 | public string Alias { get; private set; } 46 | public string Expression { get; private set; } 47 | public Type Type { get; private set; } 48 | } 49 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Queriables/RelinqQueryExecutor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using Remotion.Linq; 6 | 7 | namespace Simple1C.Impl.Queriables 8 | { 9 | internal class RelinqQueryExecutor : IQueryExecutor 10 | { 11 | private readonly TypeRegistry typeRegistry; 12 | private readonly Func execute; 13 | 14 | public RelinqQueryExecutor(TypeRegistry typeRegistry, Func execute) 15 | { 16 | this.typeRegistry = typeRegistry; 17 | this.execute = execute; 18 | } 19 | 20 | public T ExecuteScalar(QueryModel queryModel) 21 | { 22 | return ExecuteCollection(queryModel).Single(); 23 | } 24 | 25 | public T ExecuteSingle(QueryModel queryModel, bool returnDefaultWhenEmpty) 26 | { 27 | return returnDefaultWhenEmpty 28 | ? ExecuteCollection(queryModel).SingleOrDefault() 29 | : ExecuteCollection(queryModel).Single(); 30 | } 31 | 32 | public IEnumerable ExecuteCollection(QueryModel queryModel) 33 | { 34 | BuiltQuery builtQuery; 35 | if (EntityHelpers.IsConstant(typeof(T))) 36 | builtQuery = BuiltQuery.Constant(typeof(T)); 37 | else 38 | { 39 | var builder = new QueryBuilder(typeRegistry); 40 | queryModel.Accept(new QueryModelVisitor(builder)); 41 | builtQuery = builder.Build(); 42 | } 43 | return execute(builtQuery).Cast(); 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Queriables/RelinqQueryProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Linq.Expressions; 3 | using Remotion.Linq; 4 | using Remotion.Linq.Parsing.Structure; 5 | 6 | namespace Simple1C.Impl.Queriables 7 | { 8 | internal class RelinqQueryProvider : QueryProviderBase 9 | { 10 | public RelinqQueryProvider(IQueryParser queryParser, IQueryExecutor executor) 11 | : base(queryParser, executor) 12 | { 13 | } 14 | 15 | public override IQueryable CreateQuery(Expression expression) 16 | { 17 | return new RelinqQueryable(this, expression); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Queriables/RelinqQueryable.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Linq.Expressions; 3 | using Remotion.Linq; 4 | 5 | namespace Simple1C.Impl.Queriables 6 | { 7 | internal class RelinqQueryable : QueryableBase, IRelinqQueryable 8 | { 9 | public RelinqQueryable(IQueryProvider queryProvider, string sourceName) 10 | : base(queryProvider) 11 | { 12 | SourceName = sourceName; 13 | } 14 | 15 | public RelinqQueryable(IQueryProvider queryProvider, Expression expression) 16 | : base(queryProvider, expression) 17 | { 18 | } 19 | 20 | public string SourceName { get; private set; } 21 | } 22 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Queriables/SelectedProperty.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq.Expressions; 3 | 4 | namespace Simple1C.Impl.Queriables 5 | { 6 | internal class SelectedProperty 7 | { 8 | public Expression expression; 9 | public Func compiledExpression; 10 | public bool needLocalEval; 11 | public SelectedPropertyItem[] items; 12 | } 13 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Queriables/SelectedPropertyItem.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | namespace Simple1C.Impl.Queriables 4 | { 5 | internal struct SelectedPropertyItem 6 | { 7 | public SelectedPropertyItem(object constant, int queryFieldIndex) 8 | { 9 | this.constant = constant; 10 | this.queryFieldIndex = queryFieldIndex; 11 | } 12 | 13 | private readonly object constant; 14 | private readonly int queryFieldIndex; 15 | 16 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 17 | public object GetValue(object[] fieldValues) 18 | { 19 | return queryFieldIndex < 0 ? constant : fieldValues[queryFieldIndex]; 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Queries/QueryResult.cs: -------------------------------------------------------------------------------- 1 | using Simple1C.Impl.Com; 2 | 3 | namespace Simple1C.Impl.Queries 4 | { 5 | internal class QueryResult : DispatchObject 6 | { 7 | public QueryResult(object comObject) 8 | : base(comObject) 9 | { 10 | } 11 | 12 | public QueryResultSelection Select() 13 | { 14 | return new QueryResultSelection(Invoke("Select")); 15 | } 16 | 17 | public ValueTable Unload() 18 | { 19 | return new ValueTable(Invoke("Unload")); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Queries/QueryResultSelection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Simple1C.Impl.Com; 3 | 4 | namespace Simple1C.Impl.Queries 5 | { 6 | internal class QueryResultSelection 7 | { 8 | private readonly object comObject; 9 | 10 | internal QueryResultSelection(object comObject) 11 | { 12 | this.comObject = comObject; 13 | } 14 | 15 | public object ComObject 16 | { 17 | get { return comObject; } 18 | } 19 | 20 | public string GetString(string name) 21 | { 22 | return Convert.ToString(ComHelpers.GetProperty(comObject, name)); 23 | } 24 | 25 | public object this[string name] 26 | { 27 | get { return ComHelpers.GetProperty(comObject, name); } 28 | } 29 | 30 | public bool Next() 31 | { 32 | return Convert.ToBoolean(ComHelpers.Invoke(comObject, "Следующий")); 33 | } 34 | 35 | public void Reset() 36 | { 37 | ComHelpers.Invoke(comObject, "Сбросить"); 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Queries/ValueTable.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Simple1C.Impl.Com; 5 | 6 | namespace Simple1C.Impl.Queries 7 | { 8 | internal class ValueTable : DispatchObject, IEnumerable 9 | { 10 | private readonly Dictionary columnsMap; 11 | 12 | public ValueTable(object comObject) : base(comObject) 13 | { 14 | columnsMap = GetColumns().GetMap(); 15 | } 16 | 17 | public ValueTableColumnCollection GetColumns() 18 | { 19 | return new ValueTableColumnCollection(Get("Columns")); 20 | } 21 | 22 | public int Count 23 | { 24 | get { return (int) Invoke("Count"); } 25 | } 26 | 27 | public ValueTableRow this[int index] 28 | { 29 | get { return Get(index); } 30 | } 31 | 32 | public ValueTableRow Get(int i) 33 | { 34 | return new ValueTableRow(Invoke("Get", i), columnsMap); 35 | } 36 | 37 | IEnumerator IEnumerable.GetEnumerator() 38 | { 39 | return GetEnumerator(); 40 | } 41 | 42 | public IEnumerator GetEnumerator() 43 | { 44 | return Enumerable.Range(0, Count).Select(x => this[x]).GetEnumerator(); 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Queries/ValueTableColumn.cs: -------------------------------------------------------------------------------- 1 | using Simple1C.Impl.Com; 2 | 3 | namespace Simple1C.Impl.Queries 4 | { 5 | internal class ValueTableColumn : DispatchObject 6 | { 7 | public ValueTableColumn(object comObject) 8 | : base(comObject) 9 | { 10 | } 11 | 12 | public string Name 13 | { 14 | get { return GetString("Name"); } 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Queries/ValueTableColumnCollection.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Simple1C.Impl.Com; 3 | 4 | namespace Simple1C.Impl.Queries 5 | { 6 | internal class ValueTableColumnCollection : DispatchObject 7 | { 8 | public ValueTableColumnCollection(object comObject) 9 | : base(comObject) 10 | { 11 | } 12 | 13 | public int Count 14 | { 15 | get { return (int) Invoke("Count"); } 16 | } 17 | 18 | public ValueTableColumn Get(int i) 19 | { 20 | return new ValueTableColumn(Invoke("Get", i)); 21 | } 22 | 23 | public Dictionary GetMap() 24 | { 25 | var result = new Dictionary(); 26 | for (var i = 0; i < Count; i++) 27 | result[Get(i).Name] = i; 28 | return result; 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Queries/ValueTableRow.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Simple1C.Impl.Com; 3 | 4 | namespace Simple1C.Impl.Queries 5 | { 6 | internal class ValueTableRow : DispatchObject 7 | { 8 | private readonly Dictionary columnsMap; 9 | 10 | public ValueTableRow(object comObject, Dictionary columnsMap) 11 | : base(comObject) 12 | { 13 | this.columnsMap = columnsMap; 14 | } 15 | 16 | public object this[string name] 17 | { 18 | get { return Get(columnsMap[name]); } 19 | } 20 | 21 | public new string GetString(string property) 22 | { 23 | return base.GetString(property); 24 | } 25 | 26 | public object Get(int i) 27 | { 28 | return Invoke("Get", i); 29 | } 30 | 31 | public new object ComObject() 32 | { 33 | return base.ComObject(); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /Simple1C/Impl/SimpleTypeInfo.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Impl 2 | { 3 | internal struct SimpleTypeInfo 4 | { 5 | public string typeName; 6 | public int? maxLength; 7 | } 8 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/MsSqlBulkCopyWriter.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Data; 3 | using Simple1C.Impl.Sql.SqlAccess; 4 | using Simple1C.Interface.Sql; 5 | 6 | namespace Simple1C.Impl.Sql 7 | { 8 | internal class MsSqlBulkCopyWriter : IWriter 9 | { 10 | private readonly List rows = new List(); 11 | private int filledRowsCount; 12 | private readonly MsSqlDatabase target; 13 | private readonly string tableName; 14 | private readonly bool historyMode; 15 | private readonly int batchSize; 16 | private DataColumn[] columns; 17 | 18 | public MsSqlBulkCopyWriter(MsSqlDatabase target, string tableName, 19 | bool historyMode, int batchSize) 20 | { 21 | this.target = target; 22 | this.tableName = tableName; 23 | this.historyMode = historyMode; 24 | this.batchSize = batchSize; 25 | } 26 | 27 | public void BeginWrite(DataColumn[] newColumns) 28 | { 29 | columns = newColumns; 30 | if (historyMode) 31 | { 32 | if (!target.TableExists(tableName)) 33 | target.CreateTable(tableName, newColumns); 34 | else 35 | { 36 | var existingColumns = target.GetColumns(tableName); 37 | DatabaseHelpers.CheckColumnsAreEqual(existingColumns, "existing", newColumns, "new"); 38 | } 39 | } 40 | else 41 | { 42 | if (target.TableExists(tableName)) 43 | target.DropTable("dbo." + tableName); 44 | target.CreateTable(tableName, newColumns); 45 | } 46 | } 47 | 48 | public void Write(RowAccessor row) 49 | { 50 | var currentRowIndex = filledRowsCount; 51 | object[] rowData; 52 | if (currentRowIndex < rows.Count) 53 | rowData = rows[currentRowIndex]; 54 | else 55 | rows.Add(rowData = new object[columns.Length]); 56 | row.GetValues(rowData); 57 | filledRowsCount++; 58 | if (filledRowsCount == batchSize) 59 | Flush(); 60 | } 61 | 62 | public void EndWrite() 63 | { 64 | if (filledRowsCount > 0) 65 | Flush(); 66 | } 67 | 68 | private void Flush() 69 | { 70 | var reader = new InMemoryDataReader(rows, filledRowsCount, columns.Length); 71 | target.BulkCopy(reader, tableName, columns.Length); 72 | filledRowsCount = 0; 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SchemaMapping/EnumMapping.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Impl.Sql.SchemaMapping 2 | { 3 | internal class EnumMapping 4 | { 5 | public string enumName; 6 | public string enumValueName; 7 | public int orderIndex; 8 | } 9 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SchemaMapping/IMappingSource.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Impl.Sql.SchemaMapping 2 | { 3 | internal interface IMappingSource 4 | { 5 | TableMapping ResolveTableOrNull(string queryName); 6 | } 7 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SchemaMapping/PropertyLauout.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Impl.Sql.SchemaMapping 2 | { 3 | internal enum PropertyLauout 4 | { 5 | Single, 6 | UnionReferences 7 | } 8 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SchemaMapping/PropertyMapping.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Text; 4 | using Simple1C.Impl.Helpers; 5 | 6 | namespace Simple1C.Impl.Sql.SchemaMapping 7 | { 8 | internal class PropertyMapping 9 | { 10 | public PropertyMapping(string propertyName, SingleLayout singleLayout, UnionLayout unionLayout) 11 | { 12 | PropertyName = propertyName; 13 | SingleLayout = singleLayout; 14 | UnionLayout = unionLayout; 15 | } 16 | 17 | public string Serialize() 18 | { 19 | var b = new StringBuilder(); 20 | b.Append(PropertyName); 21 | b.Append(" "); 22 | if (SingleLayout != null) 23 | { 24 | b.Append(PropertyLauout.Single); 25 | b.Append(" "); 26 | b.Append(SingleLayout.DbColumnName); 27 | b.Append(" "); 28 | b.Append(SingleLayout.NestedTableName); 29 | } 30 | else 31 | { 32 | b.Append(PropertyLauout.UnionReferences); 33 | b.Append(" "); 34 | b.Append(UnionLayout.TypeColumnName); 35 | b.Append(" "); 36 | b.Append(UnionLayout.TableIndexColumnName); 37 | b.Append(" "); 38 | b.Append(UnionLayout.ReferenceColumnName); 39 | foreach (var t in UnionLayout.NestedTables) 40 | { 41 | b.Append(" "); 42 | b.Append(t); 43 | } 44 | } 45 | return b.ToString(); 46 | } 47 | 48 | public static PropertyMapping Parse(string s) 49 | { 50 | try 51 | { 52 | var columnDesc = s.Split(new[] { " " }, StringSplitOptions.None); 53 | if (columnDesc.Length < 2) 54 | throw new InvalidOperationException(string.Format("can't parse line [{0}]", s)); 55 | var queryName = columnDesc[0]; 56 | PropertyLauout propertyLauout; 57 | if (!Enum.TryParse(columnDesc[1], out propertyLauout)) 58 | { 59 | const string messageFormat = "can't parse [{0}] from [{1}]"; 60 | throw new InvalidOperationException(string.Format(messageFormat, 61 | typeof(PropertyLauout).FormatName(), s)); 62 | } 63 | if (propertyLauout == PropertyLauout.Single) 64 | { 65 | var nestedTableName = columnDesc.Length >= 4 ? columnDesc[3] : null; 66 | var singleInfo = new SingleLayout(columnDesc[2], nestedTableName); 67 | return new PropertyMapping(queryName, singleInfo, null); 68 | } 69 | var unionInfo = new UnionLayout(columnDesc[2], 70 | columnDesc[3], columnDesc[4], 71 | columnDesc.Skip(5).ToArray()); 72 | return new PropertyMapping(queryName, null, unionInfo); 73 | } 74 | catch (Exception e) 75 | { 76 | const string messageFormat = "could not parse property mapping from [{0}]"; 77 | throw new InvalidOperationException(string.Format(messageFormat, s), e); 78 | } 79 | } 80 | 81 | public string PropertyName { get; private set; } 82 | public SingleLayout SingleLayout { get; private set; } 83 | public UnionLayout UnionLayout { get; private set; } 84 | } 85 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SchemaMapping/PropertyNames.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Impl.Sql.SchemaMapping 2 | { 3 | internal static class PropertyNames 4 | { 5 | public const string area = "ОбластьДанныхОсновныеДанные"; 6 | public const string id = "Ссылка"; 7 | } 8 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SchemaMapping/SingleLayout.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Impl.Sql.SchemaMapping 2 | { 3 | internal class SingleLayout 4 | { 5 | public SingleLayout(string dbColumnName, string nestedTableName) 6 | { 7 | DbColumnName = dbColumnName; 8 | NestedTableName = nestedTableName; 9 | } 10 | 11 | public string DbColumnName { get; private set; } 12 | public string NestedTableName { get; private set; } 13 | } 14 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SchemaMapping/TableMapping.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text.RegularExpressions; 4 | using Simple1C.Interface; 5 | 6 | namespace Simple1C.Impl.Sql.SchemaMapping 7 | { 8 | internal class TableMapping 9 | { 10 | public string QueryTableName { get; private set; } 11 | public string DbTableName { get; private set; } 12 | public int? Index { get; private set; } 13 | public TableType Type { get; private set; } 14 | public PropertyMapping[] Properties { get; private set; } 15 | private ConfigurationName? objectName; 16 | private bool objectNameParsed; 17 | 18 | public ConfigurationName? ObjectName 19 | { 20 | get 21 | { 22 | if (objectNameParsed) 23 | return objectName; 24 | objectNameParsed = true; 25 | return objectName = ConfigurationName.ParseOrNull(QueryTableName); 26 | } 27 | } 28 | 29 | private readonly Dictionary byPropertyName = 30 | new Dictionary(StringComparer.OrdinalIgnoreCase); 31 | 32 | private static readonly Regex tableIndexRegex = new Regex(@"(\d+)", 33 | RegexOptions.Compiled | RegexOptions.Singleline); 34 | 35 | public TableMapping(string queryTableName, string dbName, TableType type, PropertyMapping[] properties) 36 | { 37 | QueryTableName = queryTableName; 38 | DbTableName = dbName; 39 | Type = type; 40 | Properties = properties; 41 | var indexMatch = tableIndexRegex.Match(dbName); 42 | if (indexMatch.Success) 43 | Index = int.Parse(indexMatch.Groups[1].Value); 44 | foreach (var p in Properties) 45 | { 46 | if (byPropertyName.ContainsKey(p.PropertyName)) 47 | { 48 | const string messageFormat = "property [{0}] for table [{1}] already exist"; 49 | throw new InvalidOperationException(string.Format(messageFormat, p.PropertyName, QueryTableName)); 50 | } 51 | byPropertyName.Add(p.PropertyName, p); 52 | } 53 | } 54 | 55 | public static TableType ParseTableType(string s) 56 | { 57 | return (TableType) Enum.Parse(typeof(TableType), s); 58 | } 59 | 60 | public bool TryGetProperty(string queryName, out PropertyMapping result) 61 | { 62 | return byPropertyName.TryGetValue(queryName, out result); 63 | } 64 | 65 | public PropertyMapping GetByPropertyName(string queryName) 66 | { 67 | PropertyMapping result; 68 | if (TryGetProperty(queryName, out result)) 69 | return result; 70 | const string messagFormat = "can't find field [{0}] for table [{1}]"; 71 | throw new InvalidOperationException(string.Format(messagFormat, queryName, QueryTableName)); 72 | } 73 | 74 | public bool IsEnum() 75 | { 76 | return ObjectName.HasValue && ObjectName.Value.Scope == ConfigurationScope.Перечисления; 77 | } 78 | 79 | public static string GetMainQueryNameByTableSectionQueryName(string s) 80 | { 81 | var lastDot = s.LastIndexOf('.'); 82 | return s.Substring(0, lastDot); 83 | } 84 | } 85 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SchemaMapping/TableType.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Impl.Sql.SchemaMapping 2 | { 3 | internal enum TableType 4 | { 5 | Main, 6 | TableSection 7 | } 8 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SchemaMapping/UnionLayout.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Impl.Sql.SchemaMapping 2 | { 3 | internal class UnionLayout 4 | { 5 | public UnionLayout(string typeColumnName, string tableIndexColumnName, 6 | string referenceColumnName, string[] nestedTables) 7 | { 8 | TypeColumnName = typeColumnName; 9 | TableIndexColumnName = tableIndexColumnName; 10 | ReferenceColumnName = referenceColumnName; 11 | NestedTables = nestedTables; 12 | } 13 | 14 | public string TypeColumnName { get; private set; } 15 | public string TableIndexColumnName { get; private set; } 16 | public string ReferenceColumnName { get; private set; } 17 | public string[] NestedTables { get; private set; } 18 | } 19 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/DatabaseHelpers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data; 3 | using System.Linq; 4 | using Npgsql; 5 | using Simple1C.Impl.Helpers; 6 | 7 | namespace Simple1C.Impl.Sql.SqlAccess 8 | { 9 | internal static class DatabaseHelpers 10 | { 11 | public static DataColumn[] GetColumns(NpgsqlDataReader reader) 12 | { 13 | //reader.GetColumnSchema() на алиасы колонок в запросе забивает почему-то 14 | //reader.GetSchemaTable() какую-то хрень в ColumnSize возвращает 15 | 16 | var npgsqlColumns = reader.GetColumnSchema(); 17 | var result = new DataColumn[npgsqlColumns.Count]; 18 | for (var i = 0; i < result.Length; i++) 19 | { 20 | var c = npgsqlColumns[i]; 21 | var columnName = reader.GetName(i); 22 | if (string.IsNullOrEmpty(columnName) || columnName == "?column?") 23 | columnName = "col_" + i; 24 | result[i] = new DataColumn 25 | { 26 | ColumnName = columnName, 27 | AllowDBNull = true, 28 | DataType = c.DataTypeName == "bytea" ? typeof(byte[]) : c.DataType, 29 | MaxLength = c.ColumnSize.GetValueOrDefault(-1), 30 | }; 31 | } 32 | return result; 33 | } 34 | 35 | public static void CheckColumnsAreEqual(DataColumn[] a, string aName, DataColumn[] b, string bName) 36 | { 37 | var aFormat = FormatColumns(a); 38 | var bFormat = FormatColumns(b); 39 | if (aFormat == bFormat) 40 | return; 41 | const string messageFormat = "inconsistent columns {0}(first) and {1}(second):\r\n{2}\r\n{3}\r\n"; 42 | throw new InvalidOperationException(string.Format(messageFormat, 43 | aName, bName, aFormat, bFormat)); 44 | } 45 | 46 | private static string FormatColumns(DataColumn[] c) 47 | { 48 | return c.Select(FormatColumn).JoinStrings(","); 49 | } 50 | 51 | private static string FormatColumn(DataColumn c) 52 | { 53 | var lengthSpec = ""; 54 | if (c.DataType == typeof(string)) 55 | { 56 | var maxLength = c.MaxLength == -1 ? 1000 : c.MaxLength; 57 | lengthSpec = "[" + maxLength + "]"; 58 | } 59 | return string.Format("{0}:{1}{2}", c.ColumnName, c.DataType.FormatName(), lengthSpec); 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Parsing/ColumnReferenceTableNameResolver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Simple1C.Impl.Helpers; 5 | using Simple1C.Impl.Sql.SqlAccess.Syntax; 6 | using Simple1C.Impl.Sql.Translation; 7 | 8 | namespace Simple1C.Impl.Sql.SqlAccess.Parsing 9 | { 10 | internal class ColumnReferenceTableNameResolver : SqlVisitor 11 | { 12 | private readonly Stack contexts = new Stack(); 13 | 14 | public override SqlQuery VisitSqlQuery(SqlQuery sqlQuery) 15 | { 16 | contexts.Push(new SqlQueryContext()); 17 | var result = base.VisitSqlQuery(sqlQuery); 18 | contexts.Pop(); 19 | return result; 20 | } 21 | 22 | //todo remove copypaste 23 | public override SelectClause VisitSelect(SelectClause clause) 24 | { 25 | clause.Source = (IColumnSource) Visit(clause.Source); 26 | VisitEnumerable(clause.JoinClauses); 27 | if (clause.Fields != null) 28 | VisitEnumerable(clause.Fields); 29 | if (clause.WhereExpression != null) 30 | clause.WhereExpression = VisitWhere(clause.WhereExpression); 31 | if (clause.GroupBy != null) 32 | clause.GroupBy = VisitGroupBy(clause.GroupBy); 33 | if (clause.Having != null) 34 | clause.Having = Visit(clause.Having); 35 | return clause; 36 | } 37 | 38 | public override SubqueryTable VisitSubqueryTable(SubqueryTable subqueryTable) 39 | { 40 | var result = base.VisitSubqueryTable(subqueryTable); 41 | contexts.Peek().Register(result.Alias, result); 42 | return result; 43 | } 44 | 45 | public override ISqlElement VisitTableDeclaration(TableDeclarationClause clause) 46 | { 47 | contexts.Peek().Register(clause.GetRefName(), clause); 48 | return base.VisitTableDeclaration(clause); 49 | } 50 | 51 | public override ISqlElement VisitColumnReference(ColumnReferenceExpression expression) 52 | { 53 | var items = expression.Name.Split('.'); 54 | var possiblyAlias = items[0]; 55 | IColumnSource table; 56 | foreach (var context in contexts) 57 | if (context.TablesByName.TryGetValue(possiblyAlias, out table)) 58 | { 59 | expression.Name = items.Skip(1).JoinStrings("."); 60 | expression.Table = table; 61 | return expression; 62 | } 63 | expression.Table = contexts.Peek().LastDeclaration; 64 | return expression; 65 | } 66 | 67 | private class SqlQueryContext 68 | { 69 | //мудотня какая-то, разобрать 70 | //без алиасов соответствие колонка->таблица можно 71 | //построить только зная какие колонки есть в каждой таблице => 72 | //должно быть где-то выше, где уже есть TableMapping 73 | public IColumnSource LastDeclaration { get; set; } 74 | 75 | public Dictionary TablesByName { get; private set; } 76 | 77 | public SqlQueryContext() 78 | { 79 | TablesByName = new Dictionary(StringComparer.InvariantCultureIgnoreCase); 80 | } 81 | 82 | public void Register(string refName, IColumnSource clause) 83 | { 84 | LastDeclaration = clause; 85 | TablesByName[refName] = clause; 86 | } 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Parsing/ElementsHolder.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Simple1C.Impl.Sql.SqlAccess.Parsing 4 | { 5 | internal class ElementsHolder 6 | { 7 | public string DebugName { get; set; } 8 | public List Elements { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Parsing/Identifier.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Impl.Sql.SqlAccess.Parsing 2 | { 3 | public class Identifier 4 | { 5 | public string Value { get; set; } 6 | } 7 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Parsing/ParseHelpers.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Irony.Parsing; 3 | 4 | namespace Simple1C.Impl.Sql.SqlAccess.Parsing 5 | { 6 | internal static class ParseHelpers 7 | { 8 | public static List Elements(this ParseTreeNode n) 9 | { 10 | var result = new List(); 11 | foreach (var node in n.ChildNodes) 12 | { 13 | var holder = node.AstNode as ElementsHolder; 14 | if (holder != null) 15 | { 16 | result.AddRange(holder.Elements); 17 | continue; 18 | } 19 | if (node.AstNode != null) 20 | result.Add(node.AstNode); 21 | } 22 | return result; 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Parsing/QueryParser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Text; 4 | using Irony.Parsing; 5 | using Simple1C.Impl.Sql.SqlAccess.Syntax; 6 | 7 | namespace Simple1C.Impl.Sql.SqlAccess.Parsing 8 | { 9 | internal class QueryParser 10 | { 11 | private readonly Parser parser; 12 | 13 | public QueryParser() 14 | { 15 | var queryGrammar = new QueryGrammar(); 16 | var languageData = new LanguageData(queryGrammar); 17 | if (languageData.Errors.Count > 0) 18 | { 19 | var b = new StringBuilder(); 20 | foreach (var error in languageData.Errors) 21 | b.Append(error); 22 | throw new InvalidOperationException(string.Format("invalid grammar\r\n{0}", b)); 23 | } 24 | parser = new Parser(languageData); 25 | } 26 | 27 | public SqlQuery Parse(string source) 28 | { 29 | var parseTree = parser.Parse(source); 30 | if (parseTree.Status != ParseTreeStatus.Parsed) 31 | throw new InvalidOperationException(FormatErrors(parseTree, parser.Context.TabWidth)); 32 | var result = (SqlQuery) parseTree.Root.AstNode; 33 | new ColumnReferenceTableNameResolver().Visit(result); 34 | return result; 35 | } 36 | 37 | private static string FormatErrors(ParseTree parseTree, int tabWidth) 38 | { 39 | var b = new StringBuilder(); 40 | foreach (var message in parseTree.ParserMessages) 41 | { 42 | b.AppendLine(string.Format("{0}: {1} at {2} in state {3}", message.Level, message.Message, 43 | message.Location, message.ParserState)); 44 | 45 | var theMessage = message; 46 | var lines = parseTree.SourceText.Replace("\t", new string(' ', tabWidth)) 47 | .Split(new[] {"\r\n"}, StringSplitOptions.None) 48 | .Select((sourceLine, index) => 49 | index == theMessage.Location.Line 50 | ? string.Format("{0}\r\n{1}|<-Here", sourceLine, 51 | new string('_', theMessage.Location.Column)) 52 | : sourceLine); 53 | foreach (var line in lines) 54 | b.AppendLine(line); 55 | } 56 | return string.Format("parse errors\r\n:{0}", b); 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Syntax/AggregateFunctionExpression.cs: -------------------------------------------------------------------------------- 1 | using Simple1C.Impl.Sql.Translation; 2 | 3 | namespace Simple1C.Impl.Sql.SqlAccess.Syntax 4 | { 5 | internal class AggregateFunctionExpression : ISqlElement 6 | { 7 | public AggregationFunction Function { get; set; } 8 | public ISqlElement Argument { get; set; } 9 | public bool IsSelectAll { get; set; } 10 | public bool IsDistinct { get; set; } 11 | 12 | public ISqlElement Accept(SqlVisitor visitor) 13 | { 14 | return visitor.VisitAggregateFunction(this); 15 | } 16 | 17 | public override string ToString() 18 | { 19 | return string.Format("{0}. {1}({2}{3})", typeof(AggregateFunctionExpression).Name, 20 | Function, IsDistinct ? "distinct " : "", IsSelectAll ? "*" : Argument.ToString()); 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Syntax/AggregationFunction.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Impl.Sql.SqlAccess.Syntax 2 | { 3 | internal enum AggregationFunction 4 | { 5 | Sum, 6 | Count, 7 | Min, 8 | Max, 9 | Avg 10 | } 11 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Syntax/AndExpression.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Impl.Sql.SqlAccess.Syntax 2 | { 3 | internal class AndExpression : BinaryExpression 4 | { 5 | public AndExpression() : base(SqlBinaryOperator.And) 6 | { 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Syntax/BinaryExpression.cs: -------------------------------------------------------------------------------- 1 | using Simple1C.Impl.Sql.Translation; 2 | 3 | namespace Simple1C.Impl.Sql.SqlAccess.Syntax 4 | { 5 | internal class BinaryExpression : ISqlElement 6 | { 7 | public SqlBinaryOperator Operator { get; private set; } 8 | public ISqlElement Left { get; set; } 9 | public ISqlElement Right { get; set; } 10 | 11 | public BinaryExpression(SqlBinaryOperator op) 12 | { 13 | Operator = op; 14 | } 15 | 16 | public ISqlElement Accept(SqlVisitor visitor) 17 | { 18 | return visitor.VisitBinary(this); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Syntax/CaseElement.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Impl.Sql.SqlAccess.Syntax 2 | { 3 | internal class CaseElement 4 | { 5 | public ISqlElement Condition { get; set; } 6 | public ISqlElement Value { get; set; } 7 | } 8 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Syntax/CaseExpression.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Simple1C.Impl.Sql.Translation; 3 | 4 | namespace Simple1C.Impl.Sql.SqlAccess.Syntax 5 | { 6 | internal class CaseExpression : ISqlElement 7 | { 8 | public List Elements { get; set; } 9 | public ISqlElement DefaultValue { get; set; } 10 | 11 | public CaseExpression() 12 | { 13 | Elements = new List(); 14 | } 15 | 16 | public ISqlElement Accept(SqlVisitor visitor) 17 | { 18 | return visitor.VisitCase(this); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Syntax/CastExpression.cs: -------------------------------------------------------------------------------- 1 | using Simple1C.Impl.Sql.Translation; 2 | 3 | namespace Simple1C.Impl.Sql.SqlAccess.Syntax 4 | { 5 | internal class CastExpression : ISqlElement 6 | { 7 | public string Type { get; set; } 8 | public ISqlElement Expression { get; set; } 9 | 10 | public ISqlElement Accept(SqlVisitor visitor) 11 | { 12 | return visitor.VisitCast(this); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Syntax/ColumnReferenceExpression.cs: -------------------------------------------------------------------------------- 1 | using Simple1C.Impl.Sql.Translation; 2 | 3 | namespace Simple1C.Impl.Sql.SqlAccess.Syntax 4 | { 5 | internal class ColumnReferenceExpression : ISqlElement 6 | { 7 | public string Name { get; set; } 8 | public IColumnSource Table { get; set; } 9 | 10 | public ISqlElement Accept(SqlVisitor visitor) 11 | { 12 | return visitor.VisitColumnReference(this); 13 | } 14 | 15 | public override string ToString() 16 | { 17 | return string.Format("{0}. Name: {1}, Table: {2}", typeof(ColumnReferenceExpression).Name, Name, Table); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Syntax/DatePart.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Impl.Sql.SqlAccess.Syntax 2 | { 3 | public enum DatePart 4 | { 5 | Year, 6 | Quarter, 7 | Month, 8 | Week, 9 | Day, 10 | Hour, 11 | Minute 12 | } 13 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Syntax/EqualityExpression.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Impl.Sql.SqlAccess.Syntax 2 | { 3 | internal class EqualityExpression : BinaryExpression 4 | { 5 | public EqualityExpression() : base(SqlBinaryOperator.Eq) 6 | { 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Syntax/GroupByClause.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Simple1C.Impl.Sql.Translation; 3 | 4 | namespace Simple1C.Impl.Sql.SqlAccess.Syntax 5 | { 6 | internal class GroupByClause : ISqlElement 7 | { 8 | public List Expressions { get; set; } 9 | 10 | public ISqlElement Accept(SqlVisitor visitor) 11 | { 12 | return visitor.VisitGroupBy(this); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Syntax/IColumnSource.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Impl.Sql.SqlAccess.Syntax 2 | { 3 | internal interface IColumnSource : ISqlElement 4 | { 5 | string Alias { get; } 6 | } 7 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Syntax/ISqlElement.cs: -------------------------------------------------------------------------------- 1 | using Simple1C.Impl.Sql.Translation; 2 | 3 | namespace Simple1C.Impl.Sql.SqlAccess.Syntax 4 | { 5 | internal interface ISqlElement 6 | { 7 | ISqlElement Accept(SqlVisitor visitor); 8 | } 9 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Syntax/InExpression.cs: -------------------------------------------------------------------------------- 1 | using Simple1C.Impl.Sql.Translation; 2 | 3 | namespace Simple1C.Impl.Sql.SqlAccess.Syntax 4 | { 5 | internal class InExpression : ISqlElement 6 | { 7 | public ColumnReferenceExpression Column { get; set; } 8 | public ISqlElement Source { get; set; } 9 | 10 | public ISqlElement Accept(SqlVisitor visitor) 11 | { 12 | return visitor.VisitIn(this); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Syntax/IsNullExpression.cs: -------------------------------------------------------------------------------- 1 | using Simple1C.Impl.Sql.Translation; 2 | 3 | namespace Simple1C.Impl.Sql.SqlAccess.Syntax 4 | { 5 | internal class IsNullExpression : ISqlElement 6 | { 7 | public ISqlElement Argument { get; set; } 8 | public bool IsNotNull { get; set; } 9 | 10 | public ISqlElement Accept(SqlVisitor visitor) 11 | { 12 | return visitor.VisitIsNullExpression(this); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Syntax/IsReferenceExpression.cs: -------------------------------------------------------------------------------- 1 | using Simple1C.Impl.Sql.Translation; 2 | 3 | namespace Simple1C.Impl.Sql.SqlAccess.Syntax 4 | { 5 | internal class IsReferenceExpression : ISqlElement 6 | { 7 | public ColumnReferenceExpression Argument { get; set; } 8 | public string ObjectName { get; set; } 9 | 10 | public ISqlElement Accept(SqlVisitor visitor) 11 | { 12 | return visitor.VisitIsReference(this); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Syntax/JoinClause.cs: -------------------------------------------------------------------------------- 1 | using Simple1C.Impl.Sql.Translation; 2 | 3 | namespace Simple1C.Impl.Sql.SqlAccess.Syntax 4 | { 5 | internal class JoinClause : ISqlElement 6 | { 7 | public IColumnSource Source { get; set; } 8 | public JoinKind JoinKind { get; set; } 9 | public ISqlElement Condition { get; set; } 10 | 11 | public ISqlElement Accept(SqlVisitor visitor) 12 | { 13 | return visitor.VisitJoin(this); 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Syntax/JoinKind.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Impl.Sql.SqlAccess.Syntax 2 | { 3 | internal enum JoinKind 4 | { 5 | Left, 6 | Right, 7 | Inner, 8 | Full 9 | } 10 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Syntax/KnownQueryFunction.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Impl.Sql.SqlAccess.Syntax 2 | { 3 | internal enum KnownQueryFunction 4 | { 5 | Presentation, 6 | DateTime, 7 | Year, 8 | Quarter, 9 | SqlDatePart, 10 | SqlDateTrunc, 11 | SqlNot, 12 | IsNull, 13 | Substring 14 | } 15 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Syntax/ListExpression.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Simple1C.Impl.Helpers; 3 | using Simple1C.Impl.Sql.Translation; 4 | 5 | namespace Simple1C.Impl.Sql.SqlAccess.Syntax 6 | { 7 | internal class ListExpression : ISqlElement 8 | { 9 | public ListExpression() 10 | { 11 | Elements = new List(); 12 | } 13 | 14 | public List Elements { get; set; } 15 | 16 | public ISqlElement Accept(SqlVisitor visitor) 17 | { 18 | return visitor.VisitList(this); 19 | } 20 | 21 | public override string ToString() 22 | { 23 | return string.Format("{0}. ({1})", Elements.JoinStrings(","), typeof(ListExpression)); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Syntax/LiteralExpression.cs: -------------------------------------------------------------------------------- 1 | using Simple1C.Impl.Sql.Translation; 2 | 3 | namespace Simple1C.Impl.Sql.SqlAccess.Syntax 4 | { 5 | internal class LiteralExpression : ISqlElement 6 | { 7 | public object Value { get; set; } 8 | public SqlType? SqlType { get; set; } 9 | 10 | public ISqlElement Accept(SqlVisitor visitor) 11 | { 12 | return visitor.VisitLiteral(this); 13 | } 14 | 15 | public override string ToString() 16 | { 17 | return string.Format("{0} Value: [{1}], SqlType: [{2}]", 18 | typeof(LiteralExpression).Name, Value, SqlType); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Syntax/OperatorPrecedenceAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Simple1C.Impl.Sql.SqlAccess.Syntax 4 | { 5 | public class OperatorPrecedenceAttribute : Attribute 6 | { 7 | public OperatorPrecedenceAttribute(int precedence) 8 | { 9 | Precedence = precedence; 10 | } 11 | 12 | public int Precedence { get; private set; } 13 | } 14 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Syntax/OperatorSynonymsAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Simple1C.Impl.Sql.SqlAccess.Syntax 4 | { 5 | public class OperatorSynonymsAttribute : Attribute 6 | { 7 | public OperatorSynonymsAttribute(params string[] synonyms) 8 | { 9 | Synonyms = synonyms; 10 | } 11 | 12 | public string[] Synonyms { get; private set; } 13 | } 14 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Syntax/OrderByClause.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Simple1C.Impl.Sql.Translation; 3 | 4 | namespace Simple1C.Impl.Sql.SqlAccess.Syntax 5 | { 6 | internal class OrderByClause : ISqlElement 7 | { 8 | public List Expressions { get; set; } 9 | 10 | public ISqlElement Accept(SqlVisitor visitor) 11 | { 12 | return visitor.VisitOrderBy(this); 13 | } 14 | 15 | public class OrderingElement : ISqlElement 16 | { 17 | public ISqlElement Expression { get; set; } 18 | public bool IsAsc { get; set; } 19 | 20 | public ISqlElement Accept(SqlVisitor visitor) 21 | { 22 | return visitor.VisitOrderingElement(this); 23 | } 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Syntax/ParameterExpression.cs: -------------------------------------------------------------------------------- 1 | using Simple1C.Impl.Sql.Translation; 2 | 3 | namespace Simple1C.Impl.Sql.SqlAccess.Syntax 4 | { 5 | internal class ParameterExpression : ISqlElement 6 | { 7 | public string Name { get; set; } 8 | 9 | public ISqlElement Accept(SqlVisitor visitor) 10 | { 11 | return visitor.VisitParameter(this); 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Syntax/QueryFunctionExpression.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Simple1C.Impl.Helpers; 3 | using Simple1C.Impl.Sql.Translation; 4 | 5 | namespace Simple1C.Impl.Sql.SqlAccess.Syntax 6 | { 7 | internal class QueryFunctionExpression : ISqlElement 8 | { 9 | public QueryFunctionExpression() 10 | { 11 | Arguments = new List(); 12 | } 13 | 14 | public string CustomFunction { get; set; } 15 | public KnownQueryFunction? KnownFunction { get; set; } 16 | public List Arguments { get; set; } 17 | 18 | public ISqlElement Accept(SqlVisitor visitor) 19 | { 20 | return visitor.VisitQueryFunction(this); 21 | } 22 | 23 | public override string ToString() 24 | { 25 | return string.Format("{0}. {1}({2})", typeof (QueryFunctionExpression).Name, KnownFunction, Arguments.JoinStrings(",")); 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Syntax/SelectClause.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Simple1C.Impl.Sql.Translation; 3 | 4 | namespace Simple1C.Impl.Sql.SqlAccess.Syntax 5 | { 6 | internal class SelectClause : ISqlElement 7 | { 8 | public SelectClause() 9 | { 10 | JoinClauses = new List(); 11 | Fields = new List(); 12 | } 13 | 14 | public bool IsSelectAll { get; set; } 15 | public bool IsDistinct { get; set; } 16 | public int? Top { get; set; } 17 | public List Fields { get; set; } 18 | public IColumnSource Source { get; set; } 19 | public ISqlElement WhereExpression { get; set; } 20 | public List JoinClauses { get; private set; } 21 | public GroupByClause GroupBy { get; set; } 22 | public ISqlElement Having { get; set; } 23 | 24 | public ISqlElement Accept(SqlVisitor visitor) 25 | { 26 | return visitor.VisitSelect(this); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Syntax/SelectFieldExpression.cs: -------------------------------------------------------------------------------- 1 | using Simple1C.Impl.Sql.Translation; 2 | 3 | namespace Simple1C.Impl.Sql.SqlAccess.Syntax 4 | { 5 | internal class SelectFieldExpression : ISqlElement 6 | { 7 | public ISqlElement Expression { get; set; } 8 | public string Alias { get; set; } 9 | 10 | public ISqlElement Accept(SqlVisitor visitor) 11 | { 12 | return visitor.VisitSelectField(this); 13 | } 14 | 15 | public override string ToString() 16 | { 17 | return string.Format("{0}. {1} as {2}", typeof(SelectFieldExpression).Name, Expression, Alias); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Syntax/SqlBinaryOperator.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Impl.Sql.SqlAccess.Syntax 2 | { 3 | internal enum SqlBinaryOperator 4 | { 5 | [OperatorSynonyms("*")] [OperatorPrecedence(10)] Mult, 6 | [OperatorSynonyms("/")] [OperatorPrecedence(10)] Div, 7 | [OperatorSynonyms("%")] [OperatorPrecedence(10)] Remainder, 8 | [OperatorSynonyms("+")] [OperatorPrecedence(9)] Plus, 9 | [OperatorSynonyms("-")] [OperatorPrecedence(9)] Minus, 10 | [OperatorSynonyms("=")] [OperatorPrecedence(8)] Eq, 11 | [OperatorSynonyms("<>", "!=")] [OperatorPrecedence(8)] Neq, 12 | [OperatorSynonyms("<")] [OperatorPrecedence(8)] LessThan, 13 | [OperatorSynonyms("<=")] [OperatorPrecedence(8)] LessThanOrEqual, 14 | [OperatorSynonyms(">")] [OperatorPrecedence(8)] GreaterThan, 15 | [OperatorSynonyms(">=")] [OperatorPrecedence(8)] GreaterThanOrEqual, 16 | [OperatorSynonyms("LIKE", "ПОДОБНО")] [OperatorPrecedence(8)] Like, 17 | [OperatorSynonyms("И", "AND")] [OperatorPrecedence(5)] And, 18 | [OperatorSynonyms("ИЛИ", "OR")] [OperatorPrecedence(4)] Or 19 | } 20 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Syntax/SqlQuery.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Simple1C.Impl.Helpers; 5 | using Simple1C.Impl.Sql.Translation; 6 | 7 | namespace Simple1C.Impl.Sql.SqlAccess.Syntax 8 | { 9 | internal class SqlQuery : ISqlElement 10 | { 11 | public SqlQuery() 12 | { 13 | Unions = new List(); 14 | } 15 | 16 | public List Unions { get; set; } 17 | public OrderByClause OrderBy { get; set; } 18 | 19 | public ISqlElement Accept(SqlVisitor visitor) 20 | { 21 | return visitor.VisitSqlQuery(this); 22 | } 23 | 24 | public override string ToString() 25 | { 26 | return string.Format("{0}.{1} ORDER BY {2}", typeof(SqlQuery).Name, Unions.JoinStrings(" "), OrderBy); 27 | } 28 | 29 | public SelectClause GetSingleSelect() 30 | { 31 | var union = Unions.Single(); 32 | if (union.Type.HasValue) 33 | throw new InvalidOperationException("Assertion failure. Expected single select without unions"); 34 | return union.SelectClause; 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Syntax/SqlType.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Impl.Sql.SqlAccess.Syntax 2 | { 3 | internal enum SqlType 4 | { 5 | DatePart, 6 | ByteArray 7 | } 8 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Syntax/SubqueryClause.cs: -------------------------------------------------------------------------------- 1 | using Simple1C.Impl.Sql.Translation; 2 | 3 | namespace Simple1C.Impl.Sql.SqlAccess.Syntax 4 | { 5 | internal class SubqueryClause : ISqlElement 6 | { 7 | public SqlQuery Query { get; set; } 8 | 9 | public ISqlElement Accept(SqlVisitor visitor) 10 | { 11 | return visitor.VisitSubquery(this); 12 | } 13 | 14 | public override string ToString() 15 | { 16 | return string.Format("{0}. ({1})", typeof (SubqueryClause), Query); 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Syntax/SubqueryTable.cs: -------------------------------------------------------------------------------- 1 | using Simple1C.Impl.Sql.Translation; 2 | 3 | namespace Simple1C.Impl.Sql.SqlAccess.Syntax 4 | { 5 | internal class SubqueryTable : IColumnSource 6 | { 7 | public SubqueryClause Query { get; set; } 8 | public string Alias { get; set; } 9 | 10 | public ISqlElement Accept(SqlVisitor visitor) 11 | { 12 | return visitor.VisitSubqueryTable(this); 13 | } 14 | 15 | public override string ToString() 16 | { 17 | return string.Format("{0}. ({1}) as {2}",typeof(SubqueryTable).Name, Query, Alias); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Syntax/TableDeclarationClause.cs: -------------------------------------------------------------------------------- 1 | using Simple1C.Impl.Sql.Translation; 2 | 3 | namespace Simple1C.Impl.Sql.SqlAccess.Syntax 4 | { 5 | internal class TableDeclarationClause : IColumnSource 6 | { 7 | public string Name { get; set; } 8 | public string Alias { get; set; } 9 | 10 | public string GetRefName() 11 | { 12 | return Alias ?? Name; 13 | } 14 | 15 | public ISqlElement Accept(SqlVisitor visitor) 16 | { 17 | return visitor.VisitTableDeclaration(this); 18 | } 19 | 20 | public override string ToString() 21 | { 22 | return string.Format("{0} Name: [{1}], Alias: [{2}]", typeof(TableDeclarationClause).Name, Name, Alias); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Syntax/UnaryExpression.cs: -------------------------------------------------------------------------------- 1 | using Simple1C.Impl.Sql.Translation; 2 | 3 | namespace Simple1C.Impl.Sql.SqlAccess.Syntax 4 | { 5 | internal class UnaryExpression : ISqlElement 6 | { 7 | public ISqlElement Argument { get; set; } 8 | public UnaryOperator Operator { get; set; } 9 | 10 | public ISqlElement Accept(SqlVisitor visitor) 11 | { 12 | return visitor.VisitUnary(this); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Syntax/UnaryOperator.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Impl.Sql.SqlAccess.Syntax 2 | { 3 | internal enum UnaryOperator 4 | { 5 | [OperatorSynonyms("НЕ", "NOT")] [OperatorPrecedence(6)] Not, 6 | [OperatorSynonyms("-")] [OperatorPrecedence(11)] Negation 7 | } 8 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Syntax/UnionClause.cs: -------------------------------------------------------------------------------- 1 | using Simple1C.Impl.Sql.Translation; 2 | 3 | namespace Simple1C.Impl.Sql.SqlAccess.Syntax 4 | { 5 | internal class UnionClause : ISqlElement 6 | { 7 | public SelectClause SelectClause { get; set; } 8 | public UnionType? Type { get; set; } 9 | 10 | public ISqlElement Accept(SqlVisitor visitor) 11 | { 12 | return visitor.VisitUnion(this); 13 | } 14 | 15 | public override string ToString() 16 | { 17 | return string.Format("{0} {1}", SelectClause, Type == null ? "" : Type.ToString()); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Syntax/UnionType.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Impl.Sql.SqlAccess.Syntax 2 | { 3 | internal enum UnionType 4 | { 5 | Distinct, 6 | All 7 | } 8 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/SqlAccess/Syntax/ValueLiteralExpression.cs: -------------------------------------------------------------------------------- 1 | using Simple1C.Impl.Sql.Translation; 2 | 3 | namespace Simple1C.Impl.Sql.SqlAccess.Syntax 4 | { 5 | internal class ValueLiteralExpression : ISqlElement 6 | { 7 | public string Value { get; set; } 8 | 9 | public ISqlElement Accept(SqlVisitor visitor) 10 | { 11 | return visitor.VisitValueLiteral(this); 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/Translation/QueryEntities/NameGenerator.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Simple1C.Impl.Sql.Translation.QueryEntities 4 | { 5 | internal class NameGenerator 6 | { 7 | private readonly Dictionary lastUsed = new Dictionary(); 8 | 9 | public string GenerateTableName() 10 | { 11 | return Generate("__nested_table"); 12 | } 13 | 14 | public string GenerateSubqueryName() 15 | { 16 | return Generate("__subquery"); 17 | } 18 | 19 | public string GenerateColumnName() 20 | { 21 | return Generate("__nested_field"); 22 | } 23 | 24 | private string Generate(string prefix) 25 | { 26 | int lastUsedForPrefix; 27 | var number = 28 | lastUsed[prefix] = lastUsed.TryGetValue(prefix, out lastUsedForPrefix) ? lastUsedForPrefix + 1 : 0; 29 | return prefix + number; 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/Translation/QueryEntities/QueryEntity.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Simple1C.Impl.Sql.SchemaMapping; 3 | using Simple1C.Impl.Sql.SqlAccess.Syntax; 4 | 5 | namespace Simple1C.Impl.Sql.Translation.QueryEntities 6 | { 7 | internal class QueryEntity 8 | { 9 | public QueryEntity(TableMapping mapping, QueryEntityProperty referer) 10 | { 11 | this.mapping = mapping; 12 | this.referer = referer; 13 | } 14 | 15 | public readonly TableMapping mapping; 16 | public readonly QueryEntityProperty referer; 17 | public readonly List properties = new List(); 18 | 19 | public ISqlElement unionCondition; 20 | public TableDeclarationClause declaration; 21 | 22 | public string GetAreaColumnName() 23 | { 24 | return GetSingleColumnName(PropertyNames.area); 25 | } 26 | 27 | public string GetIdColumnName() 28 | { 29 | return GetSingleColumnName(PropertyNames.id); 30 | } 31 | 32 | public string GetSingleColumnName(string propertyName) 33 | { 34 | return mapping.GetByPropertyName(propertyName).SingleLayout.DbColumnName; 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/Translation/QueryEntities/QueryEntityProperty.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Simple1C.Impl.Sql.SchemaMapping; 4 | 5 | namespace Simple1C.Impl.Sql.Translation.QueryEntities 6 | { 7 | internal class QueryEntityProperty 8 | { 9 | public readonly QueryEntity referer; 10 | public readonly PropertyMapping mapping; 11 | public readonly List nestedEntities = new List(); 12 | public bool referenced; 13 | 14 | public QueryEntityProperty(QueryEntity referer, PropertyMapping mapping) 15 | { 16 | this.referer = referer; 17 | this.mapping = mapping; 18 | } 19 | 20 | public string GetDbColumnName() 21 | { 22 | var result = mapping.SingleLayout != null 23 | ? mapping.SingleLayout.DbColumnName 24 | : mapping.UnionLayout.ReferenceColumnName; 25 | if (string.IsNullOrEmpty(result)) 26 | { 27 | const string messageFormat = "ref column is not defined for [{0}.{1}]"; 28 | throw new InvalidOperationException(string.Format(messageFormat, 29 | referer.mapping.QueryTableName, mapping.PropertyName)); 30 | } 31 | return result; 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/Translation/QueryEntities/QueryEntityRegistry.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Simple1C.Impl.Sql.SchemaMapping; 5 | using Simple1C.Impl.Sql.SqlAccess.Syntax; 6 | 7 | namespace Simple1C.Impl.Sql.Translation.QueryEntities 8 | { 9 | internal class QueryEntityRegistry 10 | { 11 | private readonly Dictionary queryTables = 12 | new Dictionary(); 13 | 14 | private readonly IMappingSource mappingSource; 15 | 16 | public QueryEntityRegistry(IMappingSource mappingSource) 17 | { 18 | this.mappingSource = mappingSource; 19 | } 20 | 21 | public void RegisterTable(TableDeclarationClause declaration) 22 | { 23 | QueryRoot queryRoot; 24 | if (queryTables.TryGetValue(declaration, out queryRoot)) 25 | return; 26 | var queryEntity = CreateQueryEntity(null, declaration.Name); 27 | queryRoot = new QueryRoot(queryEntity, declaration); 28 | queryTables.Add(declaration, queryRoot); 29 | } 30 | 31 | public void RegisterSubquery(SubqueryTable clause) 32 | { 33 | QueryRoot queryRoot; 34 | if (queryTables.TryGetValue(clause, out queryRoot)) 35 | return; 36 | var subqueryProperties = CreateSubqueryProperties(clause.Query.Query.Unions.First().SelectClause); 37 | var mapping = new TableMapping(clause.Alias, clause.Alias, TableType.Main, subqueryProperties); 38 | var queryEntity = new QueryEntity(mapping, null); 39 | queryRoot = new QueryRoot(queryEntity, clause); 40 | queryTables.Add(clause, queryRoot); 41 | } 42 | 43 | public QueryRoot Get(IColumnSource declaration) 44 | { 45 | QueryRoot root; 46 | if (!queryTables.TryGetValue(declaration, out root)) 47 | { 48 | const string messageFormat = "can't find query table for [{0}]"; 49 | throw new InvalidOperationException(string.Format(messageFormat, declaration)); 50 | } 51 | return root; 52 | } 53 | 54 | public QueryEntity CreateQueryEntity(QueryEntityProperty referer, string queryName) 55 | { 56 | var tableMapping = mappingSource.ResolveTableOrNull(queryName); 57 | if (tableMapping == null) 58 | { 59 | const string messageFormat = "can't find table mapping for [{0}]"; 60 | throw new InvalidOperationException(string.Format(messageFormat, queryName)); 61 | } 62 | return new QueryEntity(tableMapping, referer); 63 | } 64 | 65 | private PropertyMapping[] CreateSubqueryProperties(SelectClause clause) 66 | { 67 | if (clause.IsSelectAll) 68 | return Get(clause.Source).entity.mapping.Properties; 69 | return clause.Fields.Select(c => 70 | { 71 | if (!string.IsNullOrEmpty(c.Alias)) 72 | return new PropertyMapping(c.Alias, new SingleLayout(c.Alias, null), null); 73 | var columnReference = ExtractColumnReferenceOrDie(c); 74 | return Get(columnReference.Table).entity.mapping.GetByPropertyName(columnReference.Name); 75 | }).ToArray(); 76 | } 77 | 78 | private static ColumnReferenceExpression ExtractColumnReferenceOrDie(SelectFieldExpression c) 79 | { 80 | var result = c.Expression as ColumnReferenceExpression; 81 | if (result == null) 82 | { 83 | const string messageFormat = "could not determine subquery property name from expression [{0}]"; 84 | throw new NotSupportedException(string.Format(messageFormat, c.Expression)); 85 | } 86 | return result; 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/Translation/QueryEntities/QueryField.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Simple1C.Impl.Sql.Translation.QueryEntities 4 | { 5 | internal class QueryField 6 | { 7 | public readonly string alias; 8 | public readonly QueryEntityProperty[] properties; 9 | public readonly bool invert; 10 | public readonly List parts = new List(); 11 | 12 | public QueryField(string alias, QueryEntityProperty[] properties, bool invert) 13 | { 14 | this.alias = alias; 15 | this.properties = properties; 16 | this.invert = invert; 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/Translation/QueryEntities/QueryRoot.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Simple1C.Impl.Sql.SqlAccess.Syntax; 4 | 5 | namespace Simple1C.Impl.Sql.Translation.QueryEntities 6 | { 7 | internal class QueryRoot 8 | { 9 | public readonly QueryEntity entity; 10 | public readonly IColumnSource tableDeclaration; 11 | 12 | public readonly Dictionary fields = 13 | new Dictionary(StringComparer.OrdinalIgnoreCase); 14 | 15 | public List additionalFields; 16 | 17 | public bool subqueryRequired; 18 | 19 | public QueryRoot(QueryEntity entity, IColumnSource tableDeclaration) 20 | { 21 | this.entity = entity; 22 | this.tableDeclaration = tableDeclaration; 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/Translation/QueryEntities/SelectPart.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Impl.Sql.Translation.QueryEntities 2 | { 3 | internal enum SelectPart 4 | { 5 | Select, 6 | GroupBy, 7 | Other 8 | } 9 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/Translation/SqlHelpers.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using Simple1C.Impl.Sql.SqlAccess.Syntax; 4 | 5 | namespace Simple1C.Impl.Sql.Translation 6 | { 7 | internal static class SqlHelpers 8 | { 9 | public static ISqlElement Combine(this List items) 10 | { 11 | return items.Aggregate((left, right) => new AndExpression 12 | { 13 | Left = left, 14 | Right = right 15 | }); 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/Translation/Visitors/AddAreaToJoinConditionVisitor.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Simple1C.Impl.Sql.SchemaMapping; 3 | using Simple1C.Impl.Sql.SqlAccess.Syntax; 4 | 5 | namespace Simple1C.Impl.Sql.Translation.Visitors 6 | { 7 | internal class AddAreaToJoinConditionVisitor : SqlVisitor 8 | { 9 | private readonly Stack contexts = new Stack(); 10 | 11 | public override JoinClause VisitJoin(JoinClause clause) 12 | { 13 | var currentContext = contexts.Peek(); 14 | if (currentContext == null || currentContext.MainTable == null || !(clause.Source is TableDeclarationClause)) 15 | return base.VisitJoin(clause); 16 | 17 | clause.Condition = new AndExpression 18 | { 19 | Left = new EqualityExpression 20 | { 21 | Left = new ColumnReferenceExpression 22 | { 23 | Name = PropertyNames.area, 24 | Table = currentContext.MainTable 25 | }, 26 | Right = new ColumnReferenceExpression 27 | { 28 | Name = PropertyNames.area, 29 | Table = clause.Source 30 | } 31 | }, 32 | Right = clause.Condition 33 | }; 34 | return base.VisitJoin(clause); 35 | } 36 | 37 | public override ISqlElement VisitTableDeclaration(TableDeclarationClause clause) 38 | { 39 | contexts.Peek().MainTable = clause; 40 | return base.VisitTableDeclaration(clause); 41 | } 42 | 43 | public override SubqueryTable VisitSubqueryTable(SubqueryTable subqueryTable) 44 | { 45 | contexts.Peek().MainTable = null; 46 | return base.VisitSubqueryTable(subqueryTable); 47 | } 48 | 49 | public override SqlQuery VisitSqlQuery(SqlQuery sqlQuery) 50 | { 51 | contexts.Push(new Context()); 52 | var result = base.VisitSqlQuery(sqlQuery); 53 | contexts.Pop(); 54 | return result; 55 | } 56 | 57 | private class Context 58 | { 59 | public TableDeclarationClause MainTable { get; set; } 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/Translation/Visitors/DeduceEntityTypeFromIsReferenceExpressionVisitor.cs: -------------------------------------------------------------------------------- 1 | using Simple1C.Impl.Helpers; 2 | using Simple1C.Impl.Sql.SqlAccess.Syntax; 3 | using Simple1C.Impl.Sql.Translation.QueryEntities; 4 | 5 | namespace Simple1C.Impl.Sql.Translation.Visitors 6 | { 7 | internal class DeduceEntityTypeFromIsReferenceExpressionVisitor : SqlVisitor 8 | { 9 | private readonly QueryEntityTree queryEntityTree; 10 | 11 | public DeduceEntityTypeFromIsReferenceExpressionVisitor(QueryEntityTree queryEntityTree) 12 | { 13 | this.queryEntityTree = queryEntityTree; 14 | } 15 | 16 | public override SelectClause VisitSelect(SelectClause clause) 17 | { 18 | var result = base.VisitSelect(clause); 19 | VisitCondition(result.WhereExpression); 20 | return result; 21 | } 22 | 23 | private void VisitCondition(ISqlElement sqlElement) 24 | { 25 | if (sqlElement == null) 26 | return; 27 | var isReference = sqlElement as IsReferenceExpression; 28 | if (isReference != null) 29 | { 30 | SetPropertyType(isReference.Argument, isReference.ObjectName); 31 | return; 32 | } 33 | var andExpression = sqlElement as AndExpression; 34 | if (andExpression != null) 35 | { 36 | VisitCondition(andExpression.Left); 37 | VisitCondition(andExpression.Right); 38 | } 39 | } 40 | 41 | private void SetPropertyType(ColumnReferenceExpression columnReference, string name) 42 | { 43 | var queryRoot = queryEntityTree.Get(columnReference.Table); 44 | var propertyNames = columnReference.Name.Split('.'); 45 | var referencedProperties = queryEntityTree.GetProperties(queryRoot, propertyNames); 46 | foreach (var property in referencedProperties) 47 | property.nestedEntities.RemoveAll(entity => !entity.mapping.QueryTableName.EqualsIgnoringCase(name)); 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/Translation/Visitors/GenericVisitor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Simple1C.Impl.Sql.SqlAccess.Syntax; 3 | using Simple1C.Impl.Sql.Translation; 4 | 5 | internal class GenericVisitor : SqlVisitor 6 | where T: class, ISqlElement 7 | { 8 | private readonly Func visit; 9 | 10 | public GenericVisitor(Func visit) 11 | { 12 | this.visit = visit; 13 | } 14 | 15 | public override ISqlElement Visit(ISqlElement element) 16 | { 17 | var sqlElement = base.Visit(element); 18 | var typedElement = element as T; 19 | if (typedElement != null) 20 | return visit(typedElement); 21 | return sqlElement; 22 | } 23 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/Translation/Visitors/IsReferenceExpressionRewriter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Simple1C.Impl.Helpers; 5 | using Simple1C.Impl.Sql.SqlAccess.Syntax; 6 | using Simple1C.Impl.Sql.Translation.QueryEntities; 7 | 8 | namespace Simple1C.Impl.Sql.Translation.Visitors 9 | { 10 | internal class IsReferenceExpressionRewriter : SqlVisitor 11 | { 12 | private readonly QueryEntityTree queryEntityTree; 13 | private readonly NameGenerator nameGenerator; 14 | private readonly HashSet rewritten; 15 | 16 | public IsReferenceExpressionRewriter(QueryEntityTree queryEntityTree, 17 | NameGenerator nameGenerator, HashSet rewritten) 18 | { 19 | this.queryEntityTree = queryEntityTree; 20 | this.nameGenerator = nameGenerator; 21 | this.rewritten = rewritten; 22 | } 23 | 24 | public override ISqlElement VisitIsReference(IsReferenceExpression expression) 25 | { 26 | var queryRoot = queryEntityTree.Get(expression.Argument.Table); 27 | var propertyNames = expression.Argument.Name.Split('.'); 28 | var referencedProperties = queryEntityTree.GetProperties(queryRoot, propertyNames); 29 | if (referencedProperties.Count != 1) 30 | { 31 | const string messageFormat = "operator IsReference property [{0}] has many " + 32 | "variants which is not supported currently"; 33 | throw new InvalidOperationException(string.Format(messageFormat, 34 | expression.Argument.Name)); 35 | } 36 | var property = referencedProperties[0]; 37 | var entity = property.nestedEntities.SingleOrDefault(x => x.mapping.QueryTableName.EqualsIgnoringCase(expression.ObjectName)); 38 | if (entity == null) 39 | { 40 | const string messageFormat = "can't find entity [{0}] for property [{1}]"; 41 | throw new InvalidOperationException(string.Format(messageFormat, 42 | expression.ObjectName, expression.Argument.Name)); 43 | } 44 | var unionCondition = queryEntityTree.GetUnionCondition(property, entity); 45 | if (unionCondition == null) 46 | { 47 | const string messageFormat = "property [{0}] has only one possible type"; 48 | throw new InvalidOperationException(string.Format(messageFormat, 49 | expression.Argument.Name)); 50 | } 51 | if (queryRoot.additionalFields == null) 52 | queryRoot.additionalFields = new List(); 53 | var filterColumnName = nameGenerator.GenerateColumnName(); 54 | queryRoot.additionalFields.Add(new SelectFieldExpression 55 | { 56 | Expression = unionCondition, 57 | Alias = filterColumnName 58 | }); 59 | var result = new ColumnReferenceExpression 60 | { 61 | Name = filterColumnName, 62 | Table = expression.Argument.Table 63 | }; 64 | rewritten.Add(result); 65 | return result; 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/Translation/Visitors/ObjectNameCheckingVisitor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Simple1C.Impl.Sql.SchemaMapping; 3 | using Simple1C.Impl.Sql.SqlAccess.Syntax; 4 | 5 | namespace Simple1C.Impl.Sql.Translation.Visitors 6 | { 7 | internal class ObjectNameCheckingVisitor : SqlVisitor 8 | { 9 | private readonly IMappingSource mappingSource; 10 | 11 | public ObjectNameCheckingVisitor(IMappingSource mappingSource) 12 | { 13 | this.mappingSource = mappingSource; 14 | } 15 | 16 | public override ISqlElement VisitIsReference(IsReferenceExpression expression) 17 | { 18 | var result = base.VisitIsReference(expression); 19 | var tableMapping = mappingSource.ResolveTableOrNull(expression.ObjectName); 20 | if (tableMapping == null) 21 | { 22 | const string messageFormat = "operator [Ссылка] has unknown object name [{0}]"; 23 | throw new InvalidOperationException(string.Format(messageFormat, expression.ObjectName)); 24 | } 25 | return result; 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/Translation/Visitors/SubqueryVisitor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Simple1C.Impl.Sql.SqlAccess.Syntax; 3 | 4 | namespace Simple1C.Impl.Sql.Translation.Visitors 5 | { 6 | internal class SubqueryVisitor : SqlVisitor 7 | { 8 | private readonly Func visit; 9 | 10 | public static void Visit(ISqlElement element, Func visit) 11 | { 12 | new SubqueryVisitor(visit).Visit(element); 13 | } 14 | 15 | private SubqueryVisitor(Func visit) 16 | { 17 | this.visit = visit; 18 | } 19 | 20 | public override SubqueryTable VisitSubqueryTable(SubqueryTable subqueryTable) 21 | { 22 | return visit(base.VisitSubqueryTable(subqueryTable)); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/Translation/Visitors/TableDeclarationVisitor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Simple1C.Impl.Sql.SqlAccess.Syntax; 3 | 4 | namespace Simple1C.Impl.Sql.Translation.Visitors 5 | { 6 | internal class TableDeclarationVisitor : SqlVisitor 7 | { 8 | private readonly Func visit; 9 | 10 | public static void Visit(ISqlElement element, Func visit) 11 | { 12 | var visitor = new TableDeclarationVisitor(visit); 13 | visitor.Visit(element); 14 | } 15 | 16 | private TableDeclarationVisitor(Func visit) 17 | { 18 | this.visit = visit; 19 | } 20 | 21 | public override ISqlElement VisitTableDeclaration(TableDeclarationClause clause) 22 | { 23 | return visit(clause); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /Simple1C/Impl/Sql/Translation/Visitors/ValueLiteralRewriter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Simple1C.Impl.Helpers; 3 | using Simple1C.Impl.Sql.SqlAccess.Syntax; 4 | using Simple1C.Impl.Sql.Translation.QueryEntities; 5 | using Simple1C.Interface; 6 | 7 | namespace Simple1C.Impl.Sql.Translation.Visitors 8 | { 9 | internal class ValueLiteralRewriter : SqlVisitor 10 | { 11 | private readonly EnumSqlBuilder enumSqlBuilder; 12 | private static readonly byte[] emptyReference = new byte[16]; 13 | 14 | public ValueLiteralRewriter(EnumSqlBuilder enumSqlBuilder) 15 | { 16 | this.enumSqlBuilder = enumSqlBuilder; 17 | } 18 | 19 | public override ISqlElement VisitValueLiteral(ValueLiteralExpression expression) 20 | { 21 | var result = GetSqlOrNull(expression.Value); 22 | if (result == null) 23 | { 24 | const string messageFormat = "operator [Значение] has invalid argument [{0}]"; 25 | throw new InvalidOperationException(string.Format(messageFormat, expression.Value)); 26 | } 27 | return result; 28 | } 29 | 30 | private ISqlElement GetSqlOrNull(string value) 31 | { 32 | var valueItems = value.Split('.'); 33 | if (valueItems.Length < 3) 34 | return null; 35 | var name = ConfigurationName.ParseOrNull(valueItems[0] + "." + valueItems[1]); 36 | if (!name.HasValue) 37 | return null; 38 | var objectValue = valueItems[2]; 39 | if (objectValue.EqualsIgnoringCase("ПустаяСсылка")) 40 | return new LiteralExpression 41 | { 42 | Value = emptyReference 43 | }; 44 | if (name.Value.Scope == ConfigurationScope.Перечисления) 45 | return enumSqlBuilder.GetValueSql(name.Value.Fullname, objectValue); 46 | return null; 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /Simple1C/Impl/SyncList.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using Simple1C.Interface.ObjectModel; 4 | 5 | namespace Simple1C.Impl 6 | { 7 | internal class SyncList 8 | { 9 | public List Commands { get; private set; } 10 | public IList Current { get; private set; } 11 | 12 | public static SyncList Compare(IList original, IList current) 13 | { 14 | var result = new SyncList 15 | { 16 | Commands = new List(), 17 | Current = current 18 | }; 19 | if (original != null) 20 | for (var i = original.Count - 1; i >= 0; i--) 21 | { 22 | var item = original[i]; 23 | if (current.IndexOf(item) < 0) 24 | { 25 | result.Commands.Add(new DeleteCommand { index = i }); 26 | original.RemoveAt(i); 27 | } 28 | } 29 | else 30 | original = new List(); 31 | for (var i = 0; i < current.Count; i++) 32 | { 33 | var item = (Abstract1CEntity) current[i]; 34 | var originalIndex = original.IndexOf(item); 35 | if (originalIndex < 0) 36 | { 37 | result.Commands.Add(new InsertCommand { item = item, index = i }); 38 | original.Insert(i, null); 39 | } 40 | else 41 | { 42 | if (originalIndex != i) 43 | { 44 | result.Commands.Add(new MoveCommand { from = originalIndex, delta = i - originalIndex }); 45 | original.RemoveAt(originalIndex); 46 | original.Insert(i, null); 47 | } 48 | if (item.Controller.Changed != null) 49 | result.Commands.Add(new UpdateCommand { index = i, item = item }); 50 | } 51 | } 52 | return result; 53 | } 54 | 55 | public enum CommandType 56 | { 57 | Delete, 58 | Insert, 59 | Move, 60 | Update 61 | } 62 | 63 | public abstract class Command 64 | { 65 | protected Command(CommandType commandType) 66 | { 67 | CommandType = commandType; 68 | } 69 | 70 | public CommandType CommandType { get; private set; } 71 | } 72 | 73 | public class DeleteCommand : Command 74 | { 75 | public DeleteCommand() : base(CommandType.Delete) 76 | { 77 | } 78 | 79 | public int index; 80 | } 81 | 82 | public class InsertCommand : Command 83 | { 84 | public InsertCommand() : base(CommandType.Insert) 85 | { 86 | } 87 | 88 | public int index; 89 | public Abstract1CEntity item; 90 | } 91 | 92 | 93 | public class MoveCommand : Command 94 | { 95 | public MoveCommand() : base(CommandType.Move) 96 | { 97 | } 98 | 99 | public int from; 100 | public int delta; 101 | } 102 | 103 | 104 | public class UpdateCommand : Command 105 | { 106 | public UpdateCommand() : base(CommandType.Update) 107 | { 108 | } 109 | 110 | public int index; 111 | public Abstract1CEntity item; 112 | } 113 | } 114 | } -------------------------------------------------------------------------------- /Simple1C/Impl/TypeInfo.cs: -------------------------------------------------------------------------------- 1 | using Simple1C.Impl.Generation; 2 | 3 | namespace Simple1C.Impl 4 | { 5 | internal struct TypeInfo 6 | { 7 | public SimpleTypeInfo? simpleType; 8 | public ConfigurationItem configurationItem; 9 | 10 | public static TypeInfo Simple(string typeName, int? maxLength = null) 11 | { 12 | return new TypeInfo 13 | { 14 | simpleType = new SimpleTypeInfo 15 | { 16 | typeName = typeName, 17 | maxLength = maxLength 18 | } 19 | }; 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /Simple1C/Impl/TypeRegistry.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | using Simple1C.Impl.Helpers; 5 | 6 | namespace Simple1C.Impl 7 | { 8 | internal class TypeRegistry 9 | { 10 | private readonly Dictionary typeMapping = new Dictionary(); 11 | 12 | public TypeRegistry(Assembly assembly) 13 | { 14 | Assembly = assembly; 15 | foreach (var x in assembly.GetTypes()) 16 | { 17 | if (!x.IsClass && !x.IsEnum) 18 | continue; 19 | var name = ConfigurationName.GetOrNull(x); 20 | if (!name.HasValue) 21 | continue; 22 | typeMapping.Add(name.Value.Fullname, x); 23 | } 24 | } 25 | 26 | public Assembly Assembly { get; private set; } 27 | 28 | public Type GetTypeOrNull(string configurationName) 29 | { 30 | return typeMapping.GetOrDefault(configurationName); 31 | } 32 | 33 | public Type GetType(string typeName) 34 | { 35 | var type = GetTypeOrNull(typeName); 36 | if (type == null) 37 | { 38 | const string messageFormat = "can't find .NET type by 1c type [{0}], mappings assembly [{1}]"; 39 | throw new InvalidOperationException(string.Format(messageFormat, 40 | typeName, Assembly.GetName().Name)); 41 | } 42 | return type; 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /Simple1C/Interface/ConfigurationScope.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Interface 2 | { 3 | public enum ConfigurationScope 4 | { 5 | Справочники, 6 | Документы, 7 | РегистрыСведений, 8 | ПланыСчетов, 9 | Перечисления, 10 | Константы, 11 | ПланыВидовХарактеристик, 12 | РегистрыБухгалтерии 13 | } 14 | } -------------------------------------------------------------------------------- /Simple1C/Interface/Connection1CType.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Interface 2 | { 3 | public enum Connection1CType 4 | { 5 | Fresh, 6 | File 7 | } 8 | } -------------------------------------------------------------------------------- /Simple1C/Interface/ConnectionStringBuilder.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | 3 | namespace Simple1C.Interface 4 | { 5 | public class ConnectionStringBuilder 6 | { 7 | public string User { get; set; } 8 | public string Password { get; set; } 9 | public string Server { get; set; } 10 | public string Database { get; set; } 11 | public Connection1CType Type { get; set; } 12 | public string FileLocation { get; set; } 13 | 14 | public string GetConnectionString() 15 | { 16 | var builder = new StringBuilder(); 17 | if (Type == Connection1CType.File) 18 | AddItem("File", FileLocation, builder); 19 | else 20 | { 21 | AddItem("Srvr", Server, builder); 22 | AddItem("Ref", Database, builder); 23 | } 24 | AddItem("Usr", User, builder); 25 | AddItem("Pwd", Password, builder); 26 | return builder.ToString(); 27 | } 28 | 29 | private static void AddItem(string name, string value, StringBuilder builder) 30 | { 31 | builder.Append(name); 32 | builder.Append('='); 33 | builder.Append(Quote(value)); 34 | builder.Append(';'); 35 | } 36 | 37 | private static string Quote(string s) 38 | { 39 | return "\"" + (s ?? "").Replace("\"", "\\\"") + "\""; 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /Simple1C/Interface/DataContextExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Linq.Expressions; 4 | using Simple1C.Impl.Helpers; 5 | 6 | namespace Simple1C.Interface 7 | { 8 | public static class DataContextExtensions 9 | { 10 | public static T Single(this IDataContext dataContextFactory, 11 | params Expression>[] filters) 12 | { 13 | var result = filters 14 | .Aggregate(dataContextFactory.Select(), (q, f) => q.Where(f)) 15 | .Take(2) 16 | .ToArray(); 17 | if (result.Length == 0) 18 | { 19 | const string messageFormat = "can't find entity [{0}] by condition [{1}]"; 20 | throw new InvalidOperationException(string.Format(messageFormat, 21 | typeof(T).FormatName(), filters.Select(Evaluator.PartialEval) 22 | .JoinStrings(" && "))); 23 | } 24 | if (result.Length > 1) 25 | { 26 | const string messageFormat = "found more than one instance of entity [{0}] by condition [{1}]"; 27 | throw new InvalidOperationException(string.Format(messageFormat, 28 | typeof(T).FormatName(), filters.Select(Evaluator.PartialEval) 29 | .JoinStrings(" && "))); 30 | } 31 | return result[0]; 32 | } 33 | 34 | public static T SingleOrDefault(this IDataContext dataContextFactory, 35 | params Expression>[] filters) 36 | where T : class 37 | { 38 | var result = filters 39 | .Aggregate(dataContextFactory.Select(), (q, f) => q.Where(f)) 40 | .Take(2) 41 | .ToArray(); 42 | if (result.Length == 0) 43 | return null; 44 | if (result.Length > 1) 45 | { 46 | const string messageFormat = "found more than one instance of entity [{0}] by condition [{1}]"; 47 | throw new InvalidOperationException(string.Format(messageFormat, 48 | typeof(T).FormatName(), filters.Select(Evaluator.PartialEval) 49 | .JoinStrings(" && "))); 50 | } 51 | return result[0]; 52 | } 53 | 54 | public static void Save(this IDataContext dataContext, params object[] entities) 55 | { 56 | dataContext.Save(entities); 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /Simple1C/Interface/GlobalContextFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Simple1C.Impl.Com; 3 | 4 | namespace Simple1C.Interface 5 | { 6 | public class GlobalContextFactory : IDisposable 7 | { 8 | private readonly object lockObject = new object(); 9 | private bool disposed; 10 | private COMConnector comConnector; 11 | 12 | public object Create(string connectionString) 13 | { 14 | lock (lockObject) 15 | { 16 | if (disposed) 17 | throw new ObjectDisposedException("GlobalContextFactory"); 18 | if (comConnector == null) 19 | comConnector = new COMConnector(); 20 | return comConnector.Connect(connectionString); 21 | } 22 | } 23 | 24 | public void Dispose() 25 | { 26 | lock (lockObject) 27 | { 28 | if (disposed) 29 | return; 30 | disposed = true; 31 | if (comConnector != null) 32 | { 33 | comConnector.Dispose(); 34 | comConnector = null; 35 | } 36 | } 37 | } 38 | 39 | private class COMConnector : DispatchObject, IDisposable 40 | { 41 | public COMConnector() 42 | : base(CreateComObject()) 43 | { 44 | } 45 | 46 | public object Connect(string connectionString) 47 | { 48 | return Invoke("Connect", connectionString); 49 | } 50 | 51 | private static object CreateComObject() 52 | { 53 | var connectorType = Type.GetTypeFromProgID("V83.COMConnector"); 54 | return Activator.CreateInstance(connectorType); 55 | } 56 | 57 | public new void Dispose() 58 | { 59 | base.Dispose(); 60 | } 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /Simple1C/Interface/IDataContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | 4 | namespace Simple1C.Interface 5 | { 6 | public interface IDataContext 7 | { 8 | Type GetTypeOrNull(string configurationName); 9 | IQueryable Select(string sourceName = null); 10 | void Save(object entity); 11 | } 12 | } -------------------------------------------------------------------------------- /Simple1C/Interface/ObjectModel/Abstract1CEntity.cs: -------------------------------------------------------------------------------- 1 | using Simple1C.Impl; 2 | 3 | namespace Simple1C.Interface.ObjectModel 4 | { 5 | public abstract class Abstract1CEntity 6 | { 7 | public EntityController Controller { get; set; } 8 | 9 | protected Abstract1CEntity() 10 | { 11 | Controller = new EntityController(null); 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /Simple1C/Interface/ObjectModel/ConfigurationScopeAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Simple1C.Interface.ObjectModel 4 | { 5 | public class ConfigurationScopeAttribute : Attribute 6 | { 7 | public ConfigurationScopeAttribute(ConfigurationScope scope) 8 | { 9 | Scope = scope; 10 | } 11 | 12 | public ConfigurationScope Scope { get; private set; } 13 | } 14 | } -------------------------------------------------------------------------------- /Simple1C/Interface/ObjectModel/Constant.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Interface.ObjectModel 2 | { 3 | public abstract class Constant 4 | { 5 | public abstract object ЗначениеНетипизированное { get; set; } 6 | } 7 | 8 | public abstract class Constant : Constant 9 | { 10 | public T Значение { get; set; } 11 | 12 | public override object ЗначениеНетипизированное 13 | { 14 | get { return Значение; } 15 | set { Значение = (T) value; } 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /Simple1C/Interface/ObjectModel/MaxLengthAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Simple1C.Interface.ObjectModel 4 | { 5 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property)] 6 | public class MaxLengthAttribute : Attribute 7 | { 8 | public MaxLengthAttribute(int value) 9 | { 10 | Value = value; 11 | } 12 | 13 | public int Value { get; private set; } 14 | } 15 | } -------------------------------------------------------------------------------- /Simple1C/Interface/ObjectModel/ObjectPresentationAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Simple1C.Interface.ObjectModel 4 | { 5 | public class ObjectPresentationAttribute : Attribute 6 | { 7 | public ObjectPresentationAttribute(string value) 8 | { 9 | Value = value; 10 | } 11 | 12 | public string Value { get; private set; } 13 | } 14 | } -------------------------------------------------------------------------------- /Simple1C/Interface/ObjectModel/Requisite.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Interface.ObjectModel 2 | { 3 | public struct Requisite 4 | { 5 | public T value; 6 | public uint revision; 7 | } 8 | } -------------------------------------------------------------------------------- /Simple1C/Interface/ObjectModel/SynonymAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Simple1C.Interface.ObjectModel 4 | { 5 | public class SynonymAttribute : Attribute 6 | { 7 | public SynonymAttribute(string value) 8 | { 9 | Value = value; 10 | } 11 | 12 | public string Value { get; private set; } 13 | } 14 | } -------------------------------------------------------------------------------- /Simple1C/Interface/ObjectPresentation.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Simple1C.Impl.Helpers; 3 | using Simple1C.Interface.ObjectModel; 4 | 5 | namespace Simple1C.Interface 6 | { 7 | public static class ObjectPresentation 8 | { 9 | public static string OfClass(object obj) 10 | { 11 | return OfClass(obj.GetType()); 12 | } 13 | 14 | public static string OfClass(Type objectType) 15 | { 16 | var attribute = AttributesCache.GetCustomAttribute(objectType, true); 17 | return attribute.Value; 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /Simple1C/Interface/Sql/IWriter.cs: -------------------------------------------------------------------------------- 1 | using System.Data; 2 | 3 | namespace Simple1C.Interface.Sql 4 | { 5 | public interface IWriter 6 | { 7 | void BeginWrite(DataColumn[] columns); 8 | void Write(RowAccessor row); 9 | void EndWrite(); 10 | } 11 | } -------------------------------------------------------------------------------- /Simple1C/Interface/Sql/QuerySource.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Interface.Sql 2 | { 3 | public class QuerySource 4 | { 5 | public string ConnectionString { get; set; } 6 | public int[] Areas { get; set; } 7 | } 8 | } -------------------------------------------------------------------------------- /Simple1C/Interface/Sql/RowAccessor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data; 4 | using System.Globalization; 5 | using System.Linq; 6 | using System.Security; 7 | using Npgsql; 8 | using Simple1C.Impl.Helpers; 9 | 10 | namespace Simple1C.Interface.Sql 11 | { 12 | public class RowAccessor 13 | { 14 | internal NpgsqlDataReader Reader { get; set; } 15 | internal DataColumn[] Columns { get; private set; } 16 | private readonly Dictionary nameToIndexMap; 17 | private static readonly DateTime minSqlDate = new DateTime(1753, 1, 1); 18 | 19 | public RowAccessor(DataColumn[] columns) 20 | { 21 | Columns = columns; 22 | nameToIndexMap = new Dictionary(StringComparer.OrdinalIgnoreCase); 23 | for (var i = 0; i < Columns.Length; i++) 24 | nameToIndexMap.Add(Columns[i].ColumnName, i); 25 | } 26 | 27 | public object GetValue(int index) 28 | { 29 | return ConvertType(Reader.GetValue(index), Columns[index]); 30 | } 31 | 32 | public object GetValue(string name) 33 | { 34 | int index; 35 | if (nameToIndexMap.TryGetValue(name, out index)) 36 | return GetValue(index); 37 | const string messageFormat = "invalid column name [{0}]"; 38 | throw new InvalidOperationException(string.Format(messageFormat, name)); 39 | } 40 | 41 | public void GetValues(object[] target) 42 | { 43 | Reader.GetValues(target); 44 | for (var i = 0; i < target.Length; i++) 45 | target[i] = ConvertType(target[i], Columns[i]); 46 | } 47 | 48 | private static object ConvertType(object source, DataColumn column) 49 | { 50 | if (!(source is string)) 51 | return source; 52 | var sourceAsString = (string) source; 53 | if (column.DataType == typeof(decimal)) 54 | return Convert.ChangeType(sourceAsString.Replace('.', ','), typeof(decimal)); 55 | if (column.DataType == typeof(bool)) 56 | return sourceAsString.EqualsIgnoringCase("t"); 57 | if (column.DataType == typeof(DateTime)) 58 | { 59 | DateTime dateTime; 60 | if (!TryParseDate(sourceAsString, out dateTime)) 61 | { 62 | const string messageFormat = "can't parse datetime from [{0}] for column [{1}]"; 63 | throw new InvalidOperationException(string.Format(messageFormat, 64 | source, column.ColumnName)); 65 | } 66 | return dateTime < minSqlDate ? (object) null : dateTime; 67 | } 68 | if (column.DataType == typeof(byte[])) 69 | { 70 | if (string.IsNullOrEmpty(sourceAsString) || sourceAsString.Length < 2) 71 | { 72 | const string messageFormat = "can't parse byte array from [{0}] for column [{1}]"; 73 | throw new InvalidOperationException(string.Format(messageFormat, source, column.ColumnName)); 74 | } 75 | return ByteArrayHelpers.FromHex(sourceAsString, 2); 76 | } 77 | return source; 78 | } 79 | 80 | private static bool TryParseDate(string s, out DateTime result) 81 | { 82 | return DateTime.TryParseExact(s, "yyyy-MM-dd", null, DateTimeStyles.None, out result) || 83 | DateTime.TryParseExact(s, "yyyy-MM-dd HH:mm:ss", null, DateTimeStyles.None, out result); 84 | } 85 | } 86 | } -------------------------------------------------------------------------------- /Simple1C/Interface/Synonym.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Simple1C.Impl.Helpers; 3 | using Simple1C.Interface.ObjectModel; 4 | 5 | namespace Simple1C.Interface 6 | { 7 | public static class Synonym 8 | { 9 | public static string OfEnum(T enumValue) 10 | where T : struct 11 | { 12 | return EnumAttributesCache.GetAttribute(enumValue).Value; 13 | } 14 | 15 | public static string OfEnumUnsafe(object enumValue) 16 | { 17 | return EnumAttributesCache.GetAttributeUnsafe(enumValue).Value; 18 | } 19 | 20 | public static string OfClass(object obj) 21 | { 22 | return OfClass(obj.GetType()); 23 | } 24 | 25 | public static string OfClass(Type objType) 26 | { 27 | return AttributesCache.GetCustomAttribute(objType, true).Value; 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /Simple1C/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("LinqTo1C")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("LinqTo1C")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("68b06c41-b5c6-4f68-9747-97d552b9bdd1")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | [assembly: InternalsVisibleTo("Generator")] 38 | [assembly: InternalsVisibleTo("Simple1C.Tests")] -------------------------------------------------------------------------------- /Simple1C/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Tests/Class1.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using Simple1C.Tests.Helpers; 3 | 4 | namespace Simple1C.Tests 5 | { 6 | internal class Class1 : TestBase 7 | { 8 | [Test] 9 | [Ignore("")] 10 | public void Test1() 11 | { 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /Tests/Helpers/Robocopy.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Tests.Helpers 2 | { 3 | public static class Robocopy 4 | { 5 | public static void Execute(string source, string target, bool onlyNewer) 6 | { 7 | ProcessesHelpers.ExecuteProcess("robocopy.exe", 8 | string.Format("\"{0}\" \"{1}\" /E{2}", 9 | source, target, onlyNewer ? " /XO" : ""), null, 10 | exitCode => exitCode >= 0 && exitCode <= 7); 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /Tests/Helpers/TestBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NUnit.Framework; 3 | 4 | namespace Simple1C.Tests.Helpers 5 | { 6 | [TestFixture] 7 | public abstract class TestBase 8 | { 9 | [OneTimeSetUp] 10 | protected virtual void OneTimeSetUp() 11 | { 12 | } 13 | 14 | [OneTimeTearDown] 15 | protected virtual void OneTimeTearDown() 16 | { 17 | } 18 | 19 | [SetUp] 20 | public void ActualSetUp() 21 | { 22 | try 23 | { 24 | SetUp(); 25 | } 26 | catch (Exception ex) 27 | { 28 | try 29 | { 30 | Console.WriteLine(ex); 31 | TearDown(); 32 | } 33 | catch (Exception e) 34 | { 35 | Console.WriteLine("teardown exception: " + e); 36 | } 37 | throw; 38 | } 39 | } 40 | 41 | protected virtual void SetUp() 42 | { 43 | } 44 | 45 | [TearDown] 46 | protected virtual void TearDown() 47 | { 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /Tests/Helpers/Testing1CConnector.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using Simple1C.Impl; 4 | using Simple1C.Interface; 5 | 6 | namespace Simple1C.Tests.Helpers 7 | { 8 | internal static class Testing1CConnector 9 | { 10 | private static GlobalContext globalContext; 11 | private static GlobalContext tempGlobalContext; 12 | private static readonly string defaultDatabaseFullPath = Path.GetFullPath("base"); 13 | private static readonly string tempDatabaseFullPath = Path.GetFullPath("temp-base"); 14 | private const string etalonDatabaseFullPath = @"\\host\dev\testBases\houseStark"; 15 | private const string etalonDatabaseLocalCacheFullPath = @"c:\testBases\houseStark"; 16 | 17 | static Testing1CConnector() 18 | { 19 | AppDomain.CurrentDomain.DomainUnload += delegate 20 | { 21 | if (globalContext != null) 22 | globalContext.Dispose(); 23 | if (tempGlobalContext != null) 24 | tempGlobalContext.Dispose(); 25 | }; 26 | } 27 | 28 | public static GlobalContext GetDefaultGlobalContext() 29 | { 30 | if (globalContext == null) 31 | { 32 | SyncDbDataWithEtalon(defaultDatabaseFullPath); 33 | globalContext = OpenContext(defaultDatabaseFullPath); 34 | } 35 | return globalContext; 36 | } 37 | 38 | public static GlobalContext GetTempGlobalContext(bool resetData) 39 | { 40 | if (tempGlobalContext != null) 41 | { 42 | tempGlobalContext.Dispose(); 43 | tempGlobalContext = null; 44 | } 45 | if (resetData) 46 | { 47 | if (Directory.Exists(tempDatabaseFullPath)) 48 | Directory.Delete(tempDatabaseFullPath, true); 49 | SyncDbDataWithEtalon(tempDatabaseFullPath); 50 | } 51 | return tempGlobalContext = OpenContext(tempDatabaseFullPath); 52 | } 53 | 54 | private static GlobalContext OpenContext(string databaseFullPath) 55 | { 56 | ProcessesHelpers.KillOwnProcessesByName("1cv8.exe"); 57 | var connectionStringBuilder = new ConnectionStringBuilder 58 | { 59 | Type = Connection1CType.File, 60 | FileLocation = databaseFullPath, 61 | User = "Администратор", 62 | Password = "" 63 | }; 64 | var globalContextFactory = new GlobalContextFactory(); 65 | var globalContextComObject = globalContextFactory.Create(connectionStringBuilder.GetConnectionString()); 66 | return new GlobalContext(globalContextComObject); 67 | } 68 | 69 | private static void SyncDbDataWithEtalon(string databaseFullPath) 70 | { 71 | Robocopy.Execute(etalonDatabaseFullPath, etalonDatabaseLocalCacheFullPath, true); 72 | Robocopy.Execute(etalonDatabaseLocalCacheFullPath, databaseFullPath, false); 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /Tests/Integration/CharacteristicsTest.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using NUnit.Framework; 3 | using Simple1C.Tests.Metadata1C.ПланыВидовХарактеристик; 4 | using Simple1C.Tests.Metadata1C.Справочники; 5 | 6 | namespace Simple1C.Tests.Integration 7 | { 8 | internal class CharacteristicsTest : COMDataContextTestBase 9 | { 10 | [Test] 11 | public void Test() 12 | { 13 | var разделыДатЗапредаИзменений = dataContext.Select<РазделыДатЗапретаИзменения>() 14 | .ToArray(); 15 | Assert.That(разделыДатЗапредаИзменений.Length, Is.EqualTo(1)); 16 | var item = разделыДатЗапредаИзменений[0]; 17 | Assert.That(item.Наименование, Is.EqualTo("Бухгалтерский учет")); 18 | Assert.That(item.ТипЗначения, Is.EquivalentTo(new[] {typeof(Организации)})); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /Tests/Integration/ConstantsTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NUnit.Framework; 3 | using Simple1C.Interface; 4 | using Simple1C.Tests.Metadata1C.Константы; 5 | 6 | namespace Simple1C.Tests.Integration 7 | { 8 | internal class ConstantsTest : COMDataContextTestBase 9 | { 10 | [Test] 11 | public void Simple() 12 | { 13 | Assert.That(dataContext.Single<ИспользоватьДатыЗапретаИзменения>().Значение, Is.False); 14 | dataContext.Save(new ИспользоватьДатыЗапретаИзменения {Значение = true}); 15 | Assert.That(dataContext.Single<ИспользоватьДатыЗапретаИзменения>().Значение, Is.True); 16 | dataContext.Save(new ИспользоватьДатыЗапретаИзменения {Значение = false}); 17 | Assert.That(dataContext.Single<ИспользоватьДатыЗапретаИзменения>().Значение, Is.False); 18 | } 19 | 20 | [Test] 21 | public void CanSaveGuidConstant() 22 | { 23 | var value = Guid.NewGuid(); 24 | dataContext.Save(new ВерсияДатЗапретаИзменения {Значение = value}); 25 | Assert.That(dataContext.Single<ВерсияДатЗапретаИзменения>().Значение.GetValueOrDefault(), 26 | Is.EqualTo(value)); 27 | dataContext.Save(new ВерсияДатЗапретаИзменения {Значение = null}); 28 | Assert.That(dataContext.Single<ВерсияДатЗапретаИзменения>().Значение, Is.Null); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /Tests/Integration/DataContextManagementTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using NUnit.Framework; 4 | using Simple1C.Impl; 5 | using Simple1C.Interface; 6 | using Simple1C.Tests.Helpers; 7 | using Simple1C.Tests.Metadata1C.Справочники; 8 | 9 | namespace Simple1C.Tests.Integration 10 | { 11 | internal class DataContextManagementTest : TestBase 12 | { 13 | private GlobalContext globalContext; 14 | private IDataContext dataContext; 15 | 16 | protected override void OneTimeSetUp() 17 | { 18 | base.OneTimeSetUp(); 19 | OpenContext(true); 20 | } 21 | 22 | [Test] 23 | public void CachedProjectionsDoNotCloseOverGlobalContext() 24 | { 25 | var контрагент1 = new Контрагенты 26 | { 27 | Наименование = "test-shortname1", 28 | ИНН = "test-inn1", 29 | КПП = "test-kpp", 30 | Комментарий = "test-comment1" 31 | }; 32 | dataContext.Save(контрагент1); 33 | 34 | var контрагент2 = dataContext.Select<Контрагенты>() 35 | .Where(x => x.Наименование == "test-shortname1") 36 | .Select(x => new 37 | { 38 | id = x.УникальныйИдентификатор 39 | }) 40 | .SingleOrDefault(); 41 | Assert.IsNotNull(контрагент2); 42 | Assert.That(контрагент2.id, Is.Not.Null); 43 | Assert.That(контрагент2.id, Is.Not.EqualTo(Guid.Empty)); 44 | Assert.That(контрагент2.id, Is.EqualTo(контрагент1.УникальныйИдентификатор)); 45 | 46 | OpenContext(false); 47 | var контрагент3 = dataContext.Select<Контрагенты>() 48 | .Where(x => x.Наименование == "test-shortname1") 49 | .Select(x => new 50 | { 51 | id = x.УникальныйИдентификатор 52 | }) 53 | .SingleOrDefault(); 54 | Assert.IsNotNull(контрагент3); 55 | Assert.That(контрагент3.id, Is.Not.Null); 56 | Assert.That(контрагент3.id, Is.Not.EqualTo(Guid.Empty)); 57 | Assert.That(контрагент3.id, Is.EqualTo(контрагент1.УникальныйИдентификатор)); 58 | } 59 | 60 | private void OpenContext(bool resetData) 61 | { 62 | globalContext = Testing1CConnector.GetTempGlobalContext(resetData); 63 | dataContext = DataContextFactory.CreateCOM(globalContext.ComObject(), typeof(Контрагенты).Assembly); 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /Tests/Integration/SaveValidationsIntegrationTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NUnit.Framework; 3 | using Simple1C.Tests.Metadata1C.Константы; 4 | using Simple1C.Tests.Metadata1C.Справочники; 5 | 6 | namespace Simple1C.Tests.Integration 7 | { 8 | internal class SaveValidationsIntegrationTest : COMDataContextTestBase 9 | { 10 | [Test] 11 | public void CrashOnMaxStringLengthViolation() 12 | { 13 | var номенклатура = new Номенклатура {Наименование = new string('x', 101)}; 14 | 15 | var exception = Assert.Throws(() => dataContext.Save(номенклатура)); 16 | 17 | const string expectedMessageFormat = 18 | "[Справочник.Номенклатура.Наименование] value [{0}] length [101] " + 19 | "is greater than configured max [100]"; 20 | Assert.That(exception.Message, Is.EqualTo(string.Format(expectedMessageFormat, 21 | new string('x', 101)))); 22 | } 23 | 24 | [Test] 25 | public void CrashOnMaxStringLengthViolationForNonCodeAndName() 26 | { 27 | var номенклатура = new Номенклатура 28 | { 29 | Наименование = "test-name", 30 | Артикул = new string('x', 26) 31 | }; 32 | var exception = Assert.Throws(() => dataContext.Save(номенклатура)); 33 | 34 | const string expectedMessageFormat = 35 | "[Справочник.Номенклатура.Артикул] value [{0}] length [26] " + 36 | "is greater than configured max [25]"; 37 | Assert.That(exception.Message, Is.EqualTo(string.Format(expectedMessageFormat, 38 | new string('x', 26)))); 39 | } 40 | 41 | [Test] 42 | public void CrashOnMaxStringLengthViolationForConstants() 43 | { 44 | var номенклатура = new АдресЦКК 45 | { 46 | Значение = new string('x', 301) 47 | }; 48 | var exception = Assert.Throws(() => dataContext.Save(номенклатура)); 49 | 50 | const string expectedMessageFormat = 51 | "[Константа.АдресЦКК] value [{0}] length [301] " + 52 | "is greater than configured max [300]"; 53 | Assert.That(exception.Message, Is.EqualTo(string.Format(expectedMessageFormat, 54 | new string('x', 301)))); 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Tests")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Tests")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("fbb45cea-5b7a-43d2-9c6d-a5b3d5fe287b")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Tests/Sql/LiteralsTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | 3 | namespace Simple1C.Tests.Sql 4 | { 5 | public class LiteralsTest : TranslationTestBase 6 | { 7 | [Test] 8 | public void EmptyReferenceLiteral() 9 | { 10 | const string sourceSql = @"select ИНН inn from Документ.ПоступлениеТоваровУслуг 11 | where Контрагент = Значение(Справочник.Контрагенты.ПустаяСсылка)"; 12 | const string mappings = @"Документ.ПоступлениеТоваровУслуг t1 Main 13 | ИНН Single c1 14 | Контрагент Single c2 15 | Справочник.Контрагенты t2 Main 16 | Ссылка Single c3"; 17 | const string expectedResult = @"select 18 | c1 as inn 19 | from t1 20 | where c2 = E'\\x00000000000000000000000000000000'"; 21 | CheckTranslate(mappings, sourceSql, expectedResult); 22 | } 23 | 24 | [Test] 25 | public void BoolLiteral() 26 | { 27 | const string sourceSql = @"select * 28 | from справочник.ДоговорыКонтрагентов as contracts 29 | where contracts.этогруппа = ложь"; 30 | const string mappings = @"Справочник.ДоговорыКонтрагентов t1 Main 31 | ЭтоГруппа Single c1"; 32 | const string expectedResult = @"select 33 | * 34 | from (select 35 | not(__nested_table0.c1) as __nested_field0 36 | from t1 as __nested_table0) as contracts 37 | where contracts.__nested_field0 = false"; 38 | CheckTranslate(mappings, sourceSql, expectedResult); 39 | } 40 | 41 | [Test] 42 | public void EscapeSingleQuotesInStringLiterals() 43 | { 44 | const string sourceSql = "select * from Справочник.Контрагенты where ИНН <> \"123'456\""; 45 | const string mappings = @"Справочник.Контрагенты t1 Main 46 | ИНН Single c1"; 47 | const string expected = @"select 48 | * 49 | from t1 50 | where c1 <> '123''456'"; 51 | CheckTranslate(mappings, sourceSql, expected); 52 | } 53 | 54 | [Test] 55 | public void ConvertDoubleQuotesToSingleQuotes() 56 | { 57 | const string sourceSql = @"select contractors.ИНН as CounterpartyInn 58 | from Справочник.Контрагенты as contractors 59 | where contractors.Наименование = ""test-name"""; 60 | const string mappings = @"Справочник.Контрагенты t1 Main 61 | ИНН Single c1 62 | Наименование Single c2"; 63 | const string expectedResult = @"select 64 | contractors.c1 as CounterpartyInn 65 | from t1 as contractors 66 | where contractors.c2 = 'test-name'"; 67 | CheckTranslate(mappings, sourceSql, expectedResult); 68 | } 69 | 70 | [Test] 71 | public void LiteralQueryFieldWithSubquery() 72 | { 73 | const string sourceSql = @"select top 10 1 from документ.поступлениетоваровуслуг"; 74 | const string mappings = @"документ.поступлениетоваровуслуг t1 Main 75 | ОбластьДанныхОсновныеДанные Single c2"; 76 | const string expectedResult = @"select 77 | 1 78 | from (select 79 | * 80 | from t1 as __nested_table0 81 | where __nested_table0.c2 in (100, 200)) as __subquery0 82 | limit 10"; 83 | CheckTranslate(mappings, sourceSql, expectedResult, 100,200); 84 | } 85 | } 86 | } -------------------------------------------------------------------------------- /Tests/Sql/TranslationTestBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using NUnit.Framework; 5 | using Simple1C.Impl.Helpers; 6 | using Simple1C.Impl.Sql.SchemaMapping; 7 | using Simple1C.Impl.Sql.Translation; 8 | using Simple1C.Tests.Helpers; 9 | 10 | namespace Simple1C.Tests.Sql 11 | { 12 | public abstract class TranslationTestBase : TestBase 13 | { 14 | protected DateTime? currentDate; 15 | 16 | protected override void SetUp() 17 | { 18 | base.SetUp(); 19 | currentDate = null; 20 | } 21 | 22 | protected void CheckTranslate(string mappings, string sql, string expected, params int[] areas) 23 | { 24 | var inmemoryMappingStore = Parse(SpacesToTabs(mappings).Trim()); 25 | var sqlTranslator = new QueryToSqlTranslator(inmemoryMappingStore, areas) 26 | { 27 | CurrentDate = currentDate 28 | }; 29 | var translated = sqlTranslator.Translate(sql); 30 | var translatedLines = SpacesToTabs(translated.Trim()) 31 | .Split(new[] {Environment.NewLine}, StringSplitOptions.None); 32 | expected = QueryToSqlTranslator.queryHints + "\r\n" + expected.Trim(); 33 | var expectedLines = SpacesToTabs(expected) 34 | .Split(new[] {Environment.NewLine}, StringSplitOptions.None); 35 | 36 | Console.WriteLine("Input:\r\n{0}\r\n", sql); 37 | Console.WriteLine("Translated:\r\n{0}\r\n", translated); 38 | Console.WriteLine("Expected:\r\n{0}\r\n", expected); 39 | Assert.That(translatedLines, Is.EqualTo(expectedLines)); 40 | } 41 | 42 | private static string SpacesToTabs(string s) 43 | { 44 | return s.Replace(" ", "\t"); 45 | } 46 | 47 | private static InMemoryMappingStore Parse(string source) 48 | { 49 | var tableMappings = StringHelpers.ParseLinesWithTabs(source, delegate(string s, List list) 50 | { 51 | var tableNames = s.Split(new[] {" "}, StringSplitOptions.None); 52 | return new TableMapping(tableNames[0], tableNames[1], 53 | TableMapping.ParseTableType(tableNames[2]), 54 | list.Select(PropertyMapping.Parse).ToArray()); 55 | }); 56 | return new InMemoryMappingStore(tableMappings.ToDictionary(x => x.QueryTableName, 57 | StringComparer.OrdinalIgnoreCase)); 58 | } 59 | 60 | private class InMemoryMappingStore : IMappingSource 61 | { 62 | private readonly Dictionary mappings; 63 | 64 | public InMemoryMappingStore(Dictionary mappings) 65 | { 66 | this.mappings = mappings; 67 | } 68 | 69 | public TableMapping ResolveTableOrNull(string queryName) 70 | { 71 | return mappings.GetOrDefault(queryName); 72 | } 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /Tests/SynonymTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using Simple1C.Interface; 3 | using Simple1C.Tests.Helpers; 4 | using Simple1C.Tests.Metadata1C.Перечисления; 5 | 6 | namespace Simple1C.Tests 7 | { 8 | public class SynonymTest : TestBase 9 | { 10 | [Test] 11 | public void CanReadSynonyms() 12 | { 13 | Assert.That(Synonym.OfEnum(ВидыРасходовНУ.АмортизационнаяПремия), Is.EqualTo("Амортизационная премия")); 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /Tests/TestEntities/AccountingDocument.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Simple1C.Tests.TestEntities 4 | { 5 | public class AccountingDocument 6 | { 7 | public Counterpart Counterpart { get; set; } 8 | public CounterpartyContract CounterpartContract { get; set; } 9 | public bool IsCreatedByEmployee { get; set; } 10 | public bool SumIncludesNds { get; set; } 11 | public DateTime Date { get; set; } 12 | public string Number { get; set; } 13 | public string Comment { get; set; } 14 | public IncomingOperationKind OperationKind { get; set; } 15 | public NomenclatureItem[] Items { get; set; } 16 | } 17 | } -------------------------------------------------------------------------------- /Tests/TestEntities/AdvanceWay.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Tests.TestEntities 2 | { 3 | public enum AdvanceWay 4 | { 5 | Automatically, 6 | ByDocument, 7 | DontTakeIntoAccount 8 | } 9 | } -------------------------------------------------------------------------------- /Tests/TestEntities/Bank.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Tests.TestEntities 2 | { 3 | public class Bank 4 | { 5 | public string Bik { get; set; } 6 | } 7 | } -------------------------------------------------------------------------------- /Tests/TestEntities/BankAccount.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Tests.TestEntities 2 | { 3 | public class BankAccount 4 | { 5 | public string Number { get; set; } 6 | public Bank Bank { get; set; } 7 | public string Name { get; set; } 8 | public string CurrencyCode { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /Tests/TestEntities/Banks.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Tests.TestEntities 2 | { 3 | public static class Banks 4 | { 5 | public static string AlfaBankBik 6 | { 7 | get { return "044525593"; } 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /Tests/TestEntities/Counterpart.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Tests.TestEntities 2 | { 3 | public class Counterpart 4 | { 5 | public string Name { get; set; } 6 | public string FullName { get; set; } 7 | public string Inn { get; set; } 8 | public string Kpp { get; set; } 9 | public LegalForm LegalForm { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /Tests/TestEntities/CounterpartContractKind.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Tests.TestEntities 2 | { 3 | public enum CounterpartContractKind 4 | { 5 | Outgoing, 6 | Incoming, 7 | Others, 8 | OutgoingWithComitent, 9 | OutgoingWithAgency, 10 | IncomingWithComitent, 11 | IncomingWithAgency 12 | } 13 | } -------------------------------------------------------------------------------- /Tests/TestEntities/CounterpartyContract.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Tests.TestEntities 2 | { 3 | public class CounterpartyContract 4 | { 5 | public string Name { get; set; } 6 | public string CurrencyCode { get; set; } 7 | public CounterpartContractKind Kind { get; set; } 8 | } 9 | } -------------------------------------------------------------------------------- /Tests/TestEntities/IncomingOperationKind.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Tests.TestEntities 2 | { 3 | public enum IncomingOperationKind 4 | { 5 | Goods, 6 | Services, 7 | BuyingCommission 8 | } 9 | } -------------------------------------------------------------------------------- /Tests/TestEntities/LegalForm.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Tests.TestEntities 2 | { 3 | public enum LegalForm 4 | { 5 | Organization, 6 | Ip 7 | } 8 | } -------------------------------------------------------------------------------- /Tests/TestEntities/NdsRate.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Tests.TestEntities 2 | { 3 | public enum NdsRate 4 | { 5 | NoNds, 6 | Nds10, 7 | Nds18, 8 | Nds20, 9 | Nds0, 10 | Nds10110, 11 | Nds18118, 12 | Nds20120 13 | } 14 | } -------------------------------------------------------------------------------- /Tests/TestEntities/NomenclatureItem.cs: -------------------------------------------------------------------------------- 1 | namespace Simple1C.Tests.TestEntities 2 | { 3 | public class NomenclatureItem 4 | { 5 | public decimal Count { get; set; } 6 | public decimal Price { get; set; } 7 | public NdsRate NdsRate { get; set; } 8 | public decimal NdsSum { get; set; } 9 | public decimal Sum { get; set; } 10 | public string Name { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /Tests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /build.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | set dotNetBasePath=%windir%\Microsoft.NET\Framework 3 | if exist %dotNetBasePath%64 set dotNetBasePath=%dotNetBasePath%64 4 | for /R %dotNetBasePath% %%i in (*msbuild.exe) do set msbuild=%%i 5 | 6 | set target=%~dp0Simple1C.sln 7 | 8 | %msbuild% /t:Rebuild /v:m /p:Configuration=Release %target% || exit /b 1 -------------------------------------------------------------------------------- /generate.cmd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivan816/simple-1c/f2e5ce78b98f70f30039fd3de79308a59d432fc2/generate.cmd -------------------------------------------------------------------------------- /nuget/publish.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | set nugetPath=C:\tools\nuget.exe 3 | del *.nupkg 4 | call ..\build.cmd || exit /b -1 5 | call %nugetPath% pack simple1C.nuspec || exit /b -1 6 | %nugetPath% push *.nupkg -Source https://www.nuget.org/api/v2/package -------------------------------------------------------------------------------- /nuget/simple1C.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Simple1C 5 | 1.0.55 6 | gusev_p, ivan_816 7 | gusev_p, ivan_816 8 | https://github.com/gusev-p/simple-1c/blob/master/LICENSE.txt 9 | https://github.com/gusev-p/simple-1c 10 | false 11 | Linq provider for 1C 12 | Copyright 2016 13 | Bug fixes 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /todo: -------------------------------------------------------------------------------- 1 | todo 2 | * UnionType 3 | * перевести все Set-property на MemberAccessor 4 | * Разрулить следующую ситуацию: 5 | КонтрагентВася.ГоловнойКонтрагент = КонтрагентВася; 6 | Save(КонтрагентВася); 7 | * Научиться мапиться на sql для чтения, как здесь http://www.linq-demo.1csoftware.com делают 8 | * создавать DispatchObject-ы через Reflection.Emit 9 | * inmemoryDataContext, LoadNewestRevisionWhenAccessPropertyForTheFirstTime: выяснить, какое поведение дожно быть 10 | * более интеллектуально генерить ключ для кэширования проекций 11 | * убрать лишнюю возню с перестроением QueryField, SelectedProperty, SelectedPropertyItem, 12 | если проекцию из кэша можно достать 13 | * объединить логику получения метаданных в генераторе и в MetadataAccessor-е 14 | 15 | todo sql 16 | 17 | ??поддержать cast. Строку с датой ("2") хотим превратить в число 2. Очень плохо в 1с 18 | 19 | ColumnReferenceTableNameRewriter 20 | запоминать филды в список, remove copypaste 21 | 22 | TableDeclarationExtractor.VisitJoin ?? 23 | copypaste иван советует 24 | 25 | В order by алиасы резолвить из первого из Union-ов 26 | 27 | ?order by по колонке с енумом -> нужен join 28 | 29 | Константы 30 | 31 | в DeduceEntityTypeFromIsReferenceExpressionVisitor учитывать условия в join-ах --------------------------------------------------------------------------------