Permalink
Browse files

resolve embedded variables before pagination rewriting.

  • Loading branch information...
1 parent 708971e commit a06d3f6bfc51a0f7f63547f78565574d6afa8dd8 Toshihiro Nakamura committed Feb 2, 2012
Showing with 144 additions and 74 deletions.
  1. +9 −0 Soma.Core.IT.MsSql/PaginateTest.fs
  2. +7 −0 Soma.Core.UT/SqlTest.fs
  3. +126 −74 Soma.Core/Sql.fs
  4. +1 −0 Soma.Core/Sql.fsi
  5. +1 −0 Soma.sln
@@ -62,6 +62,15 @@ module PaginateTest =
employees |> Seq.iter (printfn "%A")
assert_equal 2 employees.Length
+ [<Test>]
+ let ``paginate : offset is positive : embedded variable in order by clause``() =
+ let employees =
+ MsSql.paginate<Employee> "
+ select * from Employee E order by /*#orderby*/
+ " ["orderby" @= "E.EmployeeId"] (1L, 2L)
+ employees |> Seq.iter (printfn "%A")
+ assert_equal 2 employees.Length
+
[<Test>]
let ``paginate : offset is zero``() =
let employees =
View
@@ -923,6 +923,13 @@ module SqlTest =
assert_equal 1 ps.Parameters.Length
assert_equal (DateTime(2011, 1, 22)) ps.Parameters.[0].Value
+ [<Test>]
+ let ``resolveEmbeddedVariables`` () =
+ let sql = "select * from xxx.aaa where xxx.aaa.bbb = /* bbb */'a' order by /*#orderby*/"
+ let statement = config.SqlParser.Invoke sql
+ let sql = Sql.resolveEmbeddedVariables config statement sql (dict ["orderby", (box "xxx.aaa.ccc", typeof<string>)])
+ assert_equal "select * from xxx.aaa where xxx.aaa.bbb = /* bbb */'a' order by xxx.aaa.ccc" sql
+
type Hoge1 = {[<Id>]Id:int; Name:string; [<Version>]Version:int; }
type Hoge2 = {[<Id>]Id:int; Name:string }
type Hoge3 = {Name:string; [<Version>]Version:int}
View
@@ -140,6 +140,78 @@ type SqlException (message:Message, ?innerException:exn) =
inherit InvalidOperationException (message.Format (), match innerException with Some ex -> ex | _ -> null)
member this.MessageId = message.Id
+module RewriteHelper =
+ let writeIfComment ifComment (buf:StringBuilder) f =
+ match ifComment with
+ | IfComment(expression, nodeList, _) ->
+ buf.Append "/*% if " |> ignore
+ buf.Append expression |> ignore
+ buf.Append " */" |> ignore
+ List.fold f buf nodeList
+
+ let writeElifComment elifComment (buf:StringBuilder) f =
+ match elifComment with
+ | ElifComment(expression, nodeList, _) ->
+ buf.Append "/*% elif " |> ignore
+ buf.Append expression |> ignore
+ buf.Append " */" |> ignore
+ List.fold f buf nodeList
+
+ let writeElseComment elseComment (buf:StringBuilder) f =
+ match elseComment with
+ | ElseComment(nodeList, _) ->
+ buf.Append "/*% else */" |> ignore
+ List.fold f buf nodeList
+
+ let writeForComment forComment (buf:StringBuilder) f =
+ match forComment with
+ | ForComment(expression, nodeList, _) ->
+ buf.Append "/*% for " |> ignore
+ buf.Append expression |> ignore
+ buf.Append " */" |> ignore
+ List.fold f buf nodeList
+
+ let writeIfBlock (ifComment, elifCommentList, elseComment, nodeList) (buf:StringBuilder) f =
+ let buf = writeIfComment ifComment buf f
+ let buf = List.fold (fun buf comment -> writeElifComment comment buf f) buf elifCommentList
+ let buf =
+ match elseComment with
+ | Some comment -> writeElseComment comment buf f
+ | _ -> buf
+ buf.Append "/*% end */" |> ignore
+ List.fold f buf nodeList
+
+ let writeForBlock (forComment, nodeList) (buf:StringBuilder) f =
+ let (buf:StringBuilder) = writeForComment forComment buf f
+ buf.Append "/*% end */" |> ignore
+ List.fold f buf nodeList
+
+ let writeBindVarComment (expression:string, node) (buf:StringBuilder) f =
+ buf.Append "/* " |> ignore
+ buf.Append expression |> ignore
+ buf.Append " */" |> ignore
+ f buf node
+
+ let writeEmbeddedVarComment (expression:string) (buf:StringBuilder) =
+ buf.Append "/*# " |> ignore
+ buf.Append expression |> ignore
+ buf.Append " */" |> ignore
+ buf
+
+ let writeParens statement (level:int ref) (buf:StringBuilder) f =
+ buf.Append "(" |> ignore
+ incr level
+ let (buf:StringBuilder) = f buf statement
+ decr level
+ buf.Append ")"
+
+ let writeSet (set:string, lhs, rhs) (buf:StringBuilder) f =
+ let buf:StringBuilder = f buf lhs
+ buf.Append set |> ignore
+ f buf rhs
+
+open RewriteHelper
+
[<RequireQualifiedAccess>]
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module Sql =
@@ -431,24 +503,77 @@ module Sql =
let state = visitStatement (State(config.Dialect, exprCtxt, 0)) statement
state.Build()
+ let resolveEmbeddedVariables config statement sql exprCtxt =
+ let level = ref 0
+ let rec visitStatement (buf:StringBuilder) =
+ function
+ | Statement nodeList ->
+ List.fold visitNode buf nodeList
+ | Set(set, lhs, rhs, _) ->
+ writeSet (set, lhs, rhs) buf visitStatement
+ and visitNode (buf:StringBuilder) =
+ function
+ | Word(fragment)
+ | Other(fragment)
+ | Literal(fragment)
+ | Whitespaces(fragment)
+ | Newline(fragment)
+ | BlockComment(fragment)
+ | LineComment(fragment) ->
+ buf.Append fragment
+ | Select(keyword, nodeList, _)
+ | From(keyword, nodeList, _)
+ | Where(keyword, nodeList, _)
+ | GroupBy(keyword, nodeList, _)
+ | Having(keyword, nodeList, _)
+ | OrderBy(keyword, nodeList, _)
+ | ForUpdate(keyword, nodeList, _)
+ | And(keyword, nodeList)
+ | Or(keyword, nodeList) ->
+ buf.Append keyword |> ignore
+ List.fold visitNode buf nodeList
+ | Parens(statement) ->
+ writeParens statement level buf visitStatement
+ | BindVarComment(expression, node, _)
+ | BindVarsComment(expression, node, _) ->
+ writeBindVarComment (expression, node) buf visitNode
+ | EmbeddedVarComment(expression, loc) ->
+ let evalResult = eval config exprCtxt expression loc sql
+ buf.Append (fst evalResult)
+ | IfBlock(ifComment, elifCommentList, elseComment, nodeList) ->
+ writeIfBlock (ifComment, elifCommentList, elseComment, nodeList) buf visitNode
+ | ForBlock(forComment, nodeList) ->
+ writeForBlock (forComment, nodeList) buf visitNode
+ let buf = visitStatement (StringBuilder(200)) statement
+ buf.ToString()
+
let prepareCore (config:IDbConfig) sql exprCtxt (parser:Func<string, Statement>) =
let statement = parser.Invoke sql
- let exprCtxt = concatExprCtxt config.Dialect.RootExprCtxt exprCtxt
generate config sql exprCtxt statement
let prepare (config:IDbConfig) sql exprCtxt parser =
+ let exprCtxt = concatExprCtxt config.Dialect.RootExprCtxt exprCtxt
prepareCore config sql exprCtxt parser
let preparePaginate (config:IDbConfig) sql exprCtxt offset limit (parser:Func<string, Statement>) =
+ let statement = parser.Invoke sql
+ let exprCtxt = concatExprCtxt config.Dialect.RootExprCtxt exprCtxt
+ let sql = resolveEmbeddedVariables config statement sql exprCtxt
let statement = parser.Invoke sql
let sql, exprCtxt = config.Dialect.RewriteForPagination (statement, sql, exprCtxt, offset, limit)
+ let exprCtxt = concatExprCtxt config.Dialect.RootExprCtxt exprCtxt
prepareCore config sql exprCtxt parser
let preparePaginateAndCount (config:IDbConfig) sql exprCtxt offset limit (parser:Func<string, Statement>) =
+ let statement = parser.Invoke sql
+ let exprCtxt = concatExprCtxt config.Dialect.RootExprCtxt exprCtxt
+ let sql = resolveEmbeddedVariables config statement sql exprCtxt
let statement = parser.Invoke sql
let newSql, newExprCtxt = config.Dialect.RewriteForCalcPagination (statement, sql, exprCtxt, offset, limit)
+ let newExprCtxt = concatExprCtxt config.Dialect.RootExprCtxt newExprCtxt
let paginatePs = prepareCore config newSql newExprCtxt parser
let newSql, newExprCtxt = config.Dialect.RewriteForCount (statement, sql, exprCtxt)
+ let newExprCtxt = concatExprCtxt config.Dialect.RootExprCtxt newExprCtxt
let countPs = prepareCore config newSql newExprCtxt parser
paginatePs, countPs
@@ -623,79 +748,6 @@ module Sql =
FormattedText = config.Dialect.BuildProcedureCallSql(procedureName, parameters)
Parameters = parameters }
-module DialectHelper =
- let writeIfComment ifComment (buf:StringBuilder) f =
- match ifComment with
- | IfComment(expression, nodeList, _) ->
- buf.Append "/*% if " |> ignore
- buf.Append expression |> ignore
- buf.Append " */" |> ignore
- List.fold f buf nodeList
-
- let writeElifComment elifComment (buf:StringBuilder) f =
- match elifComment with
- | ElifComment(expression, nodeList, _) ->
- buf.Append "/*% elif " |> ignore
- buf.Append expression |> ignore
- buf.Append " */" |> ignore
- List.fold f buf nodeList
-
- let writeElseComment elseComment (buf:StringBuilder) f =
- match elseComment with
- | ElseComment(nodeList, _) ->
- buf.Append "/*% else */" |> ignore
- List.fold f buf nodeList
-
- let writeForComment forComment (buf:StringBuilder) f =
- match forComment with
- | ForComment(expression, nodeList, _) ->
- buf.Append "/*% for " |> ignore
- buf.Append expression |> ignore
- buf.Append " */" |> ignore
- List.fold f buf nodeList
-
- let writeIfBlock (ifComment, elifCommentList, elseComment, nodeList) (buf:StringBuilder) f =
- let buf = writeIfComment ifComment buf f
- let buf = List.fold (fun buf comment -> writeElifComment comment buf f) buf elifCommentList
- let buf =
- match elseComment with
- | Some comment -> writeElseComment comment buf f
- | _ -> buf
- buf.Append "/*% end */" |> ignore
- List.fold f buf nodeList
-
- let writeForBlock (forComment, nodeList) (buf:StringBuilder) f =
- let (buf:StringBuilder) = writeForComment forComment buf f
- buf.Append "/*% end */" |> ignore
- List.fold f buf nodeList
-
- let writeBindVarComment (expression:string, node) (buf:StringBuilder) f =
- buf.Append "/* " |> ignore
- buf.Append expression |> ignore
- buf.Append " */" |> ignore
- f buf node
-
- let writeEmbeddedVarComment (expression:string) (buf:StringBuilder) =
- buf.Append "/*# " |> ignore
- buf.Append expression |> ignore
- buf.Append " */" |> ignore
- buf
-
- let writeParens statement (level:int ref) (buf:StringBuilder) f =
- buf.Append "(" |> ignore
- incr level
- let (buf:StringBuilder) = f buf statement
- decr level
- buf.Append ")"
-
- let writeSet (set:string, lhs, rhs) (buf:StringBuilder) f =
- let buf:StringBuilder = f buf lhs
- buf.Append set |> ignore
- f buf rhs
-
-
-open DialectHelper
-
[<AbstractClass>]
type DialectBase() as this =
View
@@ -83,6 +83,7 @@ module Sql =
/// <returns>The parsed SQL statement.</returns>
[<CompiledName("Parse")>]
val parse : string -> Statement
+ val internal resolveEmbeddedVariables : IDbConfig -> Statement -> string -> IDictionary<string, obj * Type> -> string
val internal prepare : IDbConfig -> string -> IDictionary<string, obj * Type> -> Func<string, Statement> -> PreparedStatement
val internal preparePaginate : IDbConfig -> string -> IDictionary<string, obj * Type> -> int64 -> int64 -> Func<string, Statement> -> PreparedStatement
val internal preparePaginateAndCount : IDbConfig -> string -> IDictionary<string, obj * Type> -> int64 -> int64 -> Func<string, Statement> -> PreparedStatement * PreparedStatement
View
@@ -37,6 +37,7 @@ Global
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{007939D3-6636-4691-9ACF-4A901819EC32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {007939D3-6636-4691-9ACF-4A901819EC32}.Debug|Any CPU.Build.0 = Debug|Any CPU
{007939D3-6636-4691-9ACF-4A901819EC32}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{007939D3-6636-4691-9ACF-4A901819EC32}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{007939D3-6636-4691-9ACF-4A901819EC32}.Debug|x86.ActiveCfg = Debug|Any CPU

0 comments on commit a06d3f6

Please sign in to comment.