Skip to content
This repository has been archived by the owner on Mar 3, 2022. It is now read-only.

Commit

Permalink
❇️ Added support for ODBC and SQL connections
Browse files Browse the repository at this point in the history
  • Loading branch information
mike-eason committed Jan 12, 2017
1 parent 5072bf7 commit 9a1844f
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 86 deletions.
161 changes: 85 additions & 76 deletions Data.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,122 +4,109 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Data.Odbc;
using System.Data.OleDb;
using System.Data.SqlClient;
using System.Dynamic;
using System.Threading.Tasks;

public class Startup
{
private string _ConnectionString;

public async Task<object> Invoke(IDictionary<string, object> parameters)
{
//Convert the input parameters to a useable object.
ParameterCollection pcol = new ParameterCollection(parameters);

_ConnectionString = pcol.ConnectionString;

//Work out which query type to execute.
switch (pcol.QueryType)
{
case QueryTypes.query:
return await ExecuteQuery(pcol.Query, pcol.Parameters);
case QueryTypes.scalar:
return await ExecuteScalar(pcol.Query, pcol.Parameters);
case QueryTypes.command:
return await ExecuteNonQuery(pcol.Query, pcol.Parameters);
default:
throw new InvalidOperationException("Unsupported type of SQL command type. Only query and command are supported.");
}
}

private async Task<object> ExecuteQuery(string query, object[] parameters)
{
OleDbConnection connection = null;

try
using (DbConnection connection = CreateConnection(pcol.ConnectionString, pcol.ConnectionType))
{
using (connection = new OleDbConnection(_ConnectionString))
try
{
await connection.OpenAsync();

using (var command = new OleDbCommand(query, connection))
//Work out which query type to execute.
switch (pcol.QueryType)
{
List<object> results = new List<object>();

AddCommandParameters(command, parameters);

using (OleDbDataReader reader = command.ExecuteReader())
{
do
{
results.Add(await ParseReaderRow(reader));
}
while (await reader.NextResultAsync());

return results;
}
case QueryTypes.query:
return await ExecuteQuery(connection, pcol.Query, pcol.Parameters);
case QueryTypes.scalar:
return await ExecuteScalar(connection, pcol.Query, pcol.Parameters);
case QueryTypes.command:
return await ExecuteNonQuery(connection, pcol.Query, pcol.Parameters);
default:
throw new InvalidOperationException("Unsupported type of SQL command type. Only query and command are supported.");
}
}
}
finally
{
if (connection != null)
finally
{
connection.Close();
}
}
}

private async Task<object> ExecuteScalar(string query, object[] parameters)
private DbConnection CreateConnection(string connectionString, ConnectionTypes type)
{
OleDbConnection connection = null;
switch (type)
{
case ConnectionTypes.oledb:
return new OleDbConnection(connectionString);
case ConnectionTypes.odbc:
return new OdbcConnection(connectionString);
case ConnectionTypes.sql:
return new SqlConnection(connectionString);
}

throw new NotImplementedException();
}

try
private async Task<object> ExecuteQuery(DbConnection connection, string query, object[] parameters)
{
using (var command = connection.CreateCommand())
{
using (connection = new OleDbConnection(_ConnectionString))
command.CommandText = query;

AddCommandParameters(command, parameters);

using (DbDataReader reader = command.ExecuteReader())
{
await connection.OpenAsync();
List<object> results = new List<object>();

using (var command = new OleDbCommand(query, connection))
do
{
AddCommandParameters(command, parameters);

return await command.ExecuteScalarAsync();
results.Add(await ParseReaderRow(reader));
}
while (await reader.NextResultAsync());

return results;
}
}
finally
{
if (connection != null)
connection.Close();
}
}

private async Task<object> ExecuteNonQuery(string query, object[] parameters)
private async Task<object> ExecuteScalar(DbConnection connection, string query, object[] parameters)
{
OleDbConnection connection = null;

try
using (var command = connection.CreateCommand())
{
using (connection = new OleDbConnection(_ConnectionString))
{
await connection.OpenAsync();
command.CommandText = query;

using (var command = new OleDbCommand(query, connection))
{
AddCommandParameters(command, parameters);
AddCommandParameters(command, parameters);

return await command.ExecuteNonQueryAsync();
}
}
return await command.ExecuteScalarAsync();
}
finally
}

private async Task<object> ExecuteNonQuery(DbConnection connection, string query, object[] parameters)
{
using (var command = connection.CreateCommand())
{
if (connection != null)
connection.Close();
command.CommandText = query;

AddCommandParameters(command, parameters);

return await command.ExecuteNonQueryAsync();
}
}

private async Task<List<object>> ParseReaderRow(OleDbDataReader reader)
private async Task<List<object>> ParseReaderRow(DbDataReader reader)
{
List<object> rows = new List<object>();
IDataRecord row = reader;
Expand Down Expand Up @@ -152,14 +139,18 @@ private async Task<List<object>> ParseReaderRow(OleDbDataReader reader)
return rows;
}

private void AddCommandParameters(OleDbCommand command, object[] parameters)
private void AddCommandParameters(DbCommand command, object[] parameters)
{
//Generate names for each parameter and add them to the parameter collection.
for (int i = 0; i < parameters.Length; i++)
{
string name = string.Format("@p{0}", i + 1);

command.Parameters.Add(new OleDbParameter(name, parameters[i]));
DbParameter param = command.CreateParameter();
param.ParameterName = name;
param.Value = parameters[i];

command.Parameters.Add(param);
}
}
}
Expand All @@ -171,11 +162,19 @@ public enum QueryTypes
command
}

public enum ConnectionTypes
{
oledb,
odbc,
sql
}

public class ParameterCollection
{
private IDictionary<string, object> _Raw;

public string ConnectionString { get; private set; }
public ConnectionTypes ConnectionType { get; private set; }
public QueryTypes QueryType { get; private set; }
public string Query { get; private set; }
public object[] Parameters { get; private set; }
Expand Down Expand Up @@ -203,6 +202,16 @@ private void ParseRawParameters()
if (string.IsNullOrEmpty(Query))
throw new ArgumentNullException("query");

//Extract the provider type (optional)
object connectionType = null;

_Raw.TryGetValue("connection", out connectionType);

if (connectionType == null)
connectionType = "oledb";

ConnectionType = (ConnectionTypes)Enum.Parse(typeof(ConnectionTypes), connectionType.ToString().ToLower());

//Extract and command type (optional)
object commandType = null;

Expand Down
39 changes: 30 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# oledb.js

[![npm version](https://img.shields.io/badge/npm-v1.2.0-blue.svg)](https://www.npmjs.com/package/oledb)
[![npm version](https://img.shields.io/badge/npm-v1.3.0-blue.svg)](https://www.npmjs.com/package/oledb)
[![license](https://img.shields.io/badge/license-MIT-orange.svg)](LICENSE)
[![tips](https://img.shields.io/badge/tips-bitcoin-brightgreen.svg)](https://www.coinbase.com/blahyourhamster)

A small **promise based** module which uses [Edge](https://github.com/tjanczuk/edge) to connect and execute queries for an [OLE DB](https://en.wikipedia.org/wiki/OLE_DB).
A small **promise based** module which uses [Edge](https://github.com/tjanczuk/edge) to connect and execute queries for an
[OLE DB](https://en.wikipedia.org/wiki/OLE_DB), [ODBC](https://en.wikipedia.org/wiki/Open_Database_Connectivity) or [SQL](https://en.wikipedia.org/wiki/SQL) database.

## Example
```
Expand All @@ -13,7 +14,7 @@ const connectionString = 'provider=vfpoledb;data source=C:/MyDatabase.dbc';
const oledb = require('oledb');
const db = oledb(connectionString);
let command = `select * from account`;
let command = 'select * from account';
db.query(command)
.then(function(results) {
Expand All @@ -29,27 +30,47 @@ function(error) {
npm install oledb --save
```

## Options
The initializer can take up to two parameters:

- `oledb(connectionString)` - Initializes a connection and assumes you are using an **OLE DB** connection.
- `oledb(connectionString, connectionType)` - Initializes a connection to a database where `connectionType` is either `oledb`, `odbc` or `sql`.

Here is an example:

```
const connectionString = 'Server=myServerAddress;Database=myDataBase;Trusted_Connection=True;';
const connectionType = 'sql';
const oledb = require('oledb');
const db = oledb(connectionString, connectionType);
...
```

## Promises
There are 3 available promises exposed by the module:

- `.query(command, parameters)` - Executes a query and returns the result set returned by the query as an `Array`.
- `.execute(command, parameters)` - Executes a query command and returns the number of rows affected.
- `.scalar(command, parameters)` - Executes the query and returns the first column of the first row in the result set returned by the query. All other columns and rows are ignored.
- `.scalar(command, parameters)` - Executes a query and returns the first column of the first row in the result set returned by the query. All other columns and rows are ignored.

Where `command` is the query string and `parameters` is an array of parameter values.

*Where `command` is the query string and `parameters` is an array of parameter values.*
*Please note that `parameters` are **optional**.*

## Query Parameters
Parameters are also supported and uses positional parameters that are marked with a question mark (?) instead of named parameters. Here is an example:
Parameters are also supported and use positional parameters that are marked with a question mark (?) instead of named parameters. Here is an example:

```
let command = `
select * from account
where
firstname = ?
and id = ?
and age = ?
`;
let parameters = [ 'Bob', 123 ];
let parameters = [ 'Bob', 69 ];
db.query(command, parameters)
.then(function(results) {
Expand All @@ -61,7 +82,7 @@ function(error) {
```

## Multiple Data Sets
OLE DB provides multiple data sets that can be returned in a single query. Here is an example:
The `.query` promise has support for multiple data sets that can be returned in a single query. Here is an example:

```
let command = `
Expand Down
6 changes: 5 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
const edge = require('edge');
const data = edge.func(__dirname + '/Data.cs');

module.exports = function(constring) {
module.exports = function(constring, contype) {
if (constring == null || constring.trim() === '')
throw 'constring must not be null or empty';
if (contype == null || contype.trim() === '')
contype = 'oledb';

let connectionString = constring;
let connectionType = contype;

function executePromise(command, type, params) {
return new Promise(function(resolve, reject) {
let options = {
constring: connectionString,
connection: connectionType,
query: command,
type: type,
params: params || []
Expand Down

0 comments on commit 9a1844f

Please sign in to comment.