GithubHelp home page GithubHelp logo

bubdm / sqlquerybuilder Goto Github PK

View Code? Open in Web Editor NEW

This project forked from rem0o/sqlquerybuilder

0.0 0.0 0.0 74 KB

C# library to build type safe T-SQL queries around your POCO classes.

C# 100.00%

sqlquerybuilder's Introduction

SqlQueryBuilder Build Status

Main features:

  • Build all your Select/Update/Insert/Delete T-SQL queries arround your POCOs!
  • Fluent interface
  • Try-Build pattern (basic validation)
  • Evaluate once: use parameters ("@param") within the builder to parametrize your queries!

Other features

  • Build your complex "WHERE" clauses as sub-blocks you can assemble
  • Use complex selectors like aggregates and SQL functions by inheriting the SelectBuilder class.
  • Supports table name alias (when you join the same table multiple times)
  • All depedencies are abstracted and injected, can easily be integrated with any IoC library.

Code exemples

Here is a basic factory method to get a builder. This factory method can be registered into any container library.

private IQueryBuilderFactory GetBuilder()
{
    ISqlTranslator translatorFactory() => new SqlTranslator();
    ICompare compareFactory() => new Comparator();
    IWhereBuilderFactory whereBuilderFactory() => new WhereBuilderFactory(compareFactory);
    return new SqlQueryBuilderFactory(translatorFactory, whereBuilderFactory, compareFactory);
}

A basic SELECT query

Simply write your query with terms you are familiar with.

bool isValid = GetBuilder().GetSelect().From<Car>()
    .SelectAll<Car>()
    .Where(comparator => comparator.Compare<Car>(car => car.ModelYear).With(Operators.GT, "@year"))
    .TryBuild(out string query);
    
//@year can later be replaced with your favorite library

Resulting SQL:

SELECT [Car].* 
FROM [Car]
WHERE [CarMaker].[ModelYear] > @year

A basic UPDATE query

An update query is just as simple.

bool isValid = GetBuilder().GetUpdate().From<Car>("CarTableAlias")
   .Set(car => car.Mileage, "@mileage")
   .Where(c => c.Compare<Car>(car => car.Mileage).With(Operators.LT, "0"))
   .TryBuild(out string query); 

Resulting SQL:

UPDATE [CarTableAlias]
SET [CarTableAlias].[Mileage] = @mileage
FROM [Car] [CarTableAlias]
WHERE [CarTableAlias].[Mileage] < 0

Note the use of an alias for the "Car" table.

A basic INSERT INTO query

An insert query is also straightforward.

bool isValid = GetBuilder().GetInsert()
   .InsertInto<Car>(car => new {
	car.Id,
	car.ModelYear,
	car.Mileage,
	car.Price,
	car.CarMakerId
   }).Values("@id", "@modelYear", "@mileage", "@price", "@carMakerId")
   .TryBuild(out string query);  

Resulting SQL:

INSERT INTO [CAR] 
([Car].[Id], [Car].[ModelYear], [Car].[Mileage], [Car].[Price], [Car].[CarMakerId])
VALUES (@id, @modelYear, @mileage, @price, @carMakerId)

A DELETE query

By now you should expect the delete query to be just as simple. But here's a taste of more advanced features.

bool isValid = GetBuilder().GetDelete().DeleteFrom<Car>()
    .Join<Car, CarMaker>(car => car.CarMakerId, carMaker => carMaker.Id)
    .WhereFactory(f => f.Or(
        f1 => f1.Compare(c => c.Compare<CarMaker>(m => m.FoundationDate).With(Operators.LT, new DateTime(1950, 01, 01).ToShortDateString())),
        f2 => f2.Compare(c => c.Compare<Car>(car => car.Mileage).With(Operators.LTE, 50_000.ToString()))
    ));

Resulting SQL:

DELETE FROM [Car]
JOIN [CarMaker] ON [Car].[CarMakerId] = [CarMaker].[Id] 
WHERE ((([CarMaker].[FoundationDate]) < (1950-01-01)) OR (([Car].[Mileage]) <= (50000)))

Table alias

You can use table aliases if you want to join the same table multiple times.

const string TABLE1 = "MAKER1";
const string TABLE2 = "MAKER2";

var isValid = GetBuilder().GetSelect().From<CarMaker>(TABLE1)
    .Join<CarMaker, CarMaker>(maker1 => maker1.CountryOfOriginId, maker2 => maker2.CountryOfOriginId, TABLE1, TABLE2)
    .SelectAll<CarMaker>(TABLE1)
    .Where(comparator => comparator.Compare<CarMaker>(maker1 => maker1.Id, TABLE1).With<CarMaker>(Operators.NEQ, maker2 => maker2.Id, TABLE2))
    .TryBuild(out string query);

Resulting SQL:

SELECT [MAKER1].* 
FROM [CarMaker] AS [MAKER1]
JOIN [CarMaker] AS [MAKER2] ON [Maker1].[CountryOfOriginId] = [Maker2].[CountryOfOriginId]
WHERE [Maker1].[Id] <> [Maker2].Id

A more complex SELECT query

Here is a more complex query. Note the use of a complex selector (average aggregate).

var isValid = GetBuilder().GetSelect().From<Car>()
    .Join<Car, CarMaker>(car => car.CarMakerId, maker => maker.Id)
    .Select<CarMaker>(maker => maker.Name)
    .Select<Car>(car => car.ModelYear)
    .SelectAs(new Aggregate(AggregateFunctions.AVG).Select<Car>(car => car.Price), "AveragePrice")
    .GroupBy<Car>(car => car.ModelYear)
    .GroupBy<CarMaker>(maker => maker.Name)
    .TryBuild(out string query);

Resulting SQL:

SELECT AVG([Car].[Price]) AS [AveragePrice], [CarMaker].[Name], [Car].[ModelYear] 
FROM [Car]
JOIN [CarMaker] ON [Car].[CarMakerId] = [CarMaker].[Id]
GROUP BY [Car].[ModelYear], [CarMaker].[Name]

A complex selector is described as a class. Simply inherit SelectBuilder to create your own easily. The generic type <T> will enforce (or not using object) a specific type on your special selector. For example, here is a "DATEDIFF" implementation that requires the selector to be of a DateTime type.

// definition
public class DateDiff : SelectBuilder<DateTime>
{
    private readonly DateDiffType type;
    private readonly DateTime compareTo;

    public DateDiff(DateDiffType type, DateTime compareTo)
    {
        this.type = type;
        this.compareTo = compareTo;
    }

    protected override string BuildSelectClause(string column)
    {
        return $"DATEDIFF({type.ToString()}, '{compareTo.ToString("yyyy-MM-dd")}', {column})";
    }
}

// (...)

// usage
new DateDiff(DateDiffType.YEAR, new DateTime(2018,1,1))
    .Select<CarMaker>(maker => maker.FoundationDate);

Resulting SQL:

DATEDIFF(YEAR, '2018-01-01', [CarMaker].[FoundationDate])

WHERE is the fun?

People's car tastes can be all over the place, and so can be your "WHERE" clauses! Here are some "WHERE" conditions extracted as functions so we can use them later.

private IWhereBuilder CheapCarCondition(IWhereBuilderFactory factory)
{
    return factory.And(
        f => f.Compare(c => c.Compare<Car>(car => car.Mileage).With(Compare.LT, "@cheap_mileage")),
        f => f.Compare(c => c.Compare<Car>(car => car.Price).With(Compare.LT, "@cheap_price")),
        f => f.Compare(c => c.Compare<CarMaker>(maker => => maker.Name).With(Compare.NEQ, "@cheap_name")),
        f => f.Compare(c => c.Compare<Country>(country => country.Name).With(Compare.NEQ, "@cheap_country"))
    );
}

private IWhereBuilder DreamCarExceptionCondition(IWhereBuilderFactory factory)
{
    return factory.And(
        f => f.Compare(c => c.Compare<Car>(car => car.Mileage).With(Compare.LT, "@dream_mileage")),
        f => f.Compare(c => c.Compare<Car>(car => car.Price).With(Compare.LT, "@dream_price")),
        f => f.Compare(c => c.Compare<CarMaker>(maker => maker.Name).With(Compare.EQ, "@dream_maker"))
    );
}

The conditions above are assembled with a "OR" to create our very specific query! Also, notice the anonymous object used inside the select function.

var isValid = GetBuilder().GetSelect().From<Car>()
    .Join<Car, CarMaker>(car => car.CarMakerId, maker => maker.Id)
    .Join<CarMaker, Country>(maker => maker.CountryOfOriginId, country => country.Id)
    .Select<Car>(car => new { car.Id, car.Price })
    .WhereFactory(factory => factory.Or(
        CheapCarCondition,
        DreamCarExceptionCondition
    ))
    .OrderBy<Car>(car => car.Price, desc: true)
    .TryBuild(out string query);

Resulting SQL:

SELECT [Car].[Id], [Car].[Price] 
FROM [Car] 
JOIN [CarMaker] ON [Car].[CarMakerId] = [CarMaker].[Id] 
JOIN [Country] ON [CarMaker].[CountryOfOriginId] = [Country].[Id] 
WHERE (
  ((([Car].[Mileage]) < (@cheap_mileage)) AND 
  (([Car].[Price]) < (@cheap_price)) AND
  (([CarMaker].[Name]) <> (@cheap_maker)) AND
  (([Country].[Name]) <> (@cheap_country))
) OR (
  (([Car].[Mileage]) < (@dream_mileage)) AND
  (([Car].[Price]) < (@dream_price)) AND
  (([CarMaker].[Name]) = (@dream_maker)))
)
ORDER BY [Car].[Price] DESC

sqlquerybuilder's People

Contributors

dreamrunnermoshi avatar rem0o avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.