Last active
December 21, 2015 21:44
-
-
Save ImaginaryDevelopment/07f46bcf388fd8a75da7 to your computer and use it in GitHub Desktop.
Templatus generate F# from sql table
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |
<PropertyGroup> | |
<!-- for build server primarily --> | |
<FSharpTargetsPath Condition="'$(FSharpTargetsPath)' == '' And Exists('C:\Program Files (x86)\Microsoft SDKs\F#\4.0\Framework\v4.0\Microsoft.FSharp.Targets')">C:\Program Files (x86)\Microsoft SDKs\F#\4.0\Framework\v4.0\Microsoft.FSharp.Targets</FSharpTargetsPath> | |
<FSharpTargetsPath Condition="'$(FSharpTargetsPath)' == '' And Exists('C:\Program Files (x86)\Microsoft SDKs\F#\3.1\Framework\v4.0')">C:\Program Files (x86)\Microsoft SDKs\F#\3.1\Framework\v4.0\Microsoft.FSharp.Targets</FSharpTargetsPath> | |
<FSharpTargetsPath Condition="'$(FSharpTargetsPath)' == '' ">..\3rdParty\Microsoft.FSharp.Targets</FSharpTargetsPath> | |
<!-- love these option settings, but not required --> | |
<WarningLevel>5</WarningLevel> | |
<OtherFlags>--warnon:1182 --warnaserror-:0052</OtherFlags> | |
<TreatWarningsAsErrors>true</TreatWarningsAsErrors> | |
</PropertyGroup> | |
<Choose> | |
<When Condition="'$(VisualStudioVersion)' == '11.0'"> | |
<PropertyGroup Condition="'$(FSharpTargetsPath)' == '' And Exists('$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets')"> | |
<FSharpTargetsPath>$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets</FSharpTargetsPath> | |
</PropertyGroup> | |
</When> | |
<Otherwise> | |
<PropertyGroup Condition="'$(FSharpTargetsPath)' == '' And Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets')"> | |
<FSharpTargetsPath>$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets</FSharpTargetsPath> | |
</PropertyGroup> | |
</Otherwise> | |
</Choose> | |
<Target Name="FDiagnostics" BeforeTargets="Build"> | |
<Message Importance="high" Text="MSBuildExtensionsPath32:$(MSBuildExtensionsPath32)" /> | |
<Message Importance="high" Text="FSharpTargetsPath:$(FSharpTargetsPath)" /> | |
<Message Importance="high" Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets')" Text="FSharpTargetsPath:Exists" /> | |
</Target> | |
<Import Project="$(FSharpTargetsPath)" /> | |
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- relevant changes to the fsproj here, not the entire fsproj file --> | |
<None Include="Template.ttus" /> | |
<Content Include="template.txt" /> | |
<!-- may not be relevant, but was helpful for build server --> | |
<Import Project="$(MSBuildProjectDirectory)\..\FTargets.proj" /> | |
<!-- used if the templatus package starts working, otherwise not useful --> | |
<PropertyGroup> | |
<PackagesFolder>$([System.IO.Path]::GetFullPath('$(MSBuildProjectDirectory)\..\packages'))</PackagesFolder> | |
</PropertyGroup> | |
<!-- required for templatus, hard coded to point at my local build of templatus that seems to work locally in VS2015 SP1 --> | |
<!-- could stand to be updated to pull in all .ttus files in the project via msbuild item group --> | |
<Target Name="Templates" BeforeTargets="Compile;Build" Inputs="Template.ttus" Outputs="output.txt"> | |
<Exec Command="C:\projects\Templatus\bin\Templatus.exe -t "$(MSBuildProjectDirectory)\Template.ttus" -p name=Timmy;age=3" Outputs="output.txt" /> | |
<!-- <Exec Command="$(PackagesFolder)\Templatus.0.2.0\tools\Templatus.exe -t "$(MSBuildProjectDirectory)\Template.ttus" -p name=Timmy;age=3" Outputs="output.txt" /> --> | |
</Target> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<#@ assembly name="C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Data.Entity.Design.dll" #> | |
<#@ output filename="template.txt" #> | |
<# | |
// really only handles the sql, pluralizer, and creating a string builder with all the generated code content (doesn't break up into individual files, or check out automagically) | |
#> | |
Params: <#= sprintf "Name: %s, Age: %s" name age #> | |
Indented numbers: | |
<# | |
[1 .. 10] | |
|> Seq.iter (fun num -> pushIndent " "; tprintfn "%d" num) | |
[9 .. -1 .. 1] | |
|> Seq.iter (fun num -> popIndent (); sprintf "%d" num |> tprintn) | |
clearIndent () | |
tprintn "----" | |
open System | |
open System.Collections.Generic | |
open System.Linq | |
type CultureInfo = System.Globalization.CultureInfo | |
type StringBuilder = System.Text.StringBuilder | |
type PluralizationService = System.Data.Entity.Design.PluralizationServices.PluralizationService | |
type ColumnDescription = {ColumnName:string; Type:string; Length:int; Nullable:bool; IsIdentity:bool} | |
let cString = "Data Source=<redacted>;Initial Catalog=ApplicationDatabase;App=Templatus;User Id=<redacted>;Password=<redacted>;" | |
let generateTypeComment columnCount = sprintf "/// %i properties" columnCount | |
let mapNullableType(targetType:string , nullable:bool, useOptions:bool ) = targetType + (if nullable then (if useOptions then " option" else " Nullable") else String.Empty) | |
let mapSqlType(type' : string, nullable:bool , useOptions:bool ) = | |
match type'.ToLower() with | |
|"char" | |
|"nchar" | |
|"nvarchar" | |
|"varchar" -> "string" | |
|"bit" -> mapNullableType("bool", nullable, useOptions) | |
|"date" | |
|"datetime" | |
|"smalldatetime" -> mapNullableType("DateTime", nullable, useOptions) | |
|"uniqueidentifier" -> mapNullableType("Guid",nullable, useOptions) | |
|"int" -> mapNullableType("int", nullable, useOptions) | |
|"decimal" -> mapNullableType("decimal", nullable, useOptions) | |
|"float" -> mapNullableType("float", nullable, useOptions) | |
|_ -> if isNull type' then String.Empty else type' | |
let generateColumnComment (cd:ColumnDescription) = sprintf "/// %s (%i) %s" (if isNull cd.Type then "null" else cd.Type) cd.Length (if cd.Nullable then "null" else "not null") | |
let generateInterface (typeName:string , columns:IEnumerable<ColumnDescription> , appendLine:int * string -> unit, writeable:bool , useOptions:bool ) = | |
appendLine(0, generateTypeComment (columns.Count())) | |
appendLine(0,"type I" + typeName + (if writeable then "RW" else String.Empty) + " =") | |
if writeable then | |
appendLine(1,"inherit I" + typeName) | |
for cd in columns do | |
appendLine(1, generateColumnComment cd) | |
appendLine(1, "abstract member " + cd.ColumnName + ":" + mapSqlType(cd.Type, cd.Nullable, useOptions) + " with get" + (if writeable then ",set" else String.Empty)) | |
appendLine(0,String.Empty) | |
let getDefaultValue(mappedType:string ) = | |
if mappedType.EndsWith("Nullable") then | |
"Nullable()" | |
elif mappedType.EndsWith("option") then | |
"None" | |
else | |
match mappedType.ToLower() with | |
|"int" -> "0" | |
|"bool" -> "false" | |
|"decimal" -> "0m" | |
|"float" -> "0." | |
|"datetime" -> "System.DateTime.MinValue" | |
|"uniqueidentifier" -> "Guid.Empty" | |
|_ -> "null" | |
let generateRecord(typeName:string, columns: ColumnDescription seq, appendLine:int * string -> unit, useOptions:bool) = | |
appendLine(0, generateTypeComment (columns.Count())) | |
if not useOptions then | |
appendLine(0,"[<NoComparison>]") | |
appendLine(0, "type " + typeName + "Record =") | |
appendLine(1, "{") | |
for cd in columns do | |
appendLine(1, generateColumnComment(cd)) | |
appendLine(1, cd.ColumnName + ":" + mapSqlType(cd.Type,cd.Nullable,useOptions)) | |
appendLine(1,"}") | |
appendLine(1,"interface I" + typeName + " with") | |
for cd in columns do | |
appendLine(2, "member x." + cd.ColumnName + " with get () = x." + cd.ColumnName) | |
appendLine(1,"static member Zero () = ") | |
appendLine(2,"{") | |
for cd in columns do | |
let mapped = mapSqlType(cd.Type, cd.Nullable, useOptions) | |
appendLine(2, cd.ColumnName + " = " + getDefaultValue(mapped)) | |
appendLine(2,"}") | |
appendLine(0,String.Empty) | |
let toCamel s = // https://github.com/ayoung/Newtonsoft.Json/blob/master/Newtonsoft.Json/Utilities/StringUtils.cs | |
if String.IsNullOrEmpty s then | |
s | |
elif not <| Char.IsUpper s.[0] then | |
s | |
else | |
let camelCase = Char.ToLower(s.[0], CultureInfo.InvariantCulture).ToString(CultureInfo.InvariantCulture) | |
if (s.Length > 1) then | |
camelCase + s.Substring(1) | |
else | |
camelCase | |
let generateModule(typeName:string, columns:IEnumerable<ColumnDescription>, schemaName:string , tableName:string , appendLine:int * string -> unit, useOptions:bool ) = | |
let camelType = toCamel typeName | |
appendLine(0, "module " + typeName + "Helpers =") | |
appendLine(1, "open Microsoft.FSharp.Core.Operators.Unchecked") | |
appendLine(1, String.Empty) | |
appendLine(1, "let tableName = \"" + typeName + "\"") | |
appendLine(1, "let ToRecord (i" + typeName + ":I" + typeName + ") =") | |
appendLine(2, "{") | |
for cd in columns do | |
let mapped = mapSqlType(cd.Type,cd.Nullable,useOptions) | |
appendLine(2, cd.ColumnName + " = i" + typeName + "." + cd.ColumnName) | |
appendLine(2, "}") | |
appendLine(0, String.Empty) | |
appendLine(1, "let toRecord (" + camelType + ":I"+ typeName + ") =") | |
appendLine(2, "{"); | |
for cd in columns do | |
let mapped = mapSqlType(cd.Type,cd.Nullable,useOptions) | |
appendLine(2, cd.ColumnName + " = " + camelType + "." + cd.ColumnName) | |
appendLine(2, "}") | |
appendLine(0,String.Empty) | |
appendLine(1, "let FromF (camelTypeF:Func<string,obj option>) =") | |
appendLine(2, "{") | |
let mapConverter(type' : string , nullable: bool, useOptions:bool) = | |
match type'.ToLower() with | |
|"char" | |
|"nchar" | |
|"nvarchar" | |
|"varchar" -> "ToString" | |
|"bit" -> "ToBoolean" | |
|"date" | |
|"datetime" | |
|"smalldatetime" -> "ToDateTime" | |
|"uniqueidentifier" -> "ToGuid" // invalid | |
|"int" -> "ToInt32" | |
|"decimal" -> "ToDecimal" | |
|"float" -> "ToDouble" | |
|_ -> if isNull type' then String.Empty else type' | |
for cd in columns do | |
let mapped = mapSqlType(cd.Type,cd.Nullable,useOptions) | |
let converter = mapConverter(cd.Type,cd.Nullable,useOptions) | |
appendLine(2, cd.ColumnName + " = ") | |
appendLine(3, "match camelTypeF.Invoke \"" + cd.ColumnName + "\" with ") | |
if cd.Nullable && (mapped <> typeof<string>.Name) && (mapped <> "string") && mapped <> "String" then | |
appendLine(3, "|Some x -> Nullable (Convert." + converter + " x )") | |
else | |
appendLine(3, "|Some x -> Convert." + converter + " x ") | |
appendLine(3, "|None -> Unchecked.defaultof<_>") | |
appendLine(2, "}") | |
appendLine(0,String.Empty) | |
appendLine(1, "let inline toRecordStp (" + camelType + ": ^a) =") | |
appendLine(2, "{") | |
for cd in columns do | |
let mapped = mapSqlType(cd.Type,cd.Nullable,useOptions) | |
appendLine(2, cd.ColumnName + " = (^a: (member " + cd.ColumnName + ": _) " + camelType + ")") | |
appendLine(2, "}") | |
appendLine(0, String.Empty) | |
appendLine(1,"let createInsert (r:I" + typeName + ") =") | |
appendLine(2,"let quoted s = \"'\" + s + \"'\"") | |
let mapValue (cd:ColumnDescription, prefix:string) :string = | |
match cd.Type.ToLower() with | |
|"varchar" -> "if String.IsNullOrEmpty " + prefix + cd.ColumnName+ " then \"null\" else quoted " + prefix + cd.ColumnName | |
|"int" -> if cd.Nullable then "if isNull (box " + prefix + cd.ColumnName + ") then \"null\" else " + prefix + cd.ColumnName + " |> string" else prefix + cd.ColumnName + " |> string" | |
|_ -> if cd.Nullable then "if isNull (box " + prefix + cd.ColumnName + ") then \"null\" else " + prefix + cd.ColumnName + " |> string |> quoted" else prefix + cd.ColumnName + " |> string |> quoted" | |
appendLine(2,"[") | |
for cd in columns.Where(fun c -> not c.IsIdentity) do | |
let mapped = "\"" + cd.ColumnName + "\", " + mapValue(cd,"r.") | |
appendLine(3,mapped) | |
appendLine(2,"]") | |
appendLine(2,"|> fun pairs -> sprintf \"insert into " + schemaName + "." + tableName + "(%s) values (%s)\" (String.Join(\",\", pairs |> Seq.map fst )) (String.Join(\",\", pairs |> Seq.map snd))" ) | |
appendLine(0,String.Empty) | |
let mapFieldNameFromType(columnName:string) = | |
match toCamel columnName with | |
| "type" -> "type'" | |
| camel -> camel | |
let generateClass(typeName:string, columns:IEnumerable<ColumnDescription> , appendLine:int * string -> unit, useOptions:bool ) = | |
appendLine(0, generateTypeComment (columns.Count())) | |
appendLine(0, "type "+ typeName + "N (model:" + typeName + "Record) = ") | |
appendLine(0, String.Empty) | |
appendLine(1, "let propertyChanged = new Event<_, _>()"); | |
appendLine(0, String.Empty) | |
appendLine(0, String.Empty) | |
for cd in columns do // https://fadsworld.wordpress.com/2011/05/18/f-quotations-for-inotifypropertychanged/ | |
let camel = mapFieldNameFromType(cd.ColumnName) | |
appendLine(1, "let mutable "+ camel + " = model." + cd.ColumnName) | |
appendLine(0, String.Empty) | |
appendLine(1, "interface I" + typeName + " with") | |
for cd in columns do | |
appendLine(2,generateColumnComment cd) | |
appendLine(2, "member x." + cd.ColumnName + " with get () = x." + cd.ColumnName) | |
appendLine(1, "interface I" + typeName + "RW with" ) | |
for cd in columns do | |
appendLine(2,generateColumnComment cd) | |
appendLine(2, "member x." + cd.ColumnName + " with get () = x." + cd.ColumnName + " and set v = x." + cd.ColumnName + " <- v") | |
appendLine(0, String.Empty) | |
appendLine(1, "member x.MakeRecord () =") | |
appendLine(2, "{") | |
for cd in columns do | |
appendLine(2, cd.ColumnName + " = x." + cd.ColumnName) | |
appendLine(2, "}") | |
appendLine(0, String.Empty) | |
appendLine(1, "interface INotifyPropertyChanged with") | |
appendLine(2, "[<CLIEvent>]") | |
appendLine(2, "member x.PropertyChanged = propertyChanged.Publish") | |
appendLine(1, "abstract member RaisePropertyChanged : string -> unit") | |
appendLine(1, "default x.RaisePropertyChanged(propertyName : string) = propertyChanged.Trigger(x, PropertyChangedEventArgs(propertyName))") | |
appendLine(0, String.Empty) | |
appendLine(1, "abstract member SetAndNotify<'t> : string * 't byref * 't -> bool") | |
appendLine(1, "default x.SetAndNotify<'t> (propertyName, field: 't byref, value:'t) =") | |
appendLine(2, "if obj.ReferenceEquals(box field,box value) then false") | |
appendLine(2, "else") | |
appendLine(3, "field <- value") | |
appendLine(3, "x.RaisePropertyChanged(propertyNam)"); | |
appendLine(3, "true") | |
appendLine(0, String.Empty) | |
appendLine(1, "abstract member SetAndNotify<'t,'b> : string * 'b * 't Action * 't -> bool") | |
appendLine(1, "default x.SetAndNotify<'t,'b> (propertyName, baseValue:'b, baseSetter: 't Action, value:'t) =") | |
appendLine(2, "if obj.ReferenceEquals(box baseValue,box value) then false") | |
appendLine(2, "else"); | |
appendLine(3, "baseSetter.Invoke value") | |
appendLine(3, "x.RaisePropertyChanged(propertyName)") | |
appendLine(3, "true"); | |
for cd in columns do | |
let camel = mapFieldNameFromType cd.ColumnName | |
appendLine(0, String.Empty) | |
appendLine(1, generateColumnComment cd) | |
appendLine(1, "member x." + cd.ColumnName) | |
appendLine(2, "with get() = " + camel) | |
appendLine(2, "and set v = ") | |
appendLine(3, camel + " <- v") | |
appendLine(3, "x.RaisePropertyChanged \"" + cd.ColumnName + "\"") | |
let generate (generationEnvironment:StringBuilder, targetProjectName:string, tables:string seq, cString:string) (pluralizer:string -> string) (singularizer:string -> string) useOptions = | |
let appendLine text = generationEnvironment.AppendLine(text) |> ignore | |
let appendLine' (indentLevels, text) = generationEnvironment.AppendLine(String.Join(String.Empty,Enumerable.Repeat(" ",indentLevels)) + text) |> ignore | |
use cn = new System.Data.SqlClient.SqlConnection(cString) | |
cn.Open() | |
for tableName in tables do | |
//manager.StartNewFile(Path.Combine(targetProjectFolder,tableName + ".generated.fs"),targetProject) | |
let typeName = singularizer tableName | |
let columns = List<ColumnDescription>() | |
let identities = List<string>() | |
use cmd = new System.Data.SqlClient.SqlCommand("sp_help " + tableName,cn) | |
use r = cmd.ExecuteReader() | |
r.NextResult() |> ignore // ignore the first table | |
while r.Read() do // column info | |
// columns and info | |
let columnName = r.["Column_name"].ToString() | |
let type' = r.["Type"].ToString() | |
// var computed = r["Computed"]; | |
let length = Convert.ToInt32(r.["Length"]) | |
// var prec = r["Prec"]; | |
columns.Add {ColumnName=columnName; Type= type'; Length=length; Nullable = r.["Nullable"].ToString() ="yes"; IsIdentity = false} | |
r.NextResult() |> ignore | |
while r.Read() do // identities | |
if r.["Seed"] <> box System.DBNull.Value then // only valid identities (sql uses the identity column to say there are none defined instead of an empty set) | |
identities.Add(r.["Identity"].ToString()) | |
let columns = | |
columns | |
|> Seq.map (fun c -> if identities.Contains(c.ColumnName) then {c with IsIdentity = true} else c) | |
|> fun s -> s.ToList() | |
let columns = columns.OrderBy(fun c -> c.ColumnName).ToList() | |
appendLine ("namespace Pm.Schema.DataModels." + (pluralizer typeName)) // + " // Generated by item in namespace " + manager.DefaultProjectNamespace ) | |
appendLine String.Empty | |
appendLine "open System" | |
appendLine "open System.ComponentModel" | |
appendLine "open System.Linq.Expressions" | |
appendLine String.Empty | |
appendLine "open FSharp.NullHelpers" | |
generateInterface (typeName, columns, appendLine', false, useOptions) | |
generateInterface (typeName, columns, appendLine', true, useOptions) | |
generateRecord(typeName, columns, appendLine', useOptions) | |
generateModule(typeName, columns, "dbo", tableName, appendLine', useOptions) | |
generateClass(typeName, columns, appendLine', useOptions) | |
let sb = StringBuilder() | |
let pluralizer = PluralizationService.CreateService(CultureInfo "en") // https://msdn.microsoft.com/en-us/library/system.data.entity.design.pluralizationservices.pluralizationservice(v=vs.110).aspx | |
generate (sb, "Pm.Schema", ["Users"], cString) (pluralizer.Pluralize) (pluralizer.Singularize) false | |
tprint (sb.ToString()) | |
#> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Params: Name: Timmy, Age: 3 | |
Indented numbers: | |
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
9 | |
8 | |
7 | |
6 | |
5 | |
4 | |
3 | |
2 | |
1 | |
---- | |
namespace Pm.Schema.DataModels.Users | |
open System | |
open System.ComponentModel | |
open System.Linq.Expressions | |
open FSharp.NullHelpers | |
/// 13 properties | |
type IUser = | |
/// bit (1) not null | |
abstract member IsLockedOut:bool with get | |
/// int (4) not null | |
abstract member LoginAttempts:int with get | |
/// varchar (50) null | |
abstract member RcopiaID:string with get | |
/// bit (1) not null | |
abstract member ResetPassword:bool with get | |
/// int (4) not null | |
abstract member UserFacilityID:int with get | |
/// varchar (50) not null | |
abstract member UserFirstName:string with get | |
/// int (4) not null | |
abstract member UserID:int with get | |
/// varchar (50) not null | |
abstract member UserLastName:string with get | |
/// int (4) not null | |
abstract member UserLevel:int with get | |
/// varchar (1) null | |
abstract member UserMiddleInitial:string with get | |
/// varchar (50) null | |
abstract member UserName:string with get | |
/// varchar (50) not null | |
abstract member UserPassword:string with get | |
/// bit (1) not null | |
abstract member UserPreviouslyLoggedIn:bool with get | |
/// 13 properties | |
type IUserRW = | |
inherit IUser | |
/// bit (1) not null | |
abstract member IsLockedOut:bool with get,set | |
/// int (4) not null | |
abstract member LoginAttempts:int with get,set | |
/// varchar (50) null | |
abstract member RcopiaID:string with get,set | |
/// bit (1) not null | |
abstract member ResetPassword:bool with get,set | |
/// int (4) not null | |
abstract member UserFacilityID:int with get,set | |
/// varchar (50) not null | |
abstract member UserFirstName:string with get,set | |
/// int (4) not null | |
abstract member UserID:int with get,set | |
/// varchar (50) not null | |
abstract member UserLastName:string with get,set | |
/// int (4) not null | |
abstract member UserLevel:int with get,set | |
/// varchar (1) null | |
abstract member UserMiddleInitial:string with get,set | |
/// varchar (50) null | |
abstract member UserName:string with get,set | |
/// varchar (50) not null | |
abstract member UserPassword:string with get,set | |
/// bit (1) not null | |
abstract member UserPreviouslyLoggedIn:bool with get,set | |
/// 13 properties | |
[<NoComparison>] | |
type UserRecord = | |
{ | |
/// bit (1) not null | |
IsLockedOut:bool | |
/// int (4) not null | |
LoginAttempts:int | |
/// varchar (50) null | |
RcopiaID:string | |
/// bit (1) not null | |
ResetPassword:bool | |
/// int (4) not null | |
UserFacilityID:int | |
/// varchar (50) not null | |
UserFirstName:string | |
/// int (4) not null | |
UserID:int | |
/// varchar (50) not null | |
UserLastName:string | |
/// int (4) not null | |
UserLevel:int | |
/// varchar (1) null | |
UserMiddleInitial:string | |
/// varchar (50) null | |
UserName:string | |
/// varchar (50) not null | |
UserPassword:string | |
/// bit (1) not null | |
UserPreviouslyLoggedIn:bool | |
} | |
interface IUser with | |
member x.IsLockedOut with get () = x.IsLockedOut | |
member x.LoginAttempts with get () = x.LoginAttempts | |
member x.RcopiaID with get () = x.RcopiaID | |
member x.ResetPassword with get () = x.ResetPassword | |
member x.UserFacilityID with get () = x.UserFacilityID | |
member x.UserFirstName with get () = x.UserFirstName | |
member x.UserID with get () = x.UserID | |
member x.UserLastName with get () = x.UserLastName | |
member x.UserLevel with get () = x.UserLevel | |
member x.UserMiddleInitial with get () = x.UserMiddleInitial | |
member x.UserName with get () = x.UserName | |
member x.UserPassword with get () = x.UserPassword | |
member x.UserPreviouslyLoggedIn with get () = x.UserPreviouslyLoggedIn | |
static member Zero () = | |
{ | |
IsLockedOut = false | |
LoginAttempts = 0 | |
RcopiaID = null | |
ResetPassword = false | |
UserFacilityID = 0 | |
UserFirstName = null | |
UserID = 0 | |
UserLastName = null | |
UserLevel = 0 | |
UserMiddleInitial = null | |
UserName = null | |
UserPassword = null | |
UserPreviouslyLoggedIn = false | |
} | |
module UserHelpers = | |
open Microsoft.FSharp.Core.Operators.Unchecked | |
let tableName = "User" | |
let ToRecord (iUser:IUser) = | |
{ | |
IsLockedOut = iUser.IsLockedOut | |
LoginAttempts = iUser.LoginAttempts | |
RcopiaID = iUser.RcopiaID | |
ResetPassword = iUser.ResetPassword | |
UserFacilityID = iUser.UserFacilityID | |
UserFirstName = iUser.UserFirstName | |
UserID = iUser.UserID | |
UserLastName = iUser.UserLastName | |
UserLevel = iUser.UserLevel | |
UserMiddleInitial = iUser.UserMiddleInitial | |
UserName = iUser.UserName | |
UserPassword = iUser.UserPassword | |
UserPreviouslyLoggedIn = iUser.UserPreviouslyLoggedIn | |
} | |
let toRecord (user:IUser) = | |
{ | |
IsLockedOut = user.IsLockedOut | |
LoginAttempts = user.LoginAttempts | |
RcopiaID = user.RcopiaID | |
ResetPassword = user.ResetPassword | |
UserFacilityID = user.UserFacilityID | |
UserFirstName = user.UserFirstName | |
UserID = user.UserID | |
UserLastName = user.UserLastName | |
UserLevel = user.UserLevel | |
UserMiddleInitial = user.UserMiddleInitial | |
UserName = user.UserName | |
UserPassword = user.UserPassword | |
UserPreviouslyLoggedIn = user.UserPreviouslyLoggedIn | |
} | |
let FromF (camelTypeF:Func<string,obj option>) = | |
{ | |
IsLockedOut = | |
match camelTypeF.Invoke "IsLockedOut" with | |
|Some x -> Convert.ToBoolean x | |
|None -> Unchecked.defaultof<_> | |
LoginAttempts = | |
match camelTypeF.Invoke "LoginAttempts" with | |
|Some x -> Convert.ToInt32 x | |
|None -> Unchecked.defaultof<_> | |
RcopiaID = | |
match camelTypeF.Invoke "RcopiaID" with | |
|Some x -> Convert.ToString x | |
|None -> Unchecked.defaultof<_> | |
ResetPassword = | |
match camelTypeF.Invoke "ResetPassword" with | |
|Some x -> Convert.ToBoolean x | |
|None -> Unchecked.defaultof<_> | |
UserFacilityID = | |
match camelTypeF.Invoke "UserFacilityID" with | |
|Some x -> Convert.ToInt32 x | |
|None -> Unchecked.defaultof<_> | |
UserFirstName = | |
match camelTypeF.Invoke "UserFirstName" with | |
|Some x -> Convert.ToString x | |
|None -> Unchecked.defaultof<_> | |
UserID = | |
match camelTypeF.Invoke "UserID" with | |
|Some x -> Convert.ToInt32 x | |
|None -> Unchecked.defaultof<_> | |
UserLastName = | |
match camelTypeF.Invoke "UserLastName" with | |
|Some x -> Convert.ToString x | |
|None -> Unchecked.defaultof<_> | |
UserLevel = | |
match camelTypeF.Invoke "UserLevel" with | |
|Some x -> Convert.ToInt32 x | |
|None -> Unchecked.defaultof<_> | |
UserMiddleInitial = | |
match camelTypeF.Invoke "UserMiddleInitial" with | |
|Some x -> Convert.ToString x | |
|None -> Unchecked.defaultof<_> | |
UserName = | |
match camelTypeF.Invoke "UserName" with | |
|Some x -> Convert.ToString x | |
|None -> Unchecked.defaultof<_> | |
UserPassword = | |
match camelTypeF.Invoke "UserPassword" with | |
|Some x -> Convert.ToString x | |
|None -> Unchecked.defaultof<_> | |
UserPreviouslyLoggedIn = | |
match camelTypeF.Invoke "UserPreviouslyLoggedIn" with | |
|Some x -> Convert.ToBoolean x | |
|None -> Unchecked.defaultof<_> | |
} | |
let inline toRecordStp (user: ^a) = | |
{ | |
IsLockedOut = (^a: (member IsLockedOut: _) user) | |
LoginAttempts = (^a: (member LoginAttempts: _) user) | |
RcopiaID = (^a: (member RcopiaID: _) user) | |
ResetPassword = (^a: (member ResetPassword: _) user) | |
UserFacilityID = (^a: (member UserFacilityID: _) user) | |
UserFirstName = (^a: (member UserFirstName: _) user) | |
UserID = (^a: (member UserID: _) user) | |
UserLastName = (^a: (member UserLastName: _) user) | |
UserLevel = (^a: (member UserLevel: _) user) | |
UserMiddleInitial = (^a: (member UserMiddleInitial: _) user) | |
UserName = (^a: (member UserName: _) user) | |
UserPassword = (^a: (member UserPassword: _) user) | |
UserPreviouslyLoggedIn = (^a: (member UserPreviouslyLoggedIn: _) user) | |
} | |
let createInsert (r:IUser) = | |
let quoted s = "'" + s + "'" | |
[ | |
"IsLockedOut", r.IsLockedOut |> string |> quoted | |
"LoginAttempts", r.LoginAttempts |> string | |
"RcopiaID", if String.IsNullOrEmpty r.RcopiaID then "null" else quoted r.RcopiaID | |
"ResetPassword", r.ResetPassword |> string |> quoted | |
"UserFacilityID", r.UserFacilityID |> string | |
"UserFirstName", if String.IsNullOrEmpty r.UserFirstName then "null" else quoted r.UserFirstName | |
"UserLastName", if String.IsNullOrEmpty r.UserLastName then "null" else quoted r.UserLastName | |
"UserLevel", r.UserLevel |> string | |
"UserMiddleInitial", if String.IsNullOrEmpty r.UserMiddleInitial then "null" else quoted r.UserMiddleInitial | |
"UserName", if String.IsNullOrEmpty r.UserName then "null" else quoted r.UserName | |
"UserPassword", if String.IsNullOrEmpty r.UserPassword then "null" else quoted r.UserPassword | |
"UserPreviouslyLoggedIn", r.UserPreviouslyLoggedIn |> string |> quoted | |
] | |
|> fun pairs -> sprintf "insert into dbo.Users(%s) values (%s)" (String.Join(",", pairs |> Seq.map fst )) (String.Join(",", pairs |> Seq.map snd)) | |
/// 13 properties | |
type UserN (model:UserRecord) = | |
let propertyChanged = new Event<_, _>() | |
let mutable isLockedOut = model.IsLockedOut | |
let mutable loginAttempts = model.LoginAttempts | |
let mutable rcopiaID = model.RcopiaID | |
let mutable resetPassword = model.ResetPassword | |
let mutable userFacilityID = model.UserFacilityID | |
let mutable userFirstName = model.UserFirstName | |
let mutable userID = model.UserID | |
let mutable userLastName = model.UserLastName | |
let mutable userLevel = model.UserLevel | |
let mutable userMiddleInitial = model.UserMiddleInitial | |
let mutable userName = model.UserName | |
let mutable userPassword = model.UserPassword | |
let mutable userPreviouslyLoggedIn = model.UserPreviouslyLoggedIn | |
interface IUser with | |
/// bit (1) not null | |
member x.IsLockedOut with get () = x.IsLockedOut | |
/// int (4) not null | |
member x.LoginAttempts with get () = x.LoginAttempts | |
/// varchar (50) null | |
member x.RcopiaID with get () = x.RcopiaID | |
/// bit (1) not null | |
member x.ResetPassword with get () = x.ResetPassword | |
/// int (4) not null | |
member x.UserFacilityID with get () = x.UserFacilityID | |
/// varchar (50) not null | |
member x.UserFirstName with get () = x.UserFirstName | |
/// int (4) not null | |
member x.UserID with get () = x.UserID | |
/// varchar (50) not null | |
member x.UserLastName with get () = x.UserLastName | |
/// int (4) not null | |
member x.UserLevel with get () = x.UserLevel | |
/// varchar (1) null | |
member x.UserMiddleInitial with get () = x.UserMiddleInitial | |
/// varchar (50) null | |
member x.UserName with get () = x.UserName | |
/// varchar (50) not null | |
member x.UserPassword with get () = x.UserPassword | |
/// bit (1) not null | |
member x.UserPreviouslyLoggedIn with get () = x.UserPreviouslyLoggedIn | |
interface IUserRW with | |
/// bit (1) not null | |
member x.IsLockedOut with get () = x.IsLockedOut and set v = x.IsLockedOut <- v | |
/// int (4) not null | |
member x.LoginAttempts with get () = x.LoginAttempts and set v = x.LoginAttempts <- v | |
/// varchar (50) null | |
member x.RcopiaID with get () = x.RcopiaID and set v = x.RcopiaID <- v | |
/// bit (1) not null | |
member x.ResetPassword with get () = x.ResetPassword and set v = x.ResetPassword <- v | |
/// int (4) not null | |
member x.UserFacilityID with get () = x.UserFacilityID and set v = x.UserFacilityID <- v | |
/// varchar (50) not null | |
member x.UserFirstName with get () = x.UserFirstName and set v = x.UserFirstName <- v | |
/// int (4) not null | |
member x.UserID with get () = x.UserID and set v = x.UserID <- v | |
/// varchar (50) not null | |
member x.UserLastName with get () = x.UserLastName and set v = x.UserLastName <- v | |
/// int (4) not null | |
member x.UserLevel with get () = x.UserLevel and set v = x.UserLevel <- v | |
/// varchar (1) null | |
member x.UserMiddleInitial with get () = x.UserMiddleInitial and set v = x.UserMiddleInitial <- v | |
/// varchar (50) null | |
member x.UserName with get () = x.UserName and set v = x.UserName <- v | |
/// varchar (50) not null | |
member x.UserPassword with get () = x.UserPassword and set v = x.UserPassword <- v | |
/// bit (1) not null | |
member x.UserPreviouslyLoggedIn with get () = x.UserPreviouslyLoggedIn and set v = x.UserPreviouslyLoggedIn <- v | |
member x.MakeRecord () = | |
{ | |
IsLockedOut = x.IsLockedOut | |
LoginAttempts = x.LoginAttempts | |
RcopiaID = x.RcopiaID | |
ResetPassword = x.ResetPassword | |
UserFacilityID = x.UserFacilityID | |
UserFirstName = x.UserFirstName | |
UserID = x.UserID | |
UserLastName = x.UserLastName | |
UserLevel = x.UserLevel | |
UserMiddleInitial = x.UserMiddleInitial | |
UserName = x.UserName | |
UserPassword = x.UserPassword | |
UserPreviouslyLoggedIn = x.UserPreviouslyLoggedIn | |
} | |
interface INotifyPropertyChanged with | |
[<CLIEvent>] | |
member x.PropertyChanged = propertyChanged.Publish | |
abstract member RaisePropertyChanged : string -> unit | |
default x.RaisePropertyChanged(propertyName : string) = propertyChanged.Trigger(x, PropertyChangedEventArgs(propertyName)) | |
abstract member SetAndNotify<'t> : string * 't byref * 't -> bool | |
default x.SetAndNotify<'t> (propertyName, field: 't byref, value:'t) = | |
if obj.ReferenceEquals(box field,box value) then false | |
else | |
field <- value | |
x.RaisePropertyChanged(propertyNam) | |
true | |
abstract member SetAndNotify<'t,'b> : string * 'b * 't Action * 't -> bool | |
default x.SetAndNotify<'t,'b> (propertyName, baseValue:'b, baseSetter: 't Action, value:'t) = | |
if obj.ReferenceEquals(box baseValue,box value) then false | |
else | |
baseSetter.Invoke value | |
x.RaisePropertyChanged(propertyName) | |
true | |
/// bit (1) not null | |
member x.IsLockedOut | |
with get() = isLockedOut | |
and set v = | |
isLockedOut <- v | |
x.RaisePropertyChanged "IsLockedOut" | |
/// int (4) not null | |
member x.LoginAttempts | |
with get() = loginAttempts | |
and set v = | |
loginAttempts <- v | |
x.RaisePropertyChanged "LoginAttempts" | |
/// varchar (50) null | |
member x.RcopiaID | |
with get() = rcopiaID | |
and set v = | |
rcopiaID <- v | |
x.RaisePropertyChanged "RcopiaID" | |
/// bit (1) not null | |
member x.ResetPassword | |
with get() = resetPassword | |
and set v = | |
resetPassword <- v | |
x.RaisePropertyChanged "ResetPassword" | |
/// int (4) not null | |
member x.UserFacilityID | |
with get() = userFacilityID | |
and set v = | |
userFacilityID <- v | |
x.RaisePropertyChanged "UserFacilityID" | |
/// varchar (50) not null | |
member x.UserFirstName | |
with get() = userFirstName | |
and set v = | |
userFirstName <- v | |
x.RaisePropertyChanged "UserFirstName" | |
/// int (4) not null | |
member x.UserID | |
with get() = userID | |
and set v = | |
userID <- v | |
x.RaisePropertyChanged "UserID" | |
/// varchar (50) not null | |
member x.UserLastName | |
with get() = userLastName | |
and set v = | |
userLastName <- v | |
x.RaisePropertyChanged "UserLastName" | |
/// int (4) not null | |
member x.UserLevel | |
with get() = userLevel | |
and set v = | |
userLevel <- v | |
x.RaisePropertyChanged "UserLevel" | |
/// varchar (1) null | |
member x.UserMiddleInitial | |
with get() = userMiddleInitial | |
and set v = | |
userMiddleInitial <- v | |
x.RaisePropertyChanged "UserMiddleInitial" | |
/// varchar (50) null | |
member x.UserName | |
with get() = userName | |
and set v = | |
userName <- v | |
x.RaisePropertyChanged "UserName" | |
/// varchar (50) not null | |
member x.UserPassword | |
with get() = userPassword | |
and set v = | |
userPassword <- v | |
x.RaisePropertyChanged "UserPassword" | |
/// bit (1) not null | |
member x.UserPreviouslyLoggedIn | |
with get() = userPreviouslyLoggedIn | |
and set v = | |
userPreviouslyLoggedIn <- v | |
x.RaisePropertyChanged "UserPreviouslyLoggedIn" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment