diff --git a/samples/demos/belgrade-product-catalog-demo/Controllers/ProductCatalogController.cs b/samples/demos/belgrade-product-catalog-demo/Controllers/ProductCatalogController.cs index a01f9a82d2..f3c1b46b9b 100644 --- a/samples/demos/belgrade-product-catalog-demo/Controllers/ProductCatalogController.cs +++ b/samples/demos/belgrade-product-catalog-demo/Controllers/ProductCatalogController.cs @@ -1,6 +1,7 @@ using Microsoft.AspNetCore.Mvc; using ProductCatalog.Models; using System; +using System.Collections.Generic; using System.Linq; namespace ProductCatalog.Controllers @@ -46,5 +47,22 @@ public IActionResult Report2() ViewData["page"] = "report2"; return View(); } + + [HttpGet(Name = "GetAll")] + public IEnumerable GetAll() + { + return _context.Products.AsEnumerable(); + } + + [HttpGet("GetById")] + public IActionResult GetById(int id) + { + var product = _context.Products.FirstOrDefault(p=>p.ProductId == id); + if (product == null) + { + return NotFound(); + } + return new ObjectResult(product); + } } } \ No newline at end of file diff --git a/samples/demos/belgrade-product-catalog-demo/Startup.cs b/samples/demos/belgrade-product-catalog-demo/Startup.cs index 309f4c44e6..f115293e87 100644 --- a/samples/demos/belgrade-product-catalog-demo/Startup.cs +++ b/samples/demos/belgrade-product-catalog-demo/Startup.cs @@ -1,4 +1,5 @@ -using Belgrade.SqlClient.SqlDb; +using Belgrade.SqlClient; +using Belgrade.SqlClient.SqlDb; using Belgrade.SqlClient.SqlDb.Rls; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; @@ -58,14 +59,14 @@ public void ConfigureServices(IServiceCollection services) services.AddDbContext(options => options.UseSqlServer(new SqlConnection(ConnString))); // Adding data access services/components. - services.AddTransient( + services.AddTransient( sp => new QueryPipe(new SqlConnection(ConnString)) - .AddRls("CompanyID",() => GetCompanyIdFromSession(sp)) + //.AddRls("CompanyID",() => GetCompanyIdFromSession(sp)) ); - services.AddTransient( + services.AddTransient( sp => new Command(new SqlConnection(ConnString)) - .AddRls("CompanyID", () => GetCompanyIdFromSession(sp)) + //.AddRls("CompanyID", () => GetCompanyIdFromSession(sp)) ); //// Add framework services. diff --git a/samples/demos/belgrade-product-catalog-demo/project.json b/samples/demos/belgrade-product-catalog-demo/project.json index 0935c448a9..c3a083b4bf 100644 --- a/samples/demos/belgrade-product-catalog-demo/project.json +++ b/samples/demos/belgrade-product-catalog-demo/project.json @@ -1,6 +1,6 @@ { "dependencies": { - "Belgrade.Sql.Client": "0.6.2", + "Belgrade.Sql.Client": "0.6.5", "Microsoft.AspNetCore.Mvc": "1.0.0", "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", "Microsoft.AspNetCore.Server.Kestrel": "1.0.0", diff --git a/samples/demos/belgrade-product-catalog-demo/sql-scripts/8. bcp.sql b/samples/demos/belgrade-product-catalog-demo/sql-scripts/8. bcp.sql new file mode 100644 index 0000000000..8981d8fd2f --- /dev/null +++ b/samples/demos/belgrade-product-catalog-demo/sql-scripts/8. bcp.sql @@ -0,0 +1,36 @@ +CREATE TABLE Orders ( + OrderID int, + OrderDate date, + Status varchar(16), + DeliveryDate date, + Data nvarchar(4000) +) + +CREATE TABLE OrderLines ( + OrderLineID int, + OrderID int, + ProductID int, + Quantity int, + UnitPrice decimal, + TaxRate decimal +) + +CREATE EXTERNAL DATA SOURCE MyAzureBlobStorage +WITH ( TYPE = BLOB_STORAGE, LOCATION = 'https://myazureblobstorage.blob.core.windows.net/data'); + + +BULK INSERT Orders +FROM 'orders.bcp' +WITH ( DATA_SOURCE = 'MyAzureBlobStorage', + FORMATFILE = 'orders.fmt', + FORMATFILE_DATA_SOURCE = 'MyAzureBlobStorage', + TABLOCK); + + +BULK INSERT OrderLines +FROM 'orderlines.bcp' +WITH ( DATA_SOURCE = 'MyAzureBlobStorage', + FORMATFILE = 'orderlines.fmt', + FORMATFILE_DATA_SOURCE = 'MyAzureBlobStorage', + TABLOCK); + diff --git a/samples/demos/belgrade-product-catalog-demo/sql-scripts/9. string-agg.sql b/samples/demos/belgrade-product-catalog-demo/sql-scripts/9. string-agg.sql new file mode 100644 index 0000000000..7baecd676b --- /dev/null +++ b/samples/demos/belgrade-product-catalog-demo/sql-scripts/9. string-agg.sql @@ -0,0 +1,37 @@ +select c.Name, c.Contact, STRING_AGG(p.Name,',') as Products +from Company c + join Product p on c.CompanyID = p.CompanyID +group by c.CompanyID, c.Name, c.Contact + +select c.Name, c.Contact, + '[' + STRING_AGG('"' + STRING_ESCAPE(p.Name) + '"',',') + ']' as Products +from Company c + join Product p on c.CompanyID = p.CompanyID +group by c.CompanyID, c.Name, c.Contact + +select c.Name, c.Contact, + JSON_QUERY('[' + STRING_AGG('"' + STRING_ESCAPE(p.Name) + '"',',') + ']') as Products +from Company c + join Product p on c.CompanyID = p.CompanyID +group by c.CompanyID, c.Name, c.Contact +for json path; + +WITH CustomerAlsoBuy as ( +select p.ProductID, p2.Name, p2.ProductID as RelatedProductID, + ROW_NUMBER() OVER (PARTITION BY p.ProductID ORDER BY count(ol2.OrderID) desc) orders +from Product p + join OrderLines ol1 + on p.ProductID = ol1.ProductID + join OrderLines ol2 + on ol1.OrderID = ol2.OrderID + and ol1.ProductID <> ol2.ProductID + join Product p2 + on ol2.ProductID = p2.ProductID +group by p.ProductID, p.Name, p2.ProductID, p2.Name +) +select ProductID, + '['+STRING_AGG( + CONCAT('{"ProductID":',RelatedProductID,',"Product":"',STRING_ESCAPE(Name,'json'),'"}'),',') + ']' Products +from CustomerAlsoBuy +where orders <= 5 +group by ProductID diff --git a/samples/demos/belgrade-product-catalog-demo/sql-scripts/bcp/bcp-export-order-lines-from-wwi.bat b/samples/demos/belgrade-product-catalog-demo/sql-scripts/bcp/bcp-export-order-lines-from-wwi.bat new file mode 100644 index 0000000000..1b8ad895df --- /dev/null +++ b/samples/demos/belgrade-product-catalog-demo/sql-scripts/bcp/bcp-export-order-lines-from-wwi.bat @@ -0,0 +1 @@ +bcp "select OrderLineID, OrderID, 15 + StockItemId%%14 as ProductID, Quantity, UnitPrice, TaxRate from Sales.OrderLines" queryout .\orderlines.bcp -S "." -d WideWorldImporters -T \ No newline at end of file diff --git a/samples/demos/belgrade-product-catalog-demo/sql-scripts/bcp/bcp-export-orders-from-wwi.bat b/samples/demos/belgrade-product-catalog-demo/sql-scripts/bcp/bcp-export-orders-from-wwi.bat new file mode 100644 index 0000000000..f254490fc8 --- /dev/null +++ b/samples/demos/belgrade-product-catalog-demo/sql-scripts/bcp/bcp-export-orders-from-wwi.bat @@ -0,0 +1 @@ +bcp "select o.OrderID, OrderDate, case when OrderDate > '2016-04-28' then 'Cancelled' when OrderDate <= '2016-04-28' and OrderDate > '2016-01-01' then 'Delivering' when OrderDate <= '2016-01-01' and OrderDate > '2013-01-10' then 'Delivered' else 'Open' end as Status, DATEADD(day, 3 + (o.OrderID %% 7),OrderDate) as DeliveryDate, ReturnedDeliveryData as Data from Sales.Orders o join Sales.Invoices i on o.OrderId = i.OrderId" queryout .\orders.bcp -S "." -d WideWorldImporters -T \ No newline at end of file diff --git a/samples/demos/belgrade-product-catalog-demo/sql-scripts/bcp/bcp-import-order-lines.bat b/samples/demos/belgrade-product-catalog-demo/sql-scripts/bcp/bcp-import-order-lines.bat new file mode 100644 index 0000000000..61a592fbd3 --- /dev/null +++ b/samples/demos/belgrade-product-catalog-demo/sql-scripts/bcp/bcp-import-order-lines.bat @@ -0,0 +1 @@ +bcp dbo.OrderLines in .\orderlines.bcp -f orderlines.fmt -S 127.0.0.1 -d ProductCatalog -T \ No newline at end of file diff --git a/samples/demos/belgrade-product-catalog-demo/sql-scripts/bcp/bcp-import-orders.bat b/samples/demos/belgrade-product-catalog-demo/sql-scripts/bcp/bcp-import-orders.bat new file mode 100644 index 0000000000..fe7d926cef --- /dev/null +++ b/samples/demos/belgrade-product-catalog-demo/sql-scripts/bcp/bcp-import-orders.bat @@ -0,0 +1 @@ +bcp dbo.Orders in .\orders.bcp -f orders.fmt -S 127.0.0.1 -d ProductCatalog -T \ No newline at end of file diff --git a/samples/demos/belgrade-product-catalog-demo/sql-scripts/bcp/export-order-lines-from-wwi.bat b/samples/demos/belgrade-product-catalog-demo/sql-scripts/bcp/export-order-lines-from-wwi.bat new file mode 100644 index 0000000000..705d80f082 --- /dev/null +++ b/samples/demos/belgrade-product-catalog-demo/sql-scripts/bcp/export-order-lines-from-wwi.bat @@ -0,0 +1 @@ +bcp "select OrderLineID, OrderID, 15 + StockItemId%%14 as ProductID, Quantity, UnitPrice, TaxRate from Sales.OrderLines" queryout .\orderlines.bcp -S "." -d WideWorldImporters -T \ No newline at end of file diff --git a/samples/demos/belgrade-product-catalog-demo/sql-scripts/bcp/orderlines.bcp b/samples/demos/belgrade-product-catalog-demo/sql-scripts/bcp/orderlines.bcp new file mode 100644 index 0000000000..811fd07871 Binary files /dev/null and b/samples/demos/belgrade-product-catalog-demo/sql-scripts/bcp/orderlines.bcp differ diff --git a/samples/demos/belgrade-product-catalog-demo/sql-scripts/bcp/orderlines.fmt b/samples/demos/belgrade-product-catalog-demo/sql-scripts/bcp/orderlines.fmt new file mode 100644 index 0000000000..16f2d6f2d6 --- /dev/null +++ b/samples/demos/belgrade-product-catalog-demo/sql-scripts/bcp/orderlines.fmt @@ -0,0 +1,8 @@ +13.0 +6 +1 SQLINT 0 4 "" 1 OrderLineID "" +2 SQLINT 0 4 "" 2 OrderID "" +3 SQLINT 1 4 "" 3 ProductID "" +4 SQLINT 0 4 "" 4 Quantity "" +5 SQLDECIMAL 1 19 "" 5 UnitPrice "" +6 SQLDECIMAL 1 19 "" 6 TaxRate "" diff --git a/samples/demos/belgrade-product-catalog-demo/sql-scripts/bcp/orders.bcp b/samples/demos/belgrade-product-catalog-demo/sql-scripts/bcp/orders.bcp new file mode 100644 index 0000000000..a2c814ff91 Binary files /dev/null and b/samples/demos/belgrade-product-catalog-demo/sql-scripts/bcp/orders.bcp differ diff --git a/samples/demos/belgrade-product-catalog-demo/sql-scripts/bcp/orders.fmt b/samples/demos/belgrade-product-catalog-demo/sql-scripts/bcp/orders.fmt new file mode 100644 index 0000000000..4b9b998c1c --- /dev/null +++ b/samples/demos/belgrade-product-catalog-demo/sql-scripts/bcp/orders.fmt @@ -0,0 +1,7 @@ +13.0 +5 +1 SQLINT 0 4 "" 1 OrderID "" +2 SQLDATE 1 3 "" 2 OrderDate "" +3 SQLCHAR 2 10 "" 3 Status Latin1_General_100_CI_AS +4 SQLDATE 1 3 "" 4 DeliveryDate "" +5 SQLNCHAR 8 0 "" 5 Data Latin1_General_100_CI_AS diff --git a/samples/demos/belgrade-product-catalog-demo/test/ProductListComparison.jmx b/samples/demos/belgrade-product-catalog-demo/test/ProductListComparison.jmx new file mode 100644 index 0000000000..a239a96bea --- /dev/null +++ b/samples/demos/belgrade-product-catalog-demo/test/ProductListComparison.jmx @@ -0,0 +1,163 @@ + + + + + + false + false + + + + + + + + continue + + false + -1 + + 2 + 1 + 1486984219000 + 1486984219000 + false + + + + + + + + + localhost + 5000 + + + + + + HttpClient4 + 6 + + + + + + + + + + + + + /ProductCatalog/GetAll + GET + true + false + true + false + false + + + + + + + + + + + + + + api/Product + GET + true + false + true + false + false + + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + false + true + false + false + false + true + 0 + true + true + true + true + true + + + + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + false + true + false + false + false + true + 0 + true + true + true + true + true + + + + + + + + + true + + + + diff --git a/samples/features/json/todo-app/nodejs-express4-rest-api/.vscode/launch.json b/samples/features/json/todo-app/nodejs-express4-rest-api/.vscode/launch.json new file mode 100644 index 0000000000..1973b38ff2 --- /dev/null +++ b/samples/features/json/todo-app/nodejs-express4-rest-api/.vscode/launch.json @@ -0,0 +1,21 @@ +{ + // Use IntelliSense to learn about possible Node.js debug attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Launch Program", + "program": "${workspaceRoot}\\bin\\www", + "cwd": "${workspaceRoot}" + }, + { + "type": "node", + "request": "attach", + "name": "Attach to Process", + "port": 5858 + } + ] +} \ No newline at end of file diff --git a/samples/features/json/todo-app/nodejs-express4-rest-api/README.md b/samples/features/json/todo-app/nodejs-express4-rest-api/README.md index 1a848930fb..f59ad0cbdc 100644 --- a/samples/features/json/todo-app/nodejs-express4-rest-api/README.md +++ b/samples/features/json/todo-app/nodejs-express4-rest-api/README.md @@ -29,7 +29,8 @@ To run this sample, you need the following prerequisites. **Software prerequisites:** 1. SQL Server 2016 (or higher) or an Azure SQL Database -2. Visual Studio 2015 (or higher) with the NodeJS +2. Node.js runtime. + **Azure prerequisites:** @@ -39,13 +40,12 @@ To run this sample, you need the following prerequisites. ## Run this sample -1. Navigate to the folder where you have downloaded sample and run **npm install** in command window, or run setup.bat if you are on Windows operating system. This command will install necessary npm packages defined in project.json. - -2. From SQL Server Management Studio or SQL Server Data Tools connect to your SQL Server 2016 or Azure SQL database and execute setup.sql script that will create and populate Todo table in the database. +1. Navigate to the folder where you have downloaded sample and run **npm install** in command window. -3. From Visual Studio, open the **TodoApp.xproj** file from the root directory, +2. From SQL Server Management Studio or SQL Server Data Tools connect to your SQL Server 2016 or Azure SQL database and +execute setup.sql script that will create and populate Todo table in the database. -4. Locate db.js file in the project, change database connection info in createConnection() method to reference your database. the following tokens should be replaced: +3. Locate db.js file in the project, change database connection info in createConnection() method to reference your database. the following tokens should be replaced: 1. SERVERNAME - name of the database server. 2. DATABASE - Name of database where Todo table is stored. 3. USERNAME - SQL Server login that can access table data and execute stored procedures. @@ -61,10 +61,9 @@ To run this sample, you need the following prerequisites. }; ``` -5. Build project using Ctrl+Shift+B, right-click on project + Build, or Build/Build Solution from menu. - -6. Run sample app using F5 or Ctrl+F5. /todo Url will be opened with a list of all Todo items as a JSON array, - 1. Open /api/Todo/1 Url to get details about a single Todo item with id 1, +4. Run sample app from the command line using **node app.js** + 1. Open http://localhost:3000/todo Url to get list of all Todo items from a table, + 2. Open http://localhost:3000/todo/1 Url to get details about a single Todo item with id 1, 2. Send POST, PUT, or DELETE Http requests to update content of Todo table. diff --git a/samples/features/json/todo-app/nodejs-express4-rest-api/app.js b/samples/features/json/todo-app/nodejs-express4-rest-api/app.js index e5392350c8..3decc4113b 100644 --- a/samples/features/json/todo-app/nodejs-express4-rest-api/app.js +++ b/samples/features/json/todo-app/nodejs-express4-rest-api/app.js @@ -11,5 +11,10 @@ app.use(function (req, res, next) { err.status = 404; next(err); }); +app.set('port', process.env.PORT || 3000); + +var server = app.listen(app.get('port'), function() { + console.log('Express server listening on port ' + server.address().port); +}); module.exports = app; diff --git a/samples/features/json/todo-app/nodejs-express4-rest-api/bin/www b/samples/features/json/todo-app/nodejs-express4-rest-api/bin/www index 0f63533ba6..4d9bddf04e 100644 --- a/samples/features/json/todo-app/nodejs-express4-rest-api/bin/www +++ b/samples/features/json/todo-app/nodejs-express4-rest-api/bin/www @@ -1,9 +1,3 @@ #!/usr/bin/env node var debug = require('debug')('nodejs_express4_rest_api'); var app = require('../app'); - -app.set('port', process.env.PORT || 3000); - -var server = app.listen(app.get('port'), function() { - debug('Express server listening on port ' + server.address().port); -}); diff --git a/samples/features/json/todo-app/nodejs-express4-rest-api/db.js b/samples/features/json/todo-app/nodejs-express4-rest-api/db.js index 6dae4c2833..5d8cddc112 100644 --- a/samples/features/json/todo-app/nodejs-express4-rest-api/db.js +++ b/samples/features/json/todo-app/nodejs-express4-rest-api/db.js @@ -30,40 +30,47 @@ function createRequest(query, connection) { function stream (query, connection, output, defaultContent) { - errorHandler = function (ex) { throw ex; }; var request = query; if (typeof query == "string") { request = this.createRequest(query, connection); } - + pipe(request, output, defaultContent); +} + +function pipe (request, output, defaultContent) { var empty = true; request.on('row', function (columns) { empty = false; output.write(columns[0].value); }); - + request.on('done', function (rowCount, more, rows) { - if (empty) { - output.write(defaultContent); - } - output.end(); + _OnDone(empty, defaultContent, output); }); - + request.on('doneProc', function (rowCount, more, rows) { - if (empty) { + _OnDone(empty, defaultContent, output); + }); +} + +function _OnDone(empty, defaultContent, output) { + if(empty) { output.write(defaultContent); - } - output.end(); - }); - - connection.on('connect', function (err) { - if (err) { - throw err; - } - connection.execSql(request); - }); + } + try { output.end(); } catch (err) { /* Ignore stream close error. */ } + } + +function executeRequest (request, connection) { + connection.on('connect', function (err) { + if (err) { + throw err; + } + connection.execSql(request); + }); } module.exports.createConnection = createConnection; -module.exports.createRequest = createRequest; -module.exports.stream = stream; \ No newline at end of file +module.exports.createRequest = createRequest; +module.exports.executeRequest = executeRequest; +module.exports.stream = stream; +module.exports.pipe = pipe; \ No newline at end of file diff --git a/samples/features/json/todo-app/nodejs-express4-rest-api/routes/todo.js b/samples/features/json/todo-app/nodejs-express4-rest-api/routes/todo.js index 7eb08aa0b4..5df302c8ce 100644 --- a/samples/features/json/todo-app/nodejs-express4-rest-api/routes/todo.js +++ b/samples/features/json/todo-app/nodejs-express4-rest-api/routes/todo.js @@ -27,12 +27,7 @@ router.post('/', function (req, res) { request.addParameter('todo', TYPES.NVarChar, req.body); - connection.on('connect', function (err) { - if (err) { - throw err; - } - connection.execSql(request); - }); + db.executeRequest(request, connection); }); /* PUT update task. */ @@ -44,12 +39,7 @@ router.put('/:id', function (req, res) { request.addParameter('id', TYPES.Int, req.params.id); request.addParameter('todo', TYPES.NVarChar, req.body); - connection.on('connect', function (err) { - if (err) { - throw err; - } - connection.execSql(request); - }); + db.executeRequest(request, connection); }); /* DELETE single task. */ @@ -60,12 +50,7 @@ router.delete('/:id', function (req, res) { request.addParameter('id', TYPES.Int, req.params.id); - connection.on('connect', function (err) { - if (err) { - throw err; - } - connection.execSql(request); - }); + db.executeRequest(request, connection); }); module.exports = router; \ No newline at end of file