F# constructor with <"string", str> - f#

In this article it shows how to use the SqlCommandProvider type. The sample code has this:
use cmd = new SqlCommandProvider<"
SELECT TOP(#topN) FirstName, LastName, SalesYTD
FROM Sales.vSalesPerson
WHERE CountryRegionName = #regionName AND SalesYTD > #salesMoreThan
ORDER BY SalesYTD
" , connectionString>(connectionString)
what does the <... ,...> before the type constructor name mean and why the the
first parameter have to be a string literal? It looks like a generic but it's taking variables not types. The constructor seems to be taking in a connection string already in the <> section.

The angle brackets are the configuration for a type.
In your example, you are defining a type and creating an instance at the same type. It's clearer when the steps are separated.
Define a type.
type SalesPersonQuery = SqlCommandProvider<query, connectionString>
But to actually have an instance of the type you have to create it:
let command = new SalesPersonQuery()
Now you can use the command.Execute() rather then SalesPersonQuery.Execute().
The reason there is a constructor is because later on (at run-time) you can change the connection string to a different then the one provided in the definition, so for instance:
let command = new SalesPersonQuery(differentConnectionString)
You can find that in the documentation in configuration section:
Connection string can be overridden at run-time via constructor optional parameter
First parameter can be a path to a SQL script or a SQL query. I suppose that's the reason it's a string: how else would you like to define a SQL query?
Again, from the documentation:
Command text (sql script) can be either literal or path to *.sql file

Related

Why one dynamic value can be converted to other without casting and the other one fails?

final dList = <dynamic> [];
final List<String> sList1 = dList; // fails (can't implicitly cast)
final sList2 = dList.cast<String>(); // works (needs manual casting)
dynamic dString = '';
final String sString1 = dString; // works
final sString2 = dString as String; // works
You can see the comments in the code part what I am talking about, it is difficult to point out the piece of code here in writing part, so I added them in the code part.
List fails to convert but other types like bool, int, String works with internal casting.
The point is that dList is a List<dynamic>. The type dynamic is a top type (a supertype of all other types), and it's reified (so you can test it at run time, as opposed to Java where type arguments are erased at run time). With cast you are creating a new object, instance of List<String>, so it's allowed to be the value of a variable of that type.
With dString you already have an instance of type String (because '' evaluates to such an instance), so the cast just verifies that this is indeed a String.
You can never use a cast in Dart to obtain an object whose type is different from the starting point, it will only check the type of the existing object (and confirm that the type is as required, or throw).

Can you run code before creating a type provider? (F#)

Say:
let x = // some operation
type t = SomeTypeProvider<x>
Is this valid?
No.
Since the types must be generated at compile-time, the parameter to the type provider needs to be a constant.
In other words, the code you marked // some operation can evaluate to a literal, but cannot be a value returned by a runnable function:
let arg = "foo"
type t = SomeTypeProvider<arg> // okay
let [<Literal>] arg = """{"name":"foo","value":42}"""
type t = SomeTypeProvider<arg> // okay
let arg = x.ToString()
type t = SomeTypeProvider<arg> // Boom! arg is not a Literal
It depends on your application, but one of the most common cases is the following:
You have a database-related Type Provider, and the connection string needs to be retrieved in runtime, from some sort of config file or something. So a developer mistakenly thinks they need a runnable code to retrieve the connection string first and then pass it to the Type Provider.
The correct approach is the following:
Keep two databases: one locally stored in a constant location (just for schema), and another one for the runtime purposes.
Pass the first one (a constant!) to your Type Provider. Don't worry about the hardcoded paths; it is only used for schema retrieval.
// Use a fixed sample file for schema generation only
type MyCSVData = CsvProvider<"dummy.csv">
// Load the actual data at runtime
let data = MyCSVData.Load(RetrieveFileNameFromConfig())

SqlDataConnection type provider - setting database connection string with script parameter

The normal way of using a SqlDataConnection type provider is as follows:
type dbSchema = SqlDataConnection<"Data Source=MYSERVER\INSTANCE;InitialCatalog=MyDatabase;Integrated Security=SSPI;">
let db = dbSchema.GetDataContext()
However we have a problem which is we want to use this type provider in an f# script where the connection string for the database is passed as a parameter. So what I would like to do is something like this:
let connectionString= Array.get args 1
type dbSchema = SqlDataConnection<connectionString>
However it gives the error "This is not a constant expression or valid custom attribute value"
Is there any way to do this?
Unfortunately there's no way to do this, the type provider requires a compile time literal string. This is so that when you're compiling the application, the type provider's able to connect and retrieve the metadata about the database and generate the types for the compiler. You can choose to extract out the connection string into a string literal by writing it in the form
[<Literal>] let connString = "Data Source=..."
type dbSchema = SqlDataConnection<connString>
Assuming your 2 databases have the same schema, it's then possible to supply your runtime connection string as a parameter to the GetDataContext method like
let connectionString = args.[1]
let dbContext = dbSchema.GetDataContext(connectionString)
The way i've been doing it is i have a hardcoded literal string (using the "Literal" attribute) for design time use and use a local string from the configuration when getting the data context. I use a local db schema (also hardcoded) to speed up intelli-sense during development.
type private settings = AppSettings<"app.config">
let connString = settings.ConnectionStrings.MyConnectionString
type dbSchema = Microsoft.FSharp.Data.TypeProviders.SqlDataConnection<initialConnectionString, Pluralize = true, LocalSchemaFile = localDbSchema , ForceUpdate = false, Timeout=timeout>
let indexDb = dbSchema.GetDataContext(connString);

F# Sql Type Provider: How to access

I am using a TypeProvider to access some data like this:
type internal SqlConnection =
SqlEntityConnection<ConnectionString =
#"XXXXXXXXXX">
type FooRepository () =
member x.GetFoo (Id) =
let context = SqlConnection.GetDataContext()
query {for foo in context.Foos do
where (foo.Id = Id)
select foo}
The problem is I am getting this:
The type 'FooRepository' is less accessible than the value, member or type 'member System.Linq.IQueryable' it is used in
I see the same problem asked on SO here.
Since I want to expose this type and I don't like the solutions on SO, I tried doing this:
SqlDataConnection<ConnectionString =
#"XXXXXXX">
The problem is that the database is on Azure Sql Server so I am getting this:
The type provider 'Microsoft.FSharp.Data.TypeProviders.DesignTime.DataProviders' reported an error: Error reading schema. Warning : SQM1012: Unable to extract table 'dbo.Foos from SqlServer.
Does anyone have an idea about how to get around this? One of the best things about using TPs is that I don't need to explicitly defines the types - but it looks like I am going to have to? Ugh
Are you sure the error you are getting is the one you posted here? My impression is that
the type which is less accessible should be the one from the generated database schema
(because you mark that as internal).
I tried reproducing your error by writing a simple library that uses the Northwind database:
open Microsoft.FSharp.Data.TypeProviders
type internal Nwind = SqlDataConnection<"Data Source=.\sqlexpress;Initial Catalog=Northwind;Integrated Security=True">
type NwindLibrary() =
let nw = Nwind.GetDataContext()
member this.Products = nw.Products
And I get the following message:
The type 'Products' is less accessible than the value, member or type 'member Class1.Products : System.Data.Linq.Table' it is used in C:\temp\Library1\Library1\Library1.fs 9 17 Library1
This is what I was expecting - because the Nwind type (generated by a provider) is marked as internal. However, the NwindLibrary type is public and the property Products (that I defined) returns a value of type IQueryable<Table<Nwind.ServiceTypes.Product>>. The compiler error is not particularly useful here (because it says that the type returns just Table), but the problem is that Nwind.ServiceTypes.Product is internal and so you cannot return it in a public property of a public type.
If you make the Nwind type public, then it should work fine. If you do not want to make the generated types public, then you'll have to wrap the returned values in your custom types. For example, even if you leave the type internal, the following works fine (returning a tuple instead of generated type):
member this.Products =
query { for p in mys.Products do
select (p.ProductID, p.ProductName) }

how to to find a string in groovy list

question from a groovy newbie:
sql is initiated as follows
final Binding binding = new Binding();
binding.setProperty("sql", sql);
final groovy.sql.Sql sql = Sql.newInstance(dbConfig.getUrl(), dbConfig.getUserName(), dbConfig.getPasswd(),"oracle.jdbc.OracleDriver");
I am running a query in groovy like this
def listOfRows = sql.rows (select column1 from table1);
listOfRows when printed shows contents like [[column1_name:value1], [column1_name:value2], [column1_name:value3]]
I want to check if value2 (a String) exists in the returned list of values from the above query.
I have tried doing listOfRows.contains('value2') and listOfRows.find('value2'),
it complains that the method does not exist for lists..
what's the best way of doing this ?
EDITED: I have corrected the list of printed values. What's being returned is List<GroovyResultSet>
and I have also added the definition of sql.
I would suggest you to take a look at groovy documentation, and particularly to collections documentation (both tutorial and JDK/GDK).
in that case, the most specifically adapted solution would be to use Collection#find() ... with something like
listOfRows.find { it.contains(':value2') }
Which can be translated into human-readable
find the first element in this collection which string contains ":value2".
You probably want
listOfRows.column1.contains( 'value2' )
You are probably invoking this method which takes a GString (note that GString != String) as an argument. According to this question, a string in single quotes is a standard java string, and a string in double quotes is a templatable string.
'hello' //java.lang.String
"hello" //groovy.lang.GString
Try this:
listOfRows.contains("value2")
what i ended up doing is following :
iterate the listOfRows, get all the values for column1 from each GroovyResultSet into a listOfValues ,then check for my values in that list.
def listOfValues=[];
listOfRows.collect(listOfValues){it.getAt('column1')};
if(listOfValues.size()==3){
println('success');
}

Resources