Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

First release

  • Loading branch information...
commit a751efd1c926b0494ba458b01eca9cea8d423ea5 1 parent 1884035
@markrendle authored
Showing with 5,258 additions and 501 deletions.
  1. +7 −0 README.md
  2. +53 −0 Simple.Data.Interop.Test/EnumerableExTest.cs
  3. +28 −0 Simple.Data.Interop.Test/LexerTest.cs
  4. +0 −1  Simple.Data.Interop.Test/QueryExecutorTest.cs
  5. +1 −0  Simple.Data.Interop.Test/Simple.Data.Interop.Test.csproj
  6. +29 −0 Simple.Data.Interop/EnumerableEx.cs
  7. +24 −0 Simple.Data.Interop/Lexer.cs
  8. +1 −0  Simple.Data.Interop/Simple.Data.Interop.csproj
  9. +5 −0 Simple.Data.Interop/Token.cs
  10. +192 −0 Simple.Data.Pad.Test/AutoCompleterTest.cs
  11. +36 −0 Simple.Data.Pad.Test/Properties/AssemblyInfo.cs
  12. +81 −0 Simple.Data.Pad.Test/Simple.Data.Pad.Test.csproj
  13. +7 −0 Simple.Data.Pad.Test/packages.config
  14. +12 −0 Simple.Data.Pad.sln
  15. +4,027 −3 Simple.Data.Pad/App.xaml
  16. +246 −129 Simple.Data.Pad/AutoCompleter.cs
  17. +13 −4 Simple.Data.Pad/DatabaseSelector.xaml
  18. BIN  Simple.Data.Pad/Images/Icon.ico
  19. BIN  Simple.Data.Pad/Images/database_go.png
  20. +272 −261 Simple.Data.Pad/MainViewModel.cs
  21. +114 −92 Simple.Data.Pad/MainWindow.xaml
  22. +38 −11 Simple.Data.Pad/MainWindow.xaml.cs
  23. +31 −0 Simple.Data.Pad/MethodInfoToStringConverter.cs
  24. BIN  Simple.Data.Pad/Release/Simple.Data.Ado.dll
  25. BIN  Simple.Data.Pad/Release/Simple.Data.Interop.dll
  26. BIN  Simple.Data.Pad/Release/Simple.Data.Interop.pdb
  27. BIN  Simple.Data.Pad/Release/Simple.Data.Pad-1.0.zip
  28. BIN  Simple.Data.Pad/Release/Simple.Data.Pad.exe
  29. +30 −0 Simple.Data.Pad/Release/Simple.Data.Pad.exe.config
  30. BIN  Simple.Data.Pad/Release/Simple.Data.Pad.pdb
  31. BIN  Simple.Data.Pad/Release/Simple.Data.SqlServer.dll
  32. BIN  Simple.Data.Pad/Release/Simple.Data.dll
  33. +10 −0 Simple.Data.Pad/Simple.Data.Pad.csproj
  34. +1 −0  packages/repositories.config
View
7 README.md
@@ -0,0 +1,7 @@
+# Simple.Data.Pad
+
+I've knocked this tool together to make working with Simple.Data a bit easier.
+
+I am not proud of this code.
+
+If you want to fork it and make it better, please do.
View
53 Simple.Data.Interop.Test/EnumerableExTest.cs
@@ -0,0 +1,53 @@
+namespace Simple.Data.Interop.Test
+{
+ using System.Linq;
+ using Xunit;
+
+ public class EnumerableExTest
+ {
+ [Fact]
+ public void MultiCountShouldReturnCorrectSizedArrayForOnePredicate()
+ {
+ var actual = Enumerable.Empty<string>().MultiCount(string.IsNullOrWhiteSpace);
+ Assert.Equal(1, actual.Length);
+ }
+
+ [Fact]
+ public void MultiCountShouldReturnCorrectSizedArrayForTwoPredicates()
+ {
+ var actual = Enumerable.Empty<string>().MultiCount(string.IsNullOrWhiteSpace, string.IsNullOrEmpty);
+ Assert.Equal(2, actual.Length);
+ }
+
+ [Fact]
+ public void MultiCountShouldReturnCorrectSizedArrayForThreePredicates()
+ {
+ var actual = Enumerable.Empty<string>().MultiCount(string.IsNullOrWhiteSpace, string.IsNullOrEmpty, s => s == "foo");
+ Assert.Equal(3, actual.Length);
+ }
+
+ [Fact]
+ public void MultiCountShouldGetCorrectCountForOnePredicate()
+ {
+ var actual = "Hello world!".MultiCount(c => c == 'H');
+ Assert.Equal(1, actual[0]);
+ }
+
+ [Fact]
+ public void MultiCountShouldGetCorrectCountsForTwoPredicates()
+ {
+ var actual = "Hello world!".MultiCount(c => c == 'H', c => c == 'o');
+ Assert.Equal(1, actual[0]);
+ Assert.Equal(2, actual[1]);
+ }
+
+ [Fact]
+ public void MultiCountShouldGetCorrectCountsForThreePredicates()
+ {
+ var actual = "Hello world!".MultiCount(c => c == 'H', c => c == 'o', c => c == '!');
+ Assert.Equal(1, actual[0]);
+ Assert.Equal(2, actual[1]);
+ Assert.Equal(1, actual[2]);
+ }
+ }
+}
View
28 Simple.Data.Interop.Test/LexerTest.cs
@@ -228,5 +228,33 @@ public void FindByWithNamedParameterStringConstantIsTokenizedCorrectly()
Assert.False(e.MoveNext());
}
}
+
+ [Fact]
+ public void ShouldAccountForNestedParentheses()
+ {
+ var tokens = new[]
+ {
+ new Token(TokenType.Identifier), new Token(TokenType.OpenParen),
+ new Token(TokenType.Identifier), new Token(TokenType.OpenParen),
+ new Token(TokenType.Identifier), new Token(TokenType.CloseParen),
+ new Token(TokenType.CloseParen),
+ };
+
+ Assert.Equal(1, Lexer.FindIndexOfOpeningToken(tokens, 6, TokenType.OpenParen));
+ }
+
+ [Fact]
+ public void ShouldFindOpeningTokenInsideNested()
+ {
+ var tokens = new[]
+ {
+ new Token(TokenType.Identifier), new Token(TokenType.OpenParen),
+ new Token(TokenType.Identifier), new Token(TokenType.OpenParen),
+ new Token(TokenType.Identifier), new Token(TokenType.CloseParen),
+ new Token(TokenType.CloseParen),
+ };
+
+ Assert.Equal(3, Lexer.FindIndexOfOpeningToken(tokens, 5, TokenType.OpenParen));
+ }
}
}
View
1  Simple.Data.Interop.Test/QueryExecutorTest.cs
@@ -15,7 +15,6 @@ public void CanExecuteQuery()
Assert.True(executor.CompileAndRun(database, out result));
var dict = result as IDictionary<string, object>;
Assert.NotNull(dict);
-
}
}
}
View
1  Simple.Data.Interop.Test/Simple.Data.Interop.Test.csproj
@@ -52,6 +52,7 @@
</Reference>
</ItemGroup>
<ItemGroup>
+ <Compile Include="EnumerableExTest.cs" />
<Compile Include="LexerTest.cs" />
<Compile Include="ParserTest.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
View
29 Simple.Data.Interop/EnumerableEx.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Simple.Data.Interop
+{
+ public static class EnumerableEx
+ {
+ public static int[] MultiCount<T>(this IEnumerable<T> source, params Func<T,bool>[] predicates)
+ {
+ int predicateCount = predicates.Count();
+ int[] counts = Enumerable.Repeat(0, predicateCount).ToArray();
+
+ foreach (var item in source)
+ {
+ for (int i = 0; i < predicateCount; i++)
+ {
+ if (predicates[i](item))
+ {
+ ++counts[i];
+ }
+ }
+ }
+
+ return counts;
+ }
+ }
+}
View
24 Simple.Data.Interop/Lexer.cs
@@ -80,5 +80,29 @@ private string HoldString(Match match)
_strings.Add(key, value.Substring(1, value.Length - 2));
return key;
}
+
+ public static int FindIndexOfOpeningToken(Token[] tokens, int startIndex, TokenType openingType)
+ {
+ var closingType = tokens[startIndex].Type;
+ int nestCount = 0;
+
+ for (int i = startIndex; i >= 0; i--)
+ {
+ if (tokens[i].Type == closingType)
+ {
+ ++nestCount;
+ }
+ else if (tokens[i].Type == openingType)
+ {
+ --nestCount;
+ }
+ if (nestCount == 0)
+ {
+ return i;
+ }
+ }
+
+ return -1;
+ }
}
}
View
1  Simple.Data.Interop/Simple.Data.Interop.csproj
@@ -51,6 +51,7 @@
<ItemGroup>
<Compile Include="AstNode.cs" />
<Compile Include="AstNodeType.cs" />
+ <Compile Include="EnumerableEx.cs" />
<Compile Include="Lexer.cs" />
<Compile Include="Parser.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
View
5 Simple.Data.Interop/Token.cs
@@ -24,5 +24,10 @@ public TokenType Type
{
get { return _tokenType; }
}
+
+ public bool Is(TokenType type)
+ {
+ return Type == type;
+ }
}
}
View
192 Simple.Data.Pad.Test/AutoCompleterTest.cs
@@ -0,0 +1,192 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Simple.Data.Pad.Test
+{
+ using Ado.Schema;
+ using Xunit;
+
+ public class AutoCompleterTest
+ {
+ private static AutoCompleter CreateTarget()
+ {
+ return new AutoCompleter(new StubSchemaProvider());
+ }
+
+ [Fact]
+ public void ShouldReturnEmptyForEmptyString()
+ {
+ var target = CreateTarget();
+ var actual = target.GetOptions(string.Empty);
+ Assert.Equal(0, actual.Count());
+ }
+
+ [Fact]
+ public void ShouldReturnTableListForDb()
+ {
+ var target = CreateTarget();
+ var actual = target.GetOptions("db.").ToArray();
+ Assert.Equal(1, actual.Length);
+ Assert.Equal("Test", actual[0]);
+ }
+
+ [Fact]
+ public void ShouldReturnFindByListForTable()
+ {
+ var target = CreateTarget();
+ var actual = target.GetOptions("db.Test.").ToArray();
+ Assert.Contains("FindById", actual);
+ Assert.Contains("FindByName", actual);
+ }
+
+ [Fact]
+ public void ShouldReturnFindAllByListForTable()
+ {
+ var target = CreateTarget();
+ var actual = target.GetOptions("db.Test.").ToArray();
+ Assert.Contains("FindAllById", actual);
+ Assert.Contains("FindAllByName", actual);
+ }
+
+ [Fact]
+ public void ShouldReturnColumnListForTable()
+ {
+ var target = CreateTarget();
+ var actual = target.GetOptions("db.Test.").ToArray();
+ Assert.Contains("Id", actual);
+ Assert.Contains("Name", actual);
+ }
+
+ [Fact]
+ public void ShouldNotReturnAnythingAfterFindBy()
+ {
+ var target = CreateTarget();
+ var actual = target.GetOptions("db.Test.FindById(1).").ToArray();
+ Assert.Empty(actual);
+ }
+
+ [Fact]
+ public void ShouldReturnQueryMethodsAfterQuery()
+ {
+ var target = CreateTarget();
+ var actual = target.GetOptions("db.Test.Query().").ToArray();
+ foreach (var queryMethod in ExpectedQueryMethods(false, "Id", "Name"))
+ {
+ Assert.Contains(queryMethod, actual);
+ }
+ }
+
+ [Fact]
+ public void ShouldReturnQueryMethodsAfterQueryAndChainedMethod()
+ {
+ var target = CreateTarget();
+ var actual = target.GetOptions("db.Test.Query().Where(stuff).").ToArray();
+ foreach (var queryMethod in ExpectedQueryMethods(false, "Id", "Name"))
+ {
+ Assert.Contains(queryMethod, actual);
+ }
+ }
+
+ [Fact]
+ public void ShouldReturnThenByMethodsAfterQueryAndChainedOrderBy()
+ {
+ var target = CreateTarget();
+ var actual = target.GetOptions("db.Test.Query().OrderById(stuff).").ToArray();
+ foreach (var queryMethod in ExpectedQueryMethods(true, "Id", "Name"))
+ {
+ Assert.Contains(queryMethod, actual);
+ }
+ }
+
+ [Fact]
+ public void ShouldReturnFilteredListOfOrderByWithColumns()
+ {
+ var target = CreateTarget();
+ var actual = target.GetOptions("db.Test.Query().OrderB").ToArray();
+ Assert.Equal(6, actual.Length);
+ }
+
+ private static IEnumerable<string> ExpectedQueryMethods(bool includeThenBy, params string[] columns)
+ {
+ yield return "Select";
+ yield return "Where";
+ yield return "ReplaceWhere";
+ if (includeThenBy)
+ {
+ yield return "ThenBy";
+ yield return "ThenByDescending";
+ }
+ else
+ {
+ yield return "OrderBy";
+ yield return "OrderByDescending";
+ }
+ yield return "Skip";
+ yield return "Take";
+ yield return "Join";
+
+ if (columns.Length > 0)
+ {
+ foreach (var column in columns)
+ {
+ if (includeThenBy)
+ {
+ yield return "ThenBy" + column;
+ yield return "ThenBy" + column + "Descending";
+ }
+ else
+ {
+ yield return "OrderBy" + column;
+ yield return "OrderBy" + column + "Descending";
+ }
+ }
+ }
+ }
+ }
+
+ class StubSchemaProvider : ISchemaProvider
+ {
+ public IEnumerable<Table> GetTables()
+ {
+ yield return new Table("Test", "dbo", TableType.Table);
+ }
+
+ public IEnumerable<Column> GetColumns(Table table)
+ {
+ yield return new Column("Id", table);
+ yield return new Column("Name", table);
+ }
+
+ public IEnumerable<Procedure> GetStoredProcedures()
+ {
+ yield break;
+ }
+
+ public IEnumerable<Parameter> GetParameters(Procedure storedProcedure)
+ {
+ yield break;
+ }
+
+ public Key GetPrimaryKey(Table table)
+ {
+ return new Key(new[] {"Id"});
+ }
+
+ public IEnumerable<ForeignKey> GetForeignKeys(Table table)
+ {
+ yield break;
+ }
+
+ public string QuoteObjectName(string unquotedName)
+ {
+ return "[" + unquotedName + "]";
+ }
+
+ public string NameParameter(string baseName)
+ {
+ return "@" + baseName;
+ }
+ }
+}
View
36 Simple.Data.Pad.Test/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Simple.Data.Pad.Test")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Microsoft")]
+[assembly: AssemblyProduct("Simple.Data.Pad.Test")]
+[assembly: AssemblyCopyright("Copyright © Microsoft 2011")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("2915ab12-a755-4acf-a2f2-fa653591ec23")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
View
81 Simple.Data.Pad.Test/Simple.Data.Pad.Test.csproj
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>8.0.30703</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{CB7C9EAD-74E6-473B-AA3A-AC869C24B1BD}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Simple.Data.Pad.Test</RootNamespace>
+ <AssemblyName>Simple.Data.Pad.Test</AssemblyName>
+ <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <TargetFrameworkProfile>Client</TargetFrameworkProfile>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <PlatformTarget>x86</PlatformTarget>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="Simple.Data">
+ <HintPath>..\packages\Simple.Data.Core.0.7.2\lib\net40\Simple.Data.dll</HintPath>
+ </Reference>
+ <Reference Include="Simple.Data.Ado">
+ <HintPath>..\packages\Simple.Data.Ado.0.7.2\lib\net40\Simple.Data.Ado.dll</HintPath>
+ </Reference>
+ <Reference Include="Simple.Data.SqlServer">
+ <HintPath>..\packages\Simple.Data.SqlServer.0.7.2\lib\net40\Simple.Data.SqlServer.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ <Reference Include="xunit">
+ <HintPath>..\packages\xunit.1.8.0.1545\lib\xunit.dll</HintPath>
+ </Reference>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="AutoCompleterTest.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="packages.config" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Simple.Data.Interop\Simple.Data.Interop.csproj">
+ <Project>{1BBCF939-00FE-4FF4-BF63-C460AC7C3C05}</Project>
+ <Name>Simple.Data.Interop</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Simple.Data.Pad\Simple.Data.Pad.csproj">
+ <Project>{59719692-B30E-4F55-B93B-C16EFC1CD978}</Project>
+ <Name>Simple.Data.Pad</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
View
7 Simple.Data.Pad.Test/packages.config
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="xunit" version="1.8.0.1545" />
+ <package id="Simple.Data.Core" version="0.7.2" />
+ <package id="Simple.Data.Ado" version="0.7.2" />
+ <package id="Simple.Data.SqlServer" version="0.7.2" />
+</packages>
View
12 Simple.Data.Pad.sln
@@ -7,6 +7,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Simple.Data.Interop", "Simp
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Simple.Data.Interop.Test", "Simple.Data.Interop.Test\Simple.Data.Interop.Test.csproj", "{CEFFB6A9-DF6A-4315-98BB-82BFDA6775BF}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Simple.Data.Pad.Test", "Simple.Data.Pad.Test\Simple.Data.Pad.Test.csproj", "{CB7C9EAD-74E6-473B-AA3A-AC869C24B1BD}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -47,6 +49,16 @@ Global
{CEFFB6A9-DF6A-4315-98BB-82BFDA6775BF}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{CEFFB6A9-DF6A-4315-98BB-82BFDA6775BF}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{CEFFB6A9-DF6A-4315-98BB-82BFDA6775BF}.Release|x86.ActiveCfg = Release|Any CPU
+ {CB7C9EAD-74E6-473B-AA3A-AC869C24B1BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {CB7C9EAD-74E6-473B-AA3A-AC869C24B1BD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CB7C9EAD-74E6-473B-AA3A-AC869C24B1BD}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {CB7C9EAD-74E6-473B-AA3A-AC869C24B1BD}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {CB7C9EAD-74E6-473B-AA3A-AC869C24B1BD}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {CB7C9EAD-74E6-473B-AA3A-AC869C24B1BD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {CB7C9EAD-74E6-473B-AA3A-AC869C24B1BD}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CB7C9EAD-74E6-473B-AA3A-AC869C24B1BD}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {CB7C9EAD-74E6-473B-AA3A-AC869C24B1BD}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {CB7C9EAD-74E6-473B-AA3A-AC869C24B1BD}.Release|x86.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
View
4,030 Simple.Data.Pad/App.xaml
4,027 additions, 3 deletions not shown
View
375 Simple.Data.Pad/AutoCompleter.cs
@@ -1,132 +1,249 @@
-namespace Simple.Data.Pad
-{
- using System;
- using System.Collections.Concurrent;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Text.RegularExpressions;
- using Ado;
- using Ado.Schema;
- using Interop;
-
- public class AutoCompleter
- {
- private static readonly Regex NonAlphaNumeric = new Regex("[^0-9a-zA-Z]+");
- private static readonly string[] Empty = new string[0];
- private readonly ISchemaProvider _schemaProvider;
- private readonly ConcurrentDictionary<string,string[]> _cache = new ConcurrentDictionary<string, string[]>();
-
- public AutoCompleter(Database database)
- {
- if (database != null)
- {
- var adoAdapter = database.GetAdapter() as AdoAdapter;
- if (adoAdapter != null)
- {
- _schemaProvider = adoAdapter.SchemaProvider;
- }
- }
- }
-
- public IEnumerable<string> GetOptions(string currentText)
- {
- if (_schemaProvider == null || string.IsNullOrWhiteSpace(currentText) || (!currentText.Contains("."))) return Empty;
-
- var array = _cache.GetOrAdd(currentText, GetOptionsImpl);
- if (array.Length == 1 && currentText.Substring(currentText.LastIndexOf('.') + 1).Equals(array[0], StringComparison.CurrentCultureIgnoreCase))
- return Empty;
- return array;
- }
-
- private string[] GetOptionsImpl(string currentText)
- {
- var tokens = new Lexer(currentText).GetTokens().ToArray();
- if (tokens.Length < 2) return Empty;
- var db = tokens.First().Value;
- var token = tokens.Reverse().GetEnumerator();
-
- token.MoveNext();
-
- if (token.Current.Type != TokenType.Dot && token.Current.Type != TokenType.Identifier) return Empty;
-
- string partial = string.Empty;
- if (token.Current.Type == TokenType.Identifier)
- {
- partial = token.Current.Value.ToString();
- token.MoveNext();
- }
-
- if (token.Current.Type == TokenType.Dot)
- {
- token.MoveNext();
- }
-
- if (token.Current.Type != TokenType.Identifier)
- {
- return Empty;
- }
-
- var array = GetOptionsImpl(partial, token, db).ToArray();
- if (array.Length == 1 && array[0].Equals(partial, StringComparison.CurrentCultureIgnoreCase)) return Empty;
- return array;
- }
-
- private IEnumerable<string> GetOptionsImpl(string partial, IEnumerator<Token> token, object db)
- {
- if (token.Current.Value == db)
- {
- return DatabaseOptions()
- .Select(Prettify)
- .Where(s => s.StartsWith(partial, StringComparison.CurrentCultureIgnoreCase))
- .OrderBy(s => s);
- }
-
- return TableOptions(token.Current.Value.ToString())
- .Where(s => s.StartsWith(partial, StringComparison.CurrentCultureIgnoreCase))
- .OrderBy(s => s);
- }
-
- private IEnumerable<string> TableOptions(string tableName)
- {
- Table table = _schemaProvider.GetTables()
- .Where(t => Prettify(t.ActualName) == Prettify(tableName))
- .SingleOrDefault();
-
- if (table == null) yield break;
- foreach (var column in _schemaProvider.GetColumns(table).Select(c => Prettify(c.ActualName)))
- {
- yield return column;
+namespace Simple.Data.Pad
+{
+ using System;
+ using System.Collections.Concurrent;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using System.Text.RegularExpressions;
+ using Ado;
+ using Ado.Schema;
+ using Interop;
+
+ public class AutoCompleter
+ {
+ private static readonly Regex NonAlphaNumeric = new Regex("[^0-9a-zA-Z]+");
+ private static readonly string[] Empty = new string[0];
+ private readonly ISchemaProvider _schemaProvider;
+ private readonly ConcurrentDictionary<string,string[]> _cache = new ConcurrentDictionary<string, string[]>();
+ private static readonly ConcurrentDictionary<string, string> PrettifiedCache = new ConcurrentDictionary<string, string>();
+
+ public AutoCompleter(DataStrategy database)
+ {
+ if (database != null)
+ {
+ var adoAdapter = database.GetAdapter() as AdoAdapter;
+ if (adoAdapter != null)
+ {
+ _schemaProvider = adoAdapter.SchemaProvider;
+ }
+ }
+ }
+
+ public AutoCompleter(ISchemaProvider schemaProvider)
+ {
+ _schemaProvider = schemaProvider;
+ }
+
+ public IEnumerable<string> GetOptions(string currentText)
+ {
+ // Check that we can even do anything useful
+ if (_schemaProvider == null || string.IsNullOrWhiteSpace(currentText) || (!currentText.Contains("."))) return Empty;
+
+ var array = _cache.GetOrAdd(currentText, GetOptionsImpl);
+
+ // If the only thing in the array is the last identifier before the cursor, then we've got nothing to say
+ if (array.Length == 1 && currentText.Substring(currentText.LastIndexOf('.') + 1).Equals(array[0], StringComparison.CurrentCultureIgnoreCase))
+ return Empty;
+
+ return array;
+ }
+
+ private string[] GetOptionsImpl(string currentText)
+ {
+ var tokens = new Lexer(currentText).GetTokens().ToArray();
+ if (tokens.Length < 2) return Empty;
+ var db = tokens[0].Value;
+ int current = tokens.Length - 1;
+
+ if (tokens[current].Type != TokenType.Dot && tokens[current].Type != TokenType.Identifier) return Empty;
+
+ // Is the user halfway through typing an identifier?
+ string partial = string.Empty;
+ if (tokens[current].Type == TokenType.Identifier)
+ {
+ partial = tokens[current].Value.ToString();
+ --current;
+ }
+
+ // Skip over what should be a dot.
+ if (tokens[current].Type == TokenType.Dot)
+ {
+ --current;
+ }
+
+ // Is the thing before the dot a method call?
+ if (tokens[current].Type == TokenType.CloseParen)
+ {
+ return GetOptionsForMethodReturnType(tokens, current, false, partial).ToArray();
+ }
+
+ // Now we should be on an identifier
+ if (tokens[current].Type != TokenType.Identifier)
+ {
+ return Empty;
+ }
+
+ var array = GetOptionsImpl(partial, tokens[current], db).ToArray();
+ if (array.Length == 1 && array[0].Equals(partial, StringComparison.CurrentCultureIgnoreCase)) return Empty;
+ return array;
+ }
+
+ private IEnumerable<string> GetOptionsForMethodReturnType(Token[] tokens, int current, bool methodChainIncludesOrderBy, string partial)
+ {
+ current = Lexer.FindIndexOfOpeningToken(tokens, current, TokenType.OpenParen);
+ if (--current < 0)
+ {
+ return Empty;
+ }
+
+ if (tokens[current].Type != TokenType.Identifier) return Empty;
+
+ if (IsAMethodThatReturnsAQuery(tokens[current].Value.ToString()))
+ {
+ current -= 2;
+ if (tokens[current].Type != TokenType.Identifier)
+ {
+ return Empty;
+ }
+ var options = QueryOptions(tokens[current].Value.ToString(), methodChainIncludesOrderBy);
+ if (!string.IsNullOrWhiteSpace(partial))
+ {
+ options = options.Where(s => s.StartsWith(partial, StringComparison.CurrentCultureIgnoreCase));
+ }
+ return options;
+ }
+
+ string methodName = tokens[current].Value.ToString();
+ if (methodName.Equals("join", StringComparison.CurrentCultureIgnoreCase)) return new[] { "On" };
+
+ methodChainIncludesOrderBy = methodChainIncludesOrderBy || methodName.StartsWith("OrderBy", StringComparison.CurrentCultureIgnoreCase);
+
+ --current;
+
+ if (tokens[current].Type == TokenType.Dot)
+ {
+ --current;
+ }
+
+ if (tokens[current].Type == TokenType.CloseParen)
+ {
+ return GetOptionsForMethodReturnType(tokens, current, methodChainIncludesOrderBy, partial);
+ }
+
+ return Empty;
+ }
+
+ private static bool IsAMethodThatReturnsAQuery(string identifier)
+ {
+ return identifier.StartsWith("FindAll", StringComparison.CurrentCultureIgnoreCase)
+ || identifier.Equals("All", StringComparison.CurrentCultureIgnoreCase)
+ || identifier.StartsWith("Query", StringComparison.CurrentCultureIgnoreCase);
+ }
+
+ private IEnumerable<string> GetOptionsImpl(string partial, Token token, object db)
+ {
+ if (token.Value == db)
+ {
+ return DatabaseOptions()
+ .Select(Prettify)
+ .Where(s => s.StartsWith(partial, StringComparison.CurrentCultureIgnoreCase))
+ .OrderBy(s => s);
+ }
+
+ return TableOptions(token.Value.ToString())
+ .Where(s => s.StartsWith(partial, StringComparison.CurrentCultureIgnoreCase))
+ .OrderBy(s => s);
+ }
+
+ private IEnumerable<string> TableOptions(string tableName)
+ {
+ Table table = _schemaProvider.GetTables()
+ .Where(t => Prettify(t.ActualName) == Prettify(tableName))
+ .SingleOrDefault();
+
+ if (table == null) yield break;
+
+ yield return "All";
+ yield return "Query";
+
+ foreach (var column in _schemaProvider.GetColumns(table).Select(c => Prettify(c.ActualName)))
+ {
+ yield return column;
yield return "FindBy" + column;
yield return "FindAllBy" + column;
- }
- }
-
- private IEnumerable<string> DatabaseOptions()
- {
- foreach (var table in _schemaProvider.GetTables())
- {
- yield return table.ActualName;
- }
-
- foreach (var storedProcedure in _schemaProvider.GetStoredProcedures())
- {
- yield return storedProcedure.Name;
- }
- }
-
- private static string Prettify(string source)
- {
- if (!NonAlphaNumeric.IsMatch(source)) return source;
-
- var builder = new StringBuilder();
- foreach (var word in NonAlphaNumeric.Replace(source, " ").Split(' '))
- {
- builder.Append(char.ToUpper(word[0]));
- builder.Append(word.Substring(1).ToLower());
- }
-
- return builder.ToString();
- }
- }
+ }
+ }
+
+ private IEnumerable<string> QueryOptions(string tableName, bool includeThenBy)
+ {
+ yield return "Select";
+ yield return "Where";
+ yield return "ReplaceWhere";
+ if (includeThenBy)
+ {
+ yield return "ThenBy";
+ yield return "ThenByDescending";
+ }
+ else
+ {
+ yield return "OrderBy";
+ yield return "OrderByDescending";
+ }
+ yield return "Skip";
+ yield return "Take";
+ yield return "Join";
+
+ Table table = _schemaProvider.GetTables()
+ .Where(t => Prettify(t.ActualName) == Prettify(tableName))
+ .SingleOrDefault();
+
+ if (table == null) yield break;
+ foreach (var column in _schemaProvider.GetColumns(table).Select(c => Prettify(c.ActualName)))
+ {
+ if (includeThenBy)
+ {
+ yield return "ThenBy" + column;
+ yield return "ThenBy" + column + "Descending";
+ }
+ else
+ {
+ yield return "OrderBy" + column;
+ yield return "OrderBy" + column + "Descending";
+ }
+ }
+ }
+
+ private IEnumerable<string> DatabaseOptions()
+ {
+ foreach (var table in _schemaProvider.GetTables())
+ {
+ yield return table.ActualName;
+ }
+
+ foreach (var storedProcedure in _schemaProvider.GetStoredProcedures())
+ {
+ yield return storedProcedure.Name;
+ }
+ }
+
+ private static string Prettify(string source)
+ {
+ return PrettifiedCache.GetOrAdd(source, PrettifyImpl);
+ }
+
+ private static string PrettifyImpl(string source)
+ {
+ if (!NonAlphaNumeric.IsMatch(source)) return source;
+
+ var builder = new StringBuilder();
+ foreach (var word in NonAlphaNumeric.Replace(source, " ").Split(' '))
+ {
+ builder.Append(char.ToUpper(word[0]));
+ builder.Append(word.Substring(1).ToLower());
+ }
+
+ return builder.ToString();
+ }
+ }
}
View
17 Simple.Data.Pad/DatabaseSelector.xaml
@@ -2,30 +2,39 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- mc:Ignorable="d" d:DesignHeight="32" d:DesignWidth="727">
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:Pad="clr-namespace:Simple.Data.Pad"
+ mc:Ignorable="d" d:DesignHeight="40" d:DesignWidth="727">
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVis"/>
+ <Pad:MethodInfoToStringConverter x:Key="MethodInfoToString"/>
+ <Style TargetType="Label">
+ <Setter Property="VerticalAlignment" Value="Center"/>
+ </Style>
</UserControl.Resources>
<Grid>
<StackPanel Orientation="Horizontal" Margin="2 4">
<ComboBox ItemsSource="{Binding Methods}"
SelectedItem="{Binding SelectedMethod}"
- MinWidth="100">
+ MinWidth="100"
+ Margin="4">
<ComboBox.ItemTemplate>
<DataTemplate>
- <TextBlock Text="{Binding Name}"/>
+ <TextBlock Text="{Binding Name}">
+ <ToolTipService.ToolTip><TextBlock Text="{Binding Converter={StaticResource ResourceKey=MethodInfoToString}}"/></ToolTipService.ToolTip>
+ </TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<Label FontSize="12">(</Label>
<TextBox MinWidth="100"
Text="{Binding Parameter1}"
+ Margin="4"
Visibility="{Binding HasParameter1, Converter={StaticResource ResourceKey=BoolToVis}}"/>
<Label FontSize="12"
Visibility="{Binding HasParameter2, Converter={StaticResource ResourceKey=BoolToVis}}">,</Label>
<TextBox MinWidth="100"
Text="{Binding Parameter2}"
+ Margin="4"
Visibility="{Binding HasParameter2, Converter={StaticResource ResourceKey=BoolToVis}}"/>
<Label FontSize="12">)</Label>
</StackPanel>
View
BIN  Simple.Data.Pad/Images/Icon.ico
Binary file not shown
View
BIN  Simple.Data.Pad/Images/database_go.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
533 Simple.Data.Pad/MainViewModel.cs
@@ -1,126 +1,125 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-namespace Simple.Data.Pad
-{
- using System.Collections;
- using System.Data;
- using System.Diagnostics;
- using System.Reflection;
- using System.Timers;
- using System.Windows.Input;
- using System.Windows.Media;
- using Interop;
-
- public class MainViewModel : ViewModelBase
- {
- private readonly ICommand _runCommand;
- private readonly Timer _timer;
- private AutoCompleter _autoCompleter = new AutoCompleter(null);
-
- public MainViewModel()
- {
- _databaseSelectorViewModel = new DatabaseSelectorViewModel();
- LoadSettings();
- _databaseSelectorViewModel.PropertyChanged += DatabaseSelectorViewModelPropertyChanged;
- _runCommand = new ActionCommand(RunImpl);
- _timer = new Timer(500) { AutoReset = false };
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Simple.Data.Pad
+{
+ using System.Collections;
+ using System.Data;
+ using System.Diagnostics;
+ using System.Reflection;
+ using System.Timers;
+ using System.Windows.Input;
+ using System.Windows.Media;
+ using Ado.Schema;
+ using Interop;
+
+ public class MainViewModel : ViewModelBase
+ {
+ private readonly ICommand _runCommand;
+ private readonly Timer _timer;
+ private AutoCompleter _autoCompleter = new AutoCompleter(null as ISchemaProvider);
+
+ public MainViewModel()
+ {
+ _databaseSelectorViewModel = new DatabaseSelectorViewModel();
+ LoadSettings();
+ _databaseSelectorViewModel.PropertyChanged += DatabaseSelectorViewModelPropertyChanged;
+ _runCommand = new ActionCommand(RunImpl);
+ _timer = new Timer(500) { AutoReset = false };
_timer.Elapsed += TimerElapsed;
- Trace.Listeners.Add(new ActionTraceListener(s => TraceOutput += s));
- }
-
- void TimerElapsed(object sender, ElapsedEventArgs e)
- {
- try
- {
- _autoCompleter = new AutoCompleter(CreateDatabase());
- }
- catch (Exception)
- {
- Trace.WriteLine("Failed to open database.");
- }
- }
-
- void DatabaseSelectorViewModelPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
- {
- _timer.Stop();
- _timer.Start();
- }
-
- private void LoadSettings()
- {
- if (Properties.Settings.Default.UpgradeRequired)
- {
- Properties.Settings.Default.Upgrade();
- Properties.Settings.Default.Save();
- }
- QueryText = Properties.Settings.Default.LastQuery;
- _databaseSelectorViewModel.SelectedMethod = _databaseSelectorViewModel.Methods
- .FirstOrDefault(
- m =>
- m.Name.Equals(Properties.Settings.Default.OpenMethod) &&
- m.GetParameters().Length == Properties.Settings.Default.OpenMethodParameterCount);
- _databaseSelectorViewModel.Parameter1 = Properties.Settings.Default.OpenMethodParameter1;
- _databaseSelectorViewModel.Parameter2 = Properties.Settings.Default.OpenMethodParameter2;
-
- try
- {
- _autoCompleter = new AutoCompleter(CreateDatabase());
- }
- catch (Exception)
- {
- Trace.WriteLine("Failed to open database.");
- }
- }
-
- private void SaveSettings()
- {
- Properties.Settings.Default.LastQuery = QueryText;
- Properties.Settings.Default.OpenMethod = _databaseSelectorViewModel.SelectedMethod.Name;
- Properties.Settings.Default.OpenMethodParameterCount =
- _databaseSelectorViewModel.SelectedMethod.GetParameters().Length;
- Properties.Settings.Default.OpenMethodParameter1 = _databaseSelectorViewModel.Parameter1;
- Properties.Settings.Default.OpenMethodParameter2 = _databaseSelectorViewModel.Parameter2;
- Properties.Settings.Default.Save();
- }
-
- public string WindowTitle
- {
- get
- {
- return string.Format("Simple.Data.Pad {0}",
- Assembly.GetAssembly(typeof(Database)).GetName().Version.ToString(3));
- }
- }
-
- private string _queryText;
-
- public ICommand Run
- {
- get { return _runCommand; }
- }
-
- private readonly DatabaseSelectorViewModel _databaseSelectorViewModel;
-
- public DatabaseSelectorViewModel DatabaseSelectorViewModel
- {
- get { return _databaseSelectorViewModel; }
- }
-
- public int CursorPosition { get; set; }
-
- public string QueryText
- {
- get { return _queryText; }
- set
- {
- if (Set(ref _queryText, value, "QueryText"))
- {
- RaisePropertyChanged("AutoCompleteOptions");
- }
- }
+ Trace.Listeners.Add(new ActionTraceListener(message => TraceOutput += message));
+ }
+
+ void TimerElapsed(object sender, ElapsedEventArgs e)
+ {
+ try
+ {
+ _autoCompleter = new AutoCompleter(CreateDatabase());
+ }
+ catch (Exception)
+ {
+ Trace.WriteLine("Failed to open database.");
+ }
+ }
+
+ void DatabaseSelectorViewModelPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
+ {
+ _timer.Stop();
+ _timer.Start();
+ }
+
+ private void LoadSettings()
+ {
+ if (Properties.Settings.Default.UpgradeRequired)
+ {
+ Properties.Settings.Default.Upgrade();
+ Properties.Settings.Default.Save();
+ }
+ _databaseSelectorViewModel.SelectedMethod = _databaseSelectorViewModel.Methods
+ .FirstOrDefault(
+ m =>
+ m.Name.Equals(Properties.Settings.Default.OpenMethod) &&
+ m.GetParameters().Length == Properties.Settings.Default.OpenMethodParameterCount);
+ _databaseSelectorViewModel.Parameter1 = Properties.Settings.Default.OpenMethodParameter1;
+ _databaseSelectorViewModel.Parameter2 = Properties.Settings.Default.OpenMethodParameter2;
+
+ try
+ {
+ _autoCompleter = new AutoCompleter(CreateDatabase());
+ }
+ catch (Exception)
+ {
+ Trace.WriteLine("Failed to open database.");
+ }
+ }
+
+ private void SaveSettings()
+ {
+ Properties.Settings.Default.OpenMethod = _databaseSelectorViewModel.SelectedMethod.Name;
+ Properties.Settings.Default.OpenMethodParameterCount =
+ _databaseSelectorViewModel.SelectedMethod.GetParameters().Length;
+ Properties.Settings.Default.OpenMethodParameter1 = _databaseSelectorViewModel.Parameter1;
+ Properties.Settings.Default.OpenMethodParameter2 = _databaseSelectorViewModel.Parameter2;
+ Properties.Settings.Default.Save();
+ }
+
+ public string WindowTitle
+ {
+ get
+ {
+ return string.Format("Simple.Data.Pad {0}",
+ Assembly.GetAssembly(typeof(Database)).GetName().Version.ToString(3));
+ }
+ }
+
+ private string _queryText;
+
+ public ICommand Run
+ {
+ get { return _runCommand; }
+ }
+
+ private readonly DatabaseSelectorViewModel _databaseSelectorViewModel;
+
+ public DatabaseSelectorViewModel DatabaseSelectorViewModel
+ {
+ get { return _databaseSelectorViewModel; }
+ }
+
+ public int CursorPosition { get; set; }
+
+ public string QueryText
+ {
+ get { return _queryText; }
+ set
+ {
+ if (Set(ref _queryText, value, "QueryText"))
+ {
+ RaisePropertyChanged("AutoCompleteOptions");
+ }
+ }
}
public string TraceOutput
@@ -131,148 +130,160 @@ public string TraceOutput
Set(ref _traceOutput, value, "TraceOutput");
}
}
- private string _resultText;
- public string ResultText
- {
- get { return _resultText; }
- set
- {
- Set(ref _resultText, value, "ResultText");
- }
- }
-
- private Color _resultColor;
- public Color ResultColor
- {
- get { return _resultColor; }
- set
- {
- Set(ref _resultColor, value, "ResultColor");
- }
- }
-
- private bool _dataAvailable;
- public bool DataAvailable
- {
- get { return _dataAvailable; }
- set
- {
- Set(ref _dataAvailable, value, "DataAvailable");
- }
- }
-
+ private string _resultText;
+ public string ResultText
+ {
+ get { return _resultText; }
+ set
+ {
+ Set(ref _resultText, value, "ResultText");
+ }
+ }
+
+ private Color _resultColor;
+ public Color ResultColor
+ {
+ get { return _resultColor; }
+ set
+ {
+ Set(ref _resultColor, value, "ResultColor");
+ }
+ }
+
+ private bool _dataAvailable;
+ public bool DataAvailable
+ {
+ get { return _dataAvailable; }
+ set
+ {
+ Set(ref _dataAvailable, value, "DataAvailable");
+ }
+ }
+
private object _data;
private string _traceOutput;
- public object Data
- {
- get { return _data; }
- set
- {
- Set(ref _data, value, "Data");
- }
- }
-
- public IEnumerable<string> AutoCompleteOptions
- {
+ public object Data
+ {
+ get { return _data; }
+ set
+ {
+ Set(ref _data, value, "Data");
+ }
+ }
+
+ public string QueryTextToCursor
+ {
+ get { return QueryText.Substring(0, Math.Min(CursorPosition + 1, QueryText.Length)); }
+ }
+
+ public IEnumerable<string> AutoCompleteOptions
+ {
get
{
- return QueryText.Length > CursorPosition
- ? _autoCompleter.GetOptions(QueryText.Substring(0, CursorPosition + 1))
- : Enumerable.Empty<string>();
- }
- }
-
- void RunImpl()
- {
+ if (QueryText.Length >= CursorPosition)
+ {
+ return _autoCompleter.GetOptions(QueryTextToCursor);
+ }
+ return Enumerable.Empty<string>();
+ }
+ }
+
+ public void ForceAutoCompleteOptionsUpdate()
+ {
+ RaisePropertyChanged("AutoCompleteOptions");
+ }
+
+ void RunImpl()
+ {
SaveSettings();
- TraceOutput = string.Empty;
-
- var database = CreateDatabase();
- var executor = new QueryExecutor(_queryText);
- object result;
- DataAvailable = executor.CompileAndRun(database, out result);
- ResultColor = DataAvailable ? Colors.Black : Colors.Red;
- Data = FormatResult(result);
- }
-
- private Database CreateDatabase()
- {
- var method = DatabaseSelectorViewModel.SelectedMethod;
- var parameters = BuildParameters(method);
- var database = method.Invoke(Database.Opener, parameters) as Database;
- return database;
- }
-
- private string[] BuildParameters(MethodInfo method)
- {
- string[] parameters;
- if (method.GetParameters().Length == 1)
- {
- parameters = new[] { DatabaseSelectorViewModel.Parameter1 };
- }
- else if (method.GetParameters().Length == 2)
- {
- parameters = new[] { DatabaseSelectorViewModel.Parameter1, DatabaseSelectorViewModel.Parameter2 };
- }
- else
- {
- parameters = new string[0];
- }
- return parameters;
- }
-
- private static object FormatResult(object result)
- {
- if (result == null) return "No results found.";
-
- if (result is SimpleRecord)
- {
- return FormatDictionary(result as IDictionary<string, object>);
- }
-
- if (result is SimpleQuery)
- {
- return FormatQuery(result as SimpleQuery);
- }
-
- return result.ToString();
- }
-
- private static object FormatQuery(SimpleQuery simpleQuery)
- {
- var list = simpleQuery.ToList();
- if (list.Count == 0) return "No matching records.";
-
- var firstRow = list.FirstOrDefault() as IDictionary<string, object>;
- if (firstRow == null) throw new InvalidOperationException();
-
- var table = new DataTable();
- foreach (var kvp in firstRow)
- {
- table.Columns.Add(kvp.Key);
- }
-
- foreach (var row in list.Cast<IDictionary<string,object>>())
- {
- table.Rows.Add(row.Values.ToArray());
- }
-
- return table.DefaultView;
- }
-
- private static object FormatDictionary(IEnumerable<KeyValuePair<string, object>> dictionary)
- {
- var table = new DataTable();
- table.Columns.Add("Property");
- table.Columns.Add("Value");
-
- foreach (var kvp in dictionary)
- {
- table.Rows.Add(kvp.Key, kvp.Value);
- }
-
- return table.DefaultView;
- }
- }
-}
+ TraceOutput = string.Empty;
+
+ var database = CreateDatabase();
+ var executor = new QueryExecutor(_queryText);
+ object result;
+ DataAvailable = executor.CompileAndRun(database, out result);
+ ResultColor = DataAvailable ? Colors.Black : Colors.Red;
+ Data = FormatResult(result);
+ }
+
+ private Database CreateDatabase()
+ {
+ var method = DatabaseSelectorViewModel.SelectedMethod;
+ var parameters = BuildParameters(method);
+ var database = method.Invoke(Database.Opener, parameters) as Database;
+ return database;
+ }
+
+ private string[] BuildParameters(MethodInfo method)
+ {
+ string[] parameters;
+ if (method.GetParameters().Length == 1)
+ {
+ parameters = new[] { DatabaseSelectorViewModel.Parameter1 };
+ }
+ else if (method.GetParameters().Length == 2)
+ {
+ parameters = new[] { DatabaseSelectorViewModel.Parameter1, DatabaseSelectorViewModel.Parameter2 };
+ }
+ else
+ {
+ parameters = new string[0];
+ }
+ return parameters;
+ }
+
+ private static object FormatResult(object result)
+ {
+ if (result == null) return "No results found.";
+
+ if (result is SimpleRecord)
+ {
+ return FormatDictionary(result as IDictionary<string, object>);
+ }
+
+ if (result is SimpleQuery)
+ {
+ return FormatQuery(result as SimpleQuery);
+ }
+
+ return result.ToString();
+ }
+
+ private static object FormatQuery(SimpleQuery simpleQuery)
+ {
+ var list = simpleQuery.ToList();
+ if (list.Count == 0) return "No matching records.";
+
+ var firstRow = list.FirstOrDefault() as IDictionary<string, object>;
+ if (firstRow == null) throw new InvalidOperationException();
+
+ var table = new DataTable();
+ foreach (var kvp in firstRow)
+ {
+ table.Columns.Add(kvp.Key);
+ }
+
+ foreach (var row in list.Cast<IDictionary<string,object>>())
+ {
+ table.Rows.Add(row.Values.ToArray());
+ }
+
+ return table.DefaultView;
+ }
+
+ private static object FormatDictionary(IEnumerable<KeyValuePair<string, object>> dictionary)
+ {
+ var table = new DataTable();
+ table.Columns.Add("Property");
+ table.Columns.Add("Value");
+
+ foreach (var kvp in dictionary)
+ {
+ table.Rows.Add(kvp.Key, kvp.Value);
+ }
+
+ return table.DefaultView;
+ }
+ }
+}
View
206 Simple.Data.Pad/MainWindow.xaml
@@ -1,93 +1,115 @@
-<Window x:Class="Simple.Data.Pad.MainWindow"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- Title="{Binding WindowTitle}" Height="350" Width="525"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:pad="clr-namespace:Simple.Data.Pad"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d"
- KeyUp="MainWindowKeyUp">
- <Window.Resources>
- <BooleanToVisibilityConverter x:Key="BoolToVis"/>
- </Window.Resources>
- <Grid>
- <Grid.RowDefinitions>
- <RowDefinition Height="Auto"/>
- <RowDefinition Height="*"/>
- <RowDefinition Height="Auto"/>
- <RowDefinition Height="*"/>
- <RowDefinition Height="Auto"/>
- </Grid.RowDefinitions>
- <StackPanel Grid.Row="0">
- <pad:DatabaseSelector DataContext="{Binding DatabaseSelectorViewModel}" Height="32"/>
- <StackPanel Orientation="Horizontal">
- <Button Command="{Binding Run}" Margin="2" Padding="8 2">Run</Button>
- </StackPanel>
- </StackPanel>
- <Grid Grid.Row="1">
- <Grid.ColumnDefinitions>
- <ColumnDefinition Width="*"/>
- <ColumnDefinition Width="150"/>
- </Grid.ColumnDefinitions>
- <TextBox Grid.Column="0"
- x:Name="QueryTextBox"
- FontFamily="Consolas,Lucida Console,Courier New"
- AcceptsReturn="True"
- AcceptsTab="True"
- VerticalAlignment="Stretch"
- Text="{Binding QueryText, UpdateSourceTrigger=PropertyChanged}"
- SelectionChanged="TextBoxSelectionChanged"
- TextChanged="QueryTextBoxTextChanged"/>
- </Grid>
- <GridSplitter Grid.Row="2" Height="4"/>
- <TabControl Grid.Row="3"
- TabStripPlacement="Bottom">
- <TabItem Header="Results">
- <Grid>
- <DataGrid ItemsSource="{Binding Data}"
- AutoGenerateColumns="True"
- HorizontalGridLinesBrush="LightGray"
- VerticalGridLinesBrush="LightGray"
- Visibility="{Binding DataAvailable, Converter={StaticResource ResourceKey=BoolToVis}}"/>
- <TextBlock Grid.Row="3"
- FontFamily="Consolas,Lucida Console,Courier New"
- Text="{Binding ResultText}"/>
+<Window x:Class="Simple.Data.Pad.MainWindow"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:pad="clr-namespace:Simple.Data.Pad"
+ Height="480"
+ Width="640"
+ KeyUp="MainWindowKeyUp"
+ Title="{Binding WindowTitle}"
+ mc:Ignorable="d"
+ Icon="/Simple.Data.Pad;component/Images/Icon.ico">
+ <Window.Resources>
+ <BooleanToVisibilityConverter x:Key="BoolToVis" />
+ </Window.Resources>
+ <Grid>
+ <Grid.RowDefinitions>
+ <RowDefinition Height="Auto" />
+ <RowDefinition Height="*" />
+ <RowDefinition Height="Auto" />
+ <RowDefinition Height="*" />
+ <RowDefinition Height="Auto" />
+ </Grid.RowDefinitions>
+ <StackPanel Grid.Row="0">
+ <GroupBox Header="Connection">
+ <pad:DatabaseSelector Height="40"
+ DataContext="{Binding DatabaseSelectorViewModel}" />
+ </GroupBox>
+ <StackPanel Orientation="Horizontal">
+ <Button Margin="2"
+ Padding="8 2"
+ Command="{Binding Run}">
+ <StackPanel Orientation="Horizontal">
+ <Image Source="Images/database_go.png" />
+ <TextBlock Margin="4">Run</TextBlock>
+ </StackPanel>
+ </Button>
+ </StackPanel>
+ </StackPanel>
+ <Grid Grid.Row="1">
+ <TextBox x:Name="QueryTextBox"
+ Margin="4"
+ AcceptsReturn="True"
+ AcceptsTab="True"
+ FontFamily="Consolas,Lucida Console,Courier New"
+ Text="{Binding QueryText, UpdateSourceTrigger=PropertyChanged}"
+ TextChanged="QueryTextBoxTextChanged"
+ SelectionChanged="QueryTextBoxSelectionChanged"
+ VerticalAlignment="Stretch" />
+ </Grid>
+ <GridSplitter Grid.Row="2"
+ Height="4" />
+ <TabControl Grid.Row="3"
+ Margin="4"
+ TabStripPlacement="Bottom">
+ <TabItem Header="Results">
+ <Grid Margin="2">
+ <DataGrid AutoGenerateColumns="True"
+ HorizontalGridLinesBrush="LightGray"
+ ItemsSource="{Binding Data}"
+ VerticalGridLinesBrush="LightGray"
+ Visibility="{Binding DataAvailable, Converter={StaticResource ResourceKey=BoolToVis}}" />
+ <TextBlock Grid.Row="3"
+ FontFamily="Consolas,Lucida Console,Courier New"
+ Text="{Binding ResultText}" />
</Grid>
- </TabItem>
- <TabItem Header="Trace">
- <TextBlock Text="{Binding TraceOutput}"/>
- </TabItem>
- </TabControl>
- <Popup x:Name="AutoCompletePopup" PlacementTarget="{Binding ElementName=QueryTextBox}" Placement="Relative" AllowsTransparency="True">
- <Border BorderThickness="0.1" Margin="0 0 8 8">
- <ListBox x:Name="AutoCompleteListBox"
- MinWidth="160"
- MinHeight="40"
- FontFamily="Consolas,Lucida Console,Courier New"
- ItemsSource="{Binding AutoCompleteOptions}"
- MouseUp="ListBoxMouseUp"
- SelectionChanged="AutoCompleteListBox_OnSelectionChanged">
- <ListBox.Resources>
- <Style TargetType="ListBoxItem">
- <Setter Property="Template">
- <Setter.Value>
- <ControlTemplate TargetType="ListBoxItem">
- <Border Name="Border" Padding="2" SnapsToDevicePixels="true">
- <ContentPresenter />
- </Border>
- <ControlTemplate.Triggers>
- <Trigger Property="IsSelected" Value="true">
- <Setter TargetName="Border" Property="Background"
- Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
- </Trigger>
- </ControlTemplate.Triggers>
- </ControlTemplate>
- </Setter.Value>
- </Setter>
- </Style>
- </ListBox.Resources>
-
- </ListBox>
- </Border>
- </Popup>
- </Grid>
-</Window>
+ </TabItem>
+ <TabItem Header="Trace">
+ <TextBox Text="{Binding TraceOutput}"
+ FontFamily="Consolas,Lucida Console,Courier New"
+ TextWrapping="Wrap"/>
+ </TabItem>
+ </TabControl>
+ <Popup x:Name="AutoCompletePopup"
+ AllowsTransparency="True"
+ Placement="Relative"
+ PlacementTarget="{Binding ElementName=QueryTextBox}"
+ MinWidth="160"
+ MinHeight="40">
+ <Border Margin="0 0 8 8"
+ BorderThickness="0.1">
+ <ListBox x:Name="AutoCompleteListBox"
+ FontFamily="Consolas,Lucida Console,Courier New"
+ ItemsSource="{Binding AutoCompleteOptions}"
+ MouseUp="ListBoxMouseUp"
+ SelectionChanged="AutoCompleteListBox_OnSelectionChanged">
+ <ListBox.Resources>
+ <Style TargetType="ListBoxItem">
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="ListBoxItem">
+ <Border Padding="2"
+ Name="Border"
+ SnapsToDevicePixels="true">
+ <ContentPresenter />
+ </Border>
+ <ControlTemplate.Triggers>
+ <Trigger Property="IsSelected"
+ Value="true">
+ <Setter Property="Background"
+ TargetName="Border"
+ Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" />
+ </Trigger>
+ </ControlTemplate.Triggers>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+ </ListBox.Resources>
+
+ </ListBox>
+ </Border>
+ </Popup>
+ </Grid>
+</Window>
View
49 Simple.Data.Pad/MainWindow.xaml.cs
@@ -25,6 +25,9 @@ public partial class MainWindow : Window
private static readonly string[] NewlineSplitArg = new[] { Environment.NewLine };
private readonly Typeface _typeface;
private readonly MainViewModel _viewModel;
+
+ private bool _deferKeyUp;
+
public MainWindow()
{
InitializeComponent();
@@ -37,16 +40,33 @@ public MainWindow()
void AutoCompletePopupClosed(object sender, EventArgs e)
{
- PreviewKeyUp -= MainWindowPreviewKeyUp;
+ QueryTextBox.PreviewKeyUp -= MainWindowPreviewKeyUp;
+ QueryTextBox.PreviewTextInput -= QueryTextBoxPreviewTextInput;
}
void AutoCompletePopupOpened(object sender, EventArgs e)
{
- PreviewKeyUp += MainWindowPreviewKeyUp;
+ _deferKeyUp = true;
+ QueryTextBox.PreviewKeyUp += MainWindowPreviewKeyUp;
+ QueryTextBox.PreviewTextInput += QueryTextBoxPreviewTextInput;
+ }
+
+ void QueryTextBoxPreviewTextInput(object sender, TextCompositionEventArgs e)
+ {
+ if (e.Text == "." || e.Text == "(")
+ {
+ SelectAutoCompleteText(e.Text);
+ e.Handled = true;
+ }
}
void MainWindowPreviewKeyUp(object sender, KeyEventArgs e)
{
+ if (_deferKeyUp)
+ {
+ _deferKeyUp = false;
+ return;
+ }
if (e.Key == Key.Down)
{
if (AutoCompleteListBox.SelectedIndex + 1 < AutoCompleteListBox.Items.Count)
@@ -95,7 +115,7 @@ private void OpenPopup()
AutoCompletePopup.Width = options.Select(s => s.Length*8).Max() + 8;
AutoCompletePopup.Height = Math.Min((options.Length*16) + 16, 200) + 8;
- var text = _viewModel.QueryText.Substring(0, _viewModel.CursorPosition + 1);
+ var text = _viewModel.QueryTextToCursor;
var formattedText = new FormattedText(text, CultureInfo.CurrentUICulture, FlowDirection.LeftToRight,
_typeface, QueryTextBox.FontSize, Brushes.Black);
AutoCompletePopup.VerticalOffset = formattedText.Height + 4;
@@ -113,16 +133,14 @@ void MainWindowKeyUp(object sender, KeyEventArgs e)
if (e.Key == Key.F5) _viewModel.Run.Execute(null);
}
- private void TextBoxSelectionChanged(object sender, RoutedEventArgs e)
+ private void QueryTextBoxSelectionChanged(object sender, RoutedEventArgs e)
{
- var textBox = ((TextBox) sender);
- _viewModel.CursorPosition = textBox.SelectionStart + textBox.SelectionLength;
+ _viewModel.CursorPosition = QueryTextBox.CaretIndex;
}
private void QueryTextBoxTextChanged(object sender, RoutedEventArgs e)
{
- var textBox = ((TextBox)sender);
- _viewModel.CursorPosition = textBox.SelectionStart + textBox.SelectionLength;
+ _viewModel.CursorPosition = QueryTextBox.CaretIndex;
}
private void ListBoxMouseUp(object sender, RoutedEventArgs e)
@@ -130,7 +148,7 @@ private void ListBoxMouseUp(object sender, RoutedEventArgs e)
SelectAutoCompleteText();
}
- private void SelectAutoCompleteText()
+ private void SelectAutoCompleteText(string andAppend = "")
{
var selected = AutoCompleteListBox.SelectedItem;
while (QueryTextBox.SelectedText.FirstOrDefault() != '.')
@@ -138,10 +156,19 @@ private void SelectAutoCompleteText()
QueryTextBox.SelectionStart -= 1;
QueryTextBox.SelectionLength += 1;
}
- QueryTextBox.SelectedText = "." + selected;
+ QueryTextBox.SelectedText = "." + selected + andAppend;
QueryTextBox.SelectionStart += QueryTextBox.SelectionLength;
QueryTextBox.SelectionLength = 0;
- AutoCompletePopup.IsOpen = false;
+ QueryTextBox.CaretIndex = QueryTextBox.SelectionStart;
+ _viewModel.CursorPosition = QueryTextBox.CaretIndex;
+ if (andAppend != ".")
+ {
+ AutoCompletePopup.IsOpen = false;
+ }
+ else
+ {
+ _viewModel.ForceAutoCompleteOptionsUpdate();
+ }
}
private void AutoCompleteListBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
View
31 Simple.Data.Pad/MethodInfoToStringConverter.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Simple.Data.Pad
+{
+ using System.Globalization;
+ using System.Reflection;
+ using System.Windows.Data;
+
+ public class MethodInfoToStringConverter : IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ var methodInfo = value as MethodInfo;
+ if (methodInfo == null)
+ {
+ return string.Empty;
+ }
+
+ return string.Format("{0}({1})", methodInfo.Name,
+ string.Join(", ", methodInfo.GetParameters().Select(p => p.Name)));
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
View
BIN  Simple.Data.Pad/Release/Simple.Data.Ado.dll
Binary file not shown
View
BIN  Simple.Data.Pad/Release/Simple.Data.Interop.dll
Binary file not shown
View
BIN  Simple.Data.Pad/Release/Simple.Data.Interop.pdb
Binary file not shown
View
BIN  Simple.Data.Pad/Release/Simple.Data.Pad-1.0.zip
Binary file not shown
View
BIN  Simple.Data.Pad/Release/Simple.Data.Pad.exe
Binary file not shown
View
30 Simple.Data.Pad/Release/Simple.Data.Pad.exe.config
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+ <configSections>
+ <sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
+ <section name="Simple.Data.Pad.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
+ </sectionGroup>
+ </configSections>
+ <userSettings>
+ <Simple.Data.Pad.Properties.Settings>
+ <setting name="OpenMethod" serializeAs="String">
+ <value>OpenConnection</value>
+ </setting>
+ <setting name="OpenMethodParameterCount" serializeAs="String">
+ <value>1</value>
+ </setting>
+ <setting name="OpenMethodParameter1" serializeAs="String">
+ <value>ConnectionString</value>
+ </setting>
+ <setting name="OpenMethodParameter2" serializeAs="String">
+ <value />
+ </setting>
+ <setting name="UpgradeRequired" serializeAs="String">
+ <value>True</value>
+ </setting>
+ <setting name="LastQuery" serializeAs="String">
+ <value />
+ </setting>
+ </Simple.Data.Pad.Properties.Settings>
+ </userSettings>
+</configuration>
View
BIN  Simple.Data.Pad/Release/Simple.Data.Pad.pdb
Binary file not shown
View
BIN  Simple.Data.Pad/Release/Simple.Data.SqlServer.dll
Binary file not shown
View
BIN  Simple.Data.Pad/Release/Simple.Data.dll
Binary file not shown
View
10 Simple.Data.Pad/Simple.Data.Pad.csproj
@@ -35,6 +35,9 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
+ <PropertyGroup>
+ <ApplicationIcon>Images\Icon.ico</ApplicationIcon>
+ </PropertyGroup>
<ItemGroup>
<Reference Include="Simple.Data">
<HintPath>..\packages\Simple.Data.Core.0.7.2\lib\net40\Simple.Data.dll</HintPath>
@@ -71,6 +74,7 @@
</Compile>
<Compile Include="DatabaseSelectorViewModel.cs" />
<Compile Include="ActionTraceListener.cs" />
+ <Compile Include="MethodInfoToStringConverter.cs" />
<Compile Include="ViewModelBase.cs" />
<Page Include="DatabaseSelector.xaml">
<SubType>Designer</SubType>
@@ -123,6 +127,12 @@
<Name>Simple.Data.Interop</Name>
</ProjectReference>
</ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\database_go.png" />
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\Icon.ico" />
+ </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
View
1  packages/repositories.config
@@ -3,4 +3,5 @@
<repository path="..\Simple.Data.Pad\packages.config" />
<repository path="..\Simple.Data.Interop.Test\packages.config" />
<repository path="..\Simple.Data.Interop\packages.config" />
+ <repository path="..\Simple.Data.Pad.Test\packages.config" />
</repositories>
Please sign in to comment.
Something went wrong with that request. Please try again.