Genres list
For more convenient instantiation of DbContext
, let's introduce a small helper function in Db
module:
Db.fs
23:
|
|
Now we're ready to finally read real data in the App
module:
App.fs
19: 20: 21: 22: 23: 24: |
|
App.fs
29:
|
|
overview
is a WebPart that...
Hold on, do I really need to explain it?
The usage of pipe operator here makes the flow rather obvious - each line defines each step.
The return value is passed from one function to another, starting with DbContext and ending with the WebPart.
This is just a single example of how composition in functional programming makes functions look like building blocks "glued" together.
We also had to wrap the overview
WebPart in a warbler
, because otherwise the overview
WebPart would be in a sense static - there'd be no reason not to cache the result.
warbler
ensures that genres will be fetched from the database whenever a new request comes.
Otherwise, without the warbler
in place, the genres would be fetched only at the start of the application - resulting in stale genres in case the list changes.
Do we need also to wrap with warbler
the rest of WebParts?
browse
is parametrized with genre name - each request will result in a database query anyway, so we don't need to do anything here.details
is parametrized with the id - same as above.home
is just fine - for the moment it's completely static and doesn't need to touch the database.Multiple items
namespace FSharp
--------------------
namespace Microsoft.FSharpMultiple items
namespace FSharp.Data
--------------------
namespace Microsoft.FSharp.Datanamespace FSharp.Data.SqlMultiple items
type LiteralAttribute =
inherit Attribute
new : unit -> LiteralAttribute
Full name: Microsoft.FSharp.Core.LiteralAttribute
--------------------
new : unit -> LiteralAttributeval ConnectionString : string
Full name: SuaveMusicStore.Db.ConnectionStringtype Sql = SqlDataProvider<...>
Full name: SuaveMusicStore.Db.Sqltype SqlDataProvider
Full name: FSharp.Data.Sql.SqlDataProvider
<summary>Typed representation of a database</summary>
<param name='ConnectionString'>The connection string for the SQL database</param>
<param name='ConnectionStringName'>The connection string name to select from a configuration file</param>
<param name='DatabaseVendor'> The target database vendor</param>
<param name='IndividualsAmount'>The amount of sample entities to project into the type system for each SQL entity type. Default 1000.</param>
<param name='UseOptionTypes'>If true, F# option types will be used in place of nullable database columns. If false, you will always receive the default value of the column's type even if it is null in the database.</param>
<param name='ResolutionPath'>The location to look for dynamically loaded assemblies containing database vendor specific connections and custom types.</param>
<param name='Owner'>The owner of the schema for this provider to resolve (Oracle Only)</param>
<param name='CaseSensitivityChange'>Should we do ToUpper or ToLower when generating table names?</param>
<param name='TableNames'>Comma separated table names list to limit a number of tables in big instances. The names can have '%' sign to handle it as in the 'LIKE' query (Oracle and MSSQL Only)</param>
<param name='OdbcQuote'>Odbc quote characters: Quote characters for the table and column names: `alias`, [alias]</param>
<param name='SQLiteLibrary'>Use System.Data.SQLite or Mono.Data.SQLite or select automatically (SQLite only)</param>
namespace FSharp.Data.Sql.Commontype DatabaseProviderTypes =
| MSSQLSERVER = 0
| SQLITE = 1
| POSTGRESQL = 2
| MYSQL = 3
| ORACLE = 4
| MSACCESS = 5
| ODBC = 6
| FIREBIRD = 7
Full name: FSharp.Data.Sql.Common.DatabaseProviderTypesCommon.DatabaseProviderTypes.POSTGRESQL: Common.DatabaseProviderTypes = 2type CaseSensitivityChange =
| ORIGINAL = 0
| TOUPPER = 1
| TOLOWER = 2
Full name: FSharp.Data.Sql.Common.CaseSensitivityChangeCommon.CaseSensitivityChange.ORIGINAL: Common.CaseSensitivityChange = 0type DbContext = SqlDataProvider<...>.dataContext
Full name: SuaveMusicStore.Db.DbContexttype dataContext =
member ClearUpdates : unit -> List<SqlEntity>
member CreateConnection : unit -> IDbConnection
member GetUpdates : unit -> List<SqlEntity>
member Public : publicSchema
member SubmitUpdates : unit -> Unit
member SubmitUpdatesAsync : unit -> Async<Unit>
nested type public.albumdetails.Individuals
nested type public.albumdetailsEntity
nested type public.albums.Individuals
nested type public.albumsEntity
...
Full name: FSharp.Data.Sql.SqlDataProvider,DatabaseVendor="2",ConnectionString="Server=192.168.99.100;Database=suavemusicstore;User Id=suave;Password=1234;",CaseSensitivityChange="0".dataContexttype Album = SqlDataProvider<...>.dataContext.public.albumsEntity
Full name: SuaveMusicStore.Db.Albumtype Genre = SqlDataProvider<...>.dataContext.public.genresEntity
Full name: SuaveMusicStore.Db.Genretype AlbumDetails = SqlDataProvider<...>.dataContext.public.albumdetailsEntity
Full name: SuaveMusicStore.Db.AlbumDetailsval getContext : unit -> SqlDataProvider<...>.dataContext
Full name: SuaveMusicStore.Db.getContextSqlDataProvider<...>.GetDataContext() : SqlDataProvider<...>.dataContext
<summary>Returns an instance of the SQL Provider using the static parameters</summary>
SqlDataProvider<...>.GetDataContext(transactionOptions: Transactions.TransactionOptions) : SqlDataProvider<...>.dataContext
<summary>Returns an instance of the SQL Provider</summary>
<param name='transactionOptions'>TransactionOptions for the transaction created on SubmitChanges.</param>
SqlDataProvider<...>.GetDataContext(connectionString: string) : SqlDataProvider<...>.dataContext
<summary>Returns an instance of the SQL Provider</summary>
<param name='connectionString'>The database connection string</param>
SqlDataProvider<...>.GetDataContext(connectionString: string, transactionOptions: Transactions.TransactionOptions) : SqlDataProvider<...>.dataContext
<summary>Returns an instance of the SQL Provider</summary>
<param name='connectionString'>The database connection string</param>
<param name='transactionOptions'>TransactionOptions for the transaction created on SubmitChanges.</param>
SqlDataProvider<...>.GetDataContext(connectionString: string, resolutionPath: string) : SqlDataProvider<...>.dataContext
<summary>Returns an instance of the SQL Provider</summary>
<param name='connectionString'>The database connection string</param>
<param name='resolutionPath'>The location to look for dynamically loaded assemblies containing database vendor specific connections and custom types</param>
SqlDataProvider<...>.GetDataContext(connectionString: string, resolutionPath: string, transactionOptions: Transactions.TransactionOptions) : SqlDataProvider<...>.dataContext
<summary>Returns an instance of the SQL Provider</summary>
<param name='connectionString'>The database connection string</param>
<param name='resolutionPath'>The location to look for dynamically loaded assemblies containing database vendor specific connections and custom types</param>
<param name='transactionOptions'>TransactionOptions for the transaction created on SubmitChanges.</param>val getGenres : ctx:DbContext -> Genre list
Full name: SuaveMusicStore.Db.getGenresval ctx : DbContexttype 'T list = List<'T>
Full name: Microsoft.FSharp.Collections.list<_>property SqlDataProvider<...>.dataContext.Public: SqlDataProvider<...>.dataContext.publicSchemaproperty SqlDataProvider<...>.dataContext.publicSchema.Genres: SqlDataProvider<...>.dataContext.publicSchema.public.genres
<summary> The base table genres belonging to schema public</summary>Multiple items
module Seq
from FSharp.Data.Sql
--------------------
module Seq
from Microsoft.FSharp.Collectionsval toList : source:seq<'T> -> 'T list
Full name: Microsoft.FSharp.Collections.Seq.toListval getAlbumsForGenre : genreName:string -> ctx:DbContext -> Album list
Full name: SuaveMusicStore.Db.getAlbumsForGenreval genreName : stringval query : Linq.QueryBuilder
Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.queryval album : SqlDataProvider<...>.dataContext.public.albumsEntityproperty SqlDataProvider<...>.dataContext.publicSchema.Albums: SqlDataProvider<...>.dataContext.publicSchema.public.albums
<summary> The base table albums belonging to schema public</summary>custom operation: join var in collection on (outerKey = innerKey). Note that parentheses are required after 'on'
Calls Linq.QueryBuilder.Joinval genre : SqlDataProvider<...>.dataContext.public.genresEntityproperty SqlDataProvider<...>.dataContext.public.genresEntity.Genreid: int
<summary> integer</summary>custom operation: where (bool)
Calls Linq.QueryBuilder.Whereproperty SqlDataProvider<...>.dataContext.public.genresEntity.Name: string
<summary> character varying(120)</summary>custom operation: select ('Result)
Calls Linq.QueryBuilder.Selectval getAlbumDetails : id:int -> ctx:DbContext -> AlbumDetails option
Full name: SuaveMusicStore.Db.getAlbumDetailsval id : inttype 'T option = Option<'T>
Full name: Microsoft.FSharp.Core.option<_>val album : SqlDataProvider<...>.dataContext.public.albumdetailsEntityproperty SqlDataProvider<...>.dataContext.publicSchema.Albumdetails: SqlDataProvider<...>.dataContext.publicSchema.public.albumdetails
<summary> The view albumdetails belonging to schema public</summary>property SqlDataProvider<...>.dataContext.public.albumdetailsEntity.Albumid: int
<summary> integer</summary>val tryHead : source:seq<'T> -> 'T option
Full name: Microsoft.FSharp.Collections.Seq.tryHeadtype IntPath = PrintfFormat<(int -> string),unit,string,string,int>
Full name: SuaveMusicStore.Path.IntPathMultiple items
type PrintfFormat<'Printer,'State,'Residue,'Result> =
new : value:string -> PrintfFormat<'Printer,'State,'Residue,'Result>
member Value : string
Full name: Microsoft.FSharp.Core.PrintfFormat<_,_,_,_>
--------------------
type PrintfFormat<'Printer,'State,'Residue,'Result,'Tuple> =
inherit PrintfFormat<'Printer,'State,'Residue,'Result>
new : value:string -> PrintfFormat<'Printer,'State,'Residue,'Result,'Tuple>
Full name: Microsoft.FSharp.Core.PrintfFormat<_,_,_,_,_>
--------------------
new : value:string -> PrintfFormat<'Printer,'State,'Residue,'Result>
--------------------
new : value:string -> PrintfFormat<'Printer,'State,'Residue,'Result,'Tuple>Multiple items
val int : value:'T -> int (requires member op_Explicit)
Full name: Microsoft.FSharp.Core.Operators.int
--------------------
type int = int32
Full name: Microsoft.FSharp.Core.int
--------------------
type int<'Measure> = int
Full name: Microsoft.FSharp.Core.int<_>Multiple items
val string : value:'T -> string
Full name: Microsoft.FSharp.Core.Operators.string
--------------------
type string = System.String
Full name: Microsoft.FSharp.Core.stringtype unit = Unit
Full name: Microsoft.FSharp.Core.unitval withParam : key:string * value:string -> path:string -> string
Full name: SuaveMusicStore.Path.withParamval key : stringval value : stringval path : stringval sprintf : format:Printf.StringFormat<'T> -> 'T
Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.sprintfval home : string
Full name: SuaveMusicStore.Path.homemodule Store
from SuaveMusicStore.Pathval overview : string
Full name: SuaveMusicStore.Path.Store.overviewval browse : string
Full name: SuaveMusicStore.Path.Store.browseval details : IntPath
Full name: SuaveMusicStore.Path.Store.detailsval browseKey : string
Full name: SuaveMusicStore.Path.Store.browseKeynamespace Suavemodule Html
from Suaveval cssLink : href:string -> Node
Full name: SuaveMusicStore.View.cssLinkval href : stringval link : attr:Attribute list -> Node
Full name: Suave.Html.linkval h2 : s:string -> Node
Full name: SuaveMusicStore.View.h2val s : stringval tag : tag:string -> attr:Attribute list -> contents:Node list -> Node
Full name: Suave.Html.tagunion case Node.Text: string -> Nodeval ul : nodes:Node list -> Node
Full name: SuaveMusicStore.View.ulval nodes : Node listval li : (Node list -> Node)
Full name: SuaveMusicStore.View.lival home : Node list
Full name: SuaveMusicStore.View.homeval store : genres:string list -> Node list
Full name: SuaveMusicStore.View.storeval genres : string listval p : (Attribute list -> Node list -> Node)
Full name: Suave.Html.pMultiple items
module List
from Microsoft.FSharp.Collections
--------------------
type List<'T> =
| ( [] )
| ( :: ) of Head: 'T * Tail: 'T list
interface IEnumerable
interface IEnumerable<'T>
member GetSlice : startIndex:int option * endIndex:int option -> 'T list
member Head : 'T
member IsEmpty : bool
member Item : index:int -> 'T with get
member Length : int
member Tail : 'T list
static member Cons : head:'T * tail:'T list -> 'T list
static member Empty : 'T list
Full name: Microsoft.FSharp.Collections.List<_>val length : list:'T list -> int
Full name: Microsoft.FSharp.Collections.List.lengthval genre : stringval url : stringmodule Path
from SuaveMusicStoreval a : href:string -> attr:Attribute list -> (Node list -> Node)
Full name: Suave.Html.aval browse : genre:string -> Node list
Full name: SuaveMusicStore.View.browseval details : id:int -> Node list
Full name: SuaveMusicStore.View.detailsval index : container:Node list -> string
Full name: SuaveMusicStore.View.indexval container : Node listval html : (Attribute list -> Node list -> Node)
Full name: Suave.Html.htmlval head : (Attribute list -> Node list -> Node)
Full name: Suave.Html.headval title : attr:Attribute list -> s:string -> Node
Full name: Suave.Html.titleval body : (Attribute list -> Node list -> Node)
Full name: Suave.Html.bodyval div : (Attribute list -> Node list -> Node)
Full name: Suave.Html.divval htmlToString : node:Node -> string
Full name: Suave.Html.htmlToStringmodule App
from SuaveMusicStoremodule Filters
from Suavemodule Operators
from Suavemodule RequestErrors
from Suavemodule Successful
from Suavemodule Web
from Suaveval html : container:Html.Node list -> WebPart
Full name: SuaveMusicStore.App.htmlval container : Html.Node listval OK : body:string -> WebPart
Full name: Suave.Successful.OKmodule View
from SuaveMusicStoreval index : container:Html.Node list -> string
Full name: SuaveMusicStore.View.indexval browse : (HttpContext -> Async<HttpContext option>)
Full name: SuaveMusicStore.App.browseval request : apply:(HttpRequest -> HttpContext -> 'a) -> context:HttpContext -> 'a
Full name: Suave.Http.requestval r : HttpRequestmember HttpRequest.queryParam : key:string -> Choice<string,string>union case Choice.Choice1Of2: 'T1 -> Choice<'T1,'T2>val browse : genre:string -> Html.Node list
Full name: SuaveMusicStore.View.browseunion case Choice.Choice2Of2: 'T2 -> Choice<'T1,'T2>val msg : stringval BAD_REQUEST : body:string -> WebPart
Full name: Suave.RequestErrors.BAD_REQUESTval overview : (HttpContext -> Async<HttpContext option>)
Full name: SuaveMusicStore.App.overviewval warbler : f:('t -> 't -> 'u) -> 't -> 'u
Full name: Suave.WebPart.warblermodule Db
from SuaveMusicStoreval getContext : unit -> FSharp.Data.Sql.SqlDataProvider<...>.dataContext
Full name: SuaveMusicStore.Db.getContextval getGenres : ctx:Db.DbContext -> Db.Genre list
Full name: SuaveMusicStore.Db.getGenresval map : mapping:('T -> 'U) -> list:'T list -> 'U list
Full name: Microsoft.FSharp.Collections.List.mapval g : Db.Genreproperty FSharp.Data.Sql.SqlDataProvider<...>.dataContext.public.genresEntity.Name: string
<summary> character varying(120)</summary>val store : genres:string list -> Html.Node list
Full name: SuaveMusicStore.View.storeval webPart : WebPart<HttpContext>
Full name: SuaveMusicStore.App.webPartval choose : options:WebPart<'a> list -> WebPart<'a>
Full name: Suave.WebPart.chooseval path : pathAfterDomain:string -> WebPart
Full name: Suave.Filters.pathval home : Html.Node list
Full name: SuaveMusicStore.View.homeval pathScan : pf:PrintfFormat<'a,'b,'c,'d,'t> -> h:('t -> WebPart) -> WebPart
Full name: Suave.Filters.pathScanval details : Path.IntPath
Full name: SuaveMusicStore.Path.Store.detailsval details : id:int -> Html.Node list
Full name: SuaveMusicStore.View.detailsval pathRegex : pathAfterDomainRegex:string -> WebPart
Full name: Suave.Filters.pathRegexmodule Files
from Suaveval browseHome : WebPart
Full name: Suave.Files.browseHomeval startWebServer : config:SuaveConfig -> webpart:WebPart -> unit
Full name: Suave.Web.startWebServerval defaultConfig : SuaveConfig
Full name: Suave.Web.defaultConfig
Show code from this section on GitHub