Skip to content

Commit

Permalink
v2.5.0 - HydraReader now filters out columns that are not contained i…
Browse files Browse the repository at this point in the history
…n the selected record(s). Adding `select` in query now explicitly selects all columns in the selected records rathern than `*`.
  • Loading branch information
JordanMarr committed May 17, 2024
1 parent 5b15d85 commit 965234a
Show file tree
Hide file tree
Showing 26 changed files with 1,290 additions and 1,200 deletions.
23 changes: 14 additions & 9 deletions src/SqlHydra.Cli/SchemaGenerator.fs
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ let generateHydraReaderClass (db: Schema) (rdrCfg: ReadersConfig) (app: AppInfo)
Value("accFieldCount", Unquoted "0").toMutable()

for table in allTables do
// let lazyPersonEmailAddress = lazy (Person.Readers.EmailAddressReader(reader, buildGetOrdinal 5))
// let lazyPersonEmailAddress = lazy (Person.Readers.EmailAddressReader(reader, buildGetOrdinal 5 typeof<Person.EmailAddress))
Value(
$"lazy{backticks table.Schema}{backticks table.Name}",
ConstantExpr(Unquoted $"lazy ({backticks table.Schema}.Readers.{backticks table.Name}Reader(reader, buildGetOrdinal {table.TotalColumns}))")
ConstantExpr(Unquoted $"lazy ({backticks table.Schema}.Readers.{backticks table.Name}Reader(reader, buildGetOrdinal typeof<{table.Schema}.{table.Name}>))")
)

for table in allTables do
Expand Down Expand Up @@ -367,15 +367,20 @@ let substitutions (app: AppInfo) : (string * string) list =
// HydraReader utility functions
"let mutable accFieldCount = 0",
"""let mutable accFieldCount = 0
let buildGetOrdinal fieldCount =
let buildGetOrdinal tableType =
let fieldNames =
FSharp.Reflection.FSharpType.GetRecordFields(tableType)
|> Array.map _.Name
let dictionary =
[0..reader.FieldCount-1]
|> List.map (fun i -> reader.GetName(i), i)
|> List.sortBy snd
|> List.skip accFieldCount
|> List.take fieldCount
[| 0 .. reader.FieldCount - 1 |]
|> Array.map (fun i -> reader.GetName(i), i)
|> Array.sortBy snd
|> Array.skip accFieldCount
|> Array.filter (fun (name, _) -> Array.contains name fieldNames)
|> Array.take fieldNames.Length
|> dict
accFieldCount <- accFieldCount + fieldCount
accFieldCount <- accFieldCount + fieldNames.Length
fun col -> dictionary.Item col
"""

Expand Down
8 changes: 4 additions & 4 deletions src/SqlHydra.Cli/SqlHydra.Cli.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<OutputType>Exe</OutputType>
<TargetFrameworks>net6.0;net7.0;net8.0</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<Version>2.4.1</Version>
<Version>2.5.0</Version>
<WarningsAsErrors>
<!-- Incomplete pattern matches on this expression. -->
FS0025
Expand Down Expand Up @@ -50,9 +50,9 @@
<PackageReference Update="FSharp.Core" Version="7.0.200" Condition="'$(TargetFramework)' == 'net7.0'" />
<PackageReference Update="FSharp.Core" Version="8.0.100" Condition="'$(TargetFramework)' == 'net8.0'" />
<PackageReference Include="Fabulous.AST" Version="1.0.0-pre5" />
<PackageReference Include="Npgsql" Version="6.0.7" Condition="'$(TargetFramework)' == 'net6.0'" />
<PackageReference Include="Npgsql" Version="7.0.0" Condition="'$(TargetFramework)' == 'net7.0'" />
<PackageReference Include="Npgsql" Version="8.0.0" Condition="'$(TargetFramework)' == 'net8.0'" />
<PackageReference Include="Npgsql" Version="6.0.11" Condition="'$(TargetFramework)' == 'net6.0'" />
<PackageReference Include="Npgsql" Version="7.0.7" Condition="'$(TargetFramework)' == 'net7.0'" />
<PackageReference Include="Npgsql" Version="8.0.3" Condition="'$(TargetFramework)' == 'net8.0'" />
<PackageReference Include="Oracle.ManagedDataAccess.Core" Version="3.21.120" />
<PackageReference Include="System.Data.SQLite" Version="1.0.118" />
<PackageReference Include="Microsoft.Data.SqlClient" Version="5.2.0" />
Expand Down
4 changes: 2 additions & 2 deletions src/SqlHydra.Query/LinqExpressionVisitors.fs
Original file line number Diff line number Diff line change
Expand Up @@ -752,7 +752,7 @@ let visitPropertySelector<'T, 'Prop> (propertySelector: Expression<Func<'T, 'Pro
visit (propertySelector :> Expression)

type Selection =
| SelectedTable of tableAlias: string
| SelectedTable of tableAlias: string * tableType: Type
| SelectedColumn of tableAlias: string * column: string
| SelectedAggregateColumn of aggregateType: string * tableAlias: string * column: string

Expand All @@ -775,7 +775,7 @@ let visitSelect<'T, 'Prop> (propertySelector: Expression<Func<'T, 'Prop>>) =
n.Arguments
|> Seq.map visit |> Seq.toList |> List.concat
| Parameter p ->
[ SelectedTable p.Name ]
[ SelectedTable (p.Name, p.Type) ]
| Member m ->
if m.Member.DeclaringType |> isOptionOrNullableType then
visit m.Expression
Expand Down
11 changes: 8 additions & 3 deletions src/SqlHydra.Query/SelectBuilders.fs
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,14 @@ type SelectBuilder<'Selected, 'Mapped> () =
let queryWithSelectedColumns =
selections
|> List.fold (fun (q: Query) -> function
| LinqExpressionVisitors.SelectedTable tableAlias ->
// Select all columns in table
q.Select($"%s{tableAlias}.*")
| LinqExpressionVisitors.SelectedTable (tableAlias, tableType) ->
// Explicitly select all columns in generated table record type.
// This avoids table scans due to 'SELECT *', and avoids potential errors when a table has more columns than expected.
let props =
FSharp.Reflection.FSharpType.GetRecordFields(tableType)
|> Array.map (fun p -> $"%s{tableAlias}.%s{p.Name}")

q.Select(props)
| LinqExpressionVisitors.SelectedColumn (tableAlias, column) ->
// Select a single column
q.Select($"%s{tableAlias}.%s{column}")
Expand Down
2 changes: 1 addition & 1 deletion src/SqlHydra.Query/SqlHydra.Query.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<TargetFrameworks>netstandard2.0;net6.0;net7.0</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<WarnOn>3390;$(WarnOn)</WarnOn>
<Version>2.4.1</Version>
<Version>2.5.0</Version>
<Description>SqlHydra.Query is an F# query builder powered by SqlKata.Query that supports SQL Server, PostgreSQL, Sqlite and Oracle.</Description>
<WarningsAsErrors>
<!-- Incomplete pattern matches on this expression. -->
Expand Down
Loading

0 comments on commit 965234a

Please sign in to comment.