Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
6
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Switch to GitLab Next
Sign in / Register
Toggle navigation
F
fsharp-sql-provider
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Iterations
Merge Requests
1
Merge Requests
1
Requirements
Requirements
List
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Test Cases
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Operations
Operations
Incidents
Environments
Packages & Registries
Packages & Registries
Package Registry
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issue
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Sean
fsharp-sql-provider
Commits
d6e0fbb8
Commit
d6e0fbb8
authored
Feb 06, 2020
by
Sean
🎨
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactor factor, what's my tractor?
parent
18b8e691
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
162 additions
and
126 deletions
+162
-126
DbAccess.fs
DbAccess.fs
+86
-0
Domain.fs
Domain.fs
+24
-0
Helpers.fs
Helpers.fs
+15
-0
Loader.fs
Loader.fs
+31
-0
Program.fs
Program.fs
+2
-126
test-sql-provider.fsproj
test-sql-provider.fsproj
+4
-0
No files found.
DbAccess.fs
0 → 100644
View file @
d6e0fbb8
/// Encapsulates all db access, exposes domain types
module
DbAccess
open
FSharp
.
Data
.
Sql
open
Domain
open
Helpers
// SQL Provider / DB config
[<
Literal
>]
let
private
DbVendor
=
Common
.
DatabaseProviderTypes
.
POSTGRESQL
[<
Literal
>]
let
private
ConnString
=
"Host=localhost;Port=5432;Database=postgres;Username=test_app;Password=pass"
[<
Literal
>]
let
private
Schema
=
"test"
[<
Literal
>]
let
private
ResPath
=
__
SOURCE_DIRECTORY__
+
@
"./lib"
[<
Literal
>]
let
private
IndivAmount
=
100
[<
Literal
>]
let
private
UseOptTypes
=
true
type
private
DB
=
SqlDataProvider
<
DatabaseVendor
=
DbVendor
,
ConnectionString
=
ConnString
,
ResolutionPath
=
ResPath
,
IndividualsAmount
=
IndivAmount
,
UseOptionTypes
=
UseOptTypes
,
Owner
=
Schema
>
let
private
ctx
=
DB
.
GetDataContext
(
selectOperations
=
SelectOperations
.
DatabaseSide
)
let
private
catDb
=
ctx
.
Test
// plain tables - query on these or use their functions
let
private
Attributes
=
catDb
.
Attributes
let
private
Cats
=
catDb
.
Cats
let
private
Breeds
=
catDb
.
Breeds
let
private
Owners
=
catDb
.
Owners
// join tables
let
private
BreedAttrs
=
catDb
.
BreedAttributes
let
private
OwnerCats
=
catDb
.
OwnerCats
// creating entity functions - basic building blocks for CRUD functions
let
private
createBreed
=
Breeds
.
``Create(name)``
let
private
createAttribute
=
Attributes
.
``Create(description, name)``
let
private
createCat
=
Cats
.
``Create(breedid, name)``
let
private
createOwner
=
Owners
.
``Create(age, name)``
let
private
createBreedAttr
=
BreedAttrs
.
``Create(attributeid, breedid)``
let
private
createOwnerCat
=
Owners
.
``Create(age, name)``
/// Query db for a breedId, by Breed Name
let
private
findBreedIdByName
breedName
=
query
{
for
b
in
Breeds
do
where
(
b
.
Name
=
breedName
)
take
1
select
b
.
Id
}
/// Insert a breed into the db by name
let
insertBreed
breedName
=
let
breedEntity
=
createBreed
(
breedName
)
printfn
" > Makin' breed %s..."
breedName
ctx
.
SubmitUpdates
()
printfn
" > ✅"
breedEntity
.
Id
/// Deferred insert Breed
let
private
defInsertBreed
:
string
->
unit
->
int
=
thunkOne
insertBreed
/// Insert a cat into the db, will insert the breed if necessary
let
insertCat
cat
=
let
breedId
=
findBreedIdByName
cat
.
breed
.
name
|>
Seq
.
tryHead
|>
Option
.
defaultWith
(
defInsertBreed
cat
.
breed
.
name
)
let
catEntity
=
createCat
(
breedId
,
cat
.
name
)
printfn
" > Makin' kitteh %s"
cat
.
name
ctx
.
SubmitUpdates
()
printfn
" > ✅"
{
cat
with
id
=
Some
catEntity
.
Id
breed
=
{
cat
.
breed
with
id
=
Some
breedId
}
}
Domain.fs
0 → 100644
View file @
d6e0fbb8
/// Domain modelling - normal F#!
module
Domain
/// A type of cat (ignoring attributes for now)
type
Breed
=
{
id
:
int
option
name
:
string
}
/// KITTEH
type
Cat
=
{
id
:
int
option
name
:
string
breed
:
Breed
}
/// Make a cat with just a name and breed name, with None for ids
let
mkCat
catName
breedName
=
{
id
=
None
name
=
catName
breed
=
{
id
=
None
name
=
breedName
}
}
/// Turn a cat to a string - my how the turn tables!
let
catToStr
cat
=
sprintf
"%s(%d)"
cat
.
name
(
Option
.
defaultValue
-
1
cat
.
id
)
Helpers.fs
0 → 100644
View file @
d6e0fbb8
/// Abstract functional heplers that don't go anywhere particularly specific
module
Helpers
// It's generally bad to have 'utils' bag of abstract functionality that grows forever,
// as soon as there's a logical grouping, spin off a module, maybe even a submodule
/// Take a function, and a tuple, and call the function with the destructured tuple
let
withTuple
f
(
a
,
b
)
=
f
a
b
/// Take anything, and give back a zero - a success exit code
let
returnZero
_
=
0
/// Takes a function and its param and wraps it in another function,
/// useful for if you need unit -> whatever or need to defer work
let
thunkOne
f
x
=
(
fun
_
->
f
x
)
Loader.fs
0 → 100644
View file @
d6e0fbb8
/// Load data into the db the easy way!
module
Loader
open
Domain
open
Helpers
// alias the DbAccess module with a shorter name, so it's explicit when DB
// side effects are happening, but it's still easy to read
module
DB
=
DbAccess
/// Take a tuple and make a cat in the db, then turn it into a string
let
private
tupleToCatStr
=
withTuple
mkCat
>>
DB
.
insertCat
>>
catToStr
let
private
rawCatData
=
[
(
"Denton"
,
"Gray Tabby"
)
(
"Mitzie"
,
"Tuxedo"
)
(
"Saphire"
,
"Blue Russian"
)
(
"Ailee"
,
"Siamese"
)
(
"Oreo"
,
"Tuxedo"
)
(
"Frisky"
,
"Tuxedo"
)
]
/// Loads a set of data into the db
let
load
()
=
rawCatData
|>
List
.
map
tupleToCatStr
|>
String
.
concat
", "
|>
printfn
"Made a bunch o cats!
\n
***
\n
%s
\n
***
\n
"
|>
returnZero
Program.fs
View file @
d6e0fbb8
open
FSharp
.
Data
.
Sql
[<
Literal
>]
let
DbVendor
=
Common
.
DatabaseProviderTypes
.
POSTGRESQL
[<
Literal
>]
let
ConnString
=
"Host=localhost;Port=5432;Database=postgres;Username=test_app;Password=pass"
[<
Literal
>]
let
Schema
=
"test"
[<
Literal
>]
let
ResPath
=
__
SOURCE_DIRECTORY__
+
@
"./lib"
[<
Literal
>]
let
IndivAmount
=
100
[<
Literal
>]
let
UseOptTypes
=
true
type
DB
=
SqlDataProvider
<
DatabaseVendor
=
DbVendor
,
ConnectionString
=
ConnString
,
ResolutionPath
=
ResPath
,
IndividualsAmount
=
IndivAmount
,
UseOptionTypes
=
UseOptTypes
,
Owner
=
Schema
>
let
ctx
=
DB
.
GetDataContext
(
selectOperations
=
SelectOperations
.
DatabaseSide
)
let
catDb
=
ctx
.
Test
// Domain modelling - normal F#!
/// A type of cat (ignoring attributes for now)
type
Breed
=
{
id
:
int
option
name
:
string
}
/// KITTEH
type
Cat
=
{
id
:
int
option
name
:
string
breed
:
Breed
}
/// Make a cat with just a name and breed name, with None for ids
let
mkCat
catName
breedName
=
{
id
=
None
;
name
=
catName
;
breed
=
{
id
=
None
;
name
=
breedName
}
}
/// Turn a cat to a string - my how the turn tables!
let
catToStr
cat
=
sprintf
"%s(%d)"
cat
.
name
(
Option
.
defaultValue
-
1
cat
.
id
)
// plain tables - query on these or get other functions
let
Attributes
=
catDb
.
Attributes
let
Cats
=
catDb
.
Cats
let
Breeds
=
catDb
.
Breeds
let
Owners
=
catDb
.
Owners
// join tables
let
BreedAttrs
=
catDb
.
BreedAttributes
let
OwnerCats
=
catDb
.
OwnerCats
// creating entity functions
let
createBreed
=
Breeds
.
``Create(name)``
let
createAttribute
=
Attributes
.
``Create(description, name)``
let
createCat
=
Cats
.
``Create(breedid, name)``
let
createOwner
=
Owners
.
``Create(age, name)``
let
createBreedAttr
=
BreedAttrs
.
``Create(attributeid, breedid)``
let
createOwnerCat
=
Owners
.
``Create(age, name)``
let
findBreedIdByName
bn
=
query
{
for
b
in
Breeds
do
where
(
b
.
Name
=
bn
)
take
1
select
b
.
Id
}
// DB functions
let
insertBreed
breedName
()
=
let
breedEntity
=
createBreed
(
breedName
)
ctx
.
SubmitUpdates
()
breedEntity
.
Id
let
insertCat
cat
=
let
breedId
=
findBreedIdByName
cat
.
breed
.
name
|>
Seq
.
tryHead
|>
Option
.
defaultWith
(
insertBreed
cat
.
breed
.
name
)
let
catEntity
=
createCat
(
breedId
,
cat
.
name
)
ctx
.
SubmitUpdates
()
{
cat
with
id
=
Some
catEntity
.
Id
;
breed
=
{
cat
.
breed
with
id
=
Some
breedId
}
}
// Helpers
/// Take a function, and a tuple, and call the function with the destructured tuple
let
withTuple
f
(
a
,
b
)
=
f
a
b
/// Take a tuple and make a cat in the db, then turn it into a string
let
tupleToCatStr
=
withTuple
mkCat
>>
insertCat
>>
catToStr
/// Take anything, and give back a zero - a success exit code
let
returnZero
_
=
0
let
rawCatData
=
[
(
"Denton"
,
"Gray Tabby"
)
(
"Mitzie"
,
"Tuxedo"
)
(
"Saphire"
,
"Blue Russian"
)
(
"Ailee"
,
"Siamese"
)
(
"Oreo"
,
"Tuxedo"
)
(
"Frisky"
,
"Tuxedo"
)
]
module
Program
[<
EntryPoint
>]
let
main
argv
=
rawCatData
|>
List
.
map
tupleToCatStr
|>
String
.
concat
", "
|>
printfn
"Made a bunch o cats!
\n
***
\n
%s
\n
***
\n
"
|>
returnZero
let
main
argv
=
printfn
"Loading up some cats!"
|>
Loader
.
load
test-sql-provider.fsproj
View file @
d6e0fbb8
...
...
@@ -11,6 +11,10 @@
</Target>
<ItemGroup>
<Compile Include="Helpers.fs" />
<Compile Include="Domain.fs" />
<Compile Include="DbAccess.fs" />
<Compile Include="Loader.fs" />
<Compile Include="Program.fs" />
</ItemGroup>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment