Skip to content

Commit

Permalink
(#3) Added DELETE statement
Browse files Browse the repository at this point in the history
  • Loading branch information
SiroDiaz committed Jun 6, 2019
1 parent 8145a65 commit 83cac23
Show file tree
Hide file tree
Showing 5 changed files with 167 additions and 57 deletions.
47 changes: 43 additions & 4 deletions __tests__/statements/delete_statement.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,44 @@
describe('Unit tests for DELETE statement', () => {
test('Delete all from the an index', () => {
expect(true).toBeTruthy();
import QueryBuilder from '../../src/QueryBuilder';
import SphinxClient from '../../src/SphinxClient';
require('iconv-lite').encodingExists('foo'); // fix bug with mysql2 and Jest

describe('Tests for DELETE statement', () => {
const params = {
host: '127.0.0.1',
port: 9307,
};

test('deletes with a where condition', () => {
const conn = new SphinxClient(params);
const compiledQuery = new QueryBuilder(conn)
.delete('rt')
.where('id', '=', 2)
.generate();
const expectedQuery = `DELETE FROM rt WHERE id = 2`;

expect(compiledQuery).toBe(expectedQuery);
});
});

test('deletes with a match condition', () => {
const conn = new SphinxClient(params);
const compiledQuery = new QueryBuilder(conn)
.delete('rt')
.match(['title', 'content'], 'dinosaur')
.generate();
const expectedQuery = `DELETE FROM rt WHERE MATCH('(@(title,content) dinosaur)')`;

expect(compiledQuery).toBe(expectedQuery);
});

test('deletes with multiple conditions', () => {
const conn = new SphinxClient(params);
const compiledQuery = new QueryBuilder(conn)
.delete('rt')
.match(['title', 'content'], 'dinosaur')
.where('published_at', '<', 2030)
.generate();
const expectedQuery = `DELETE FROM rt WHERE MATCH('(@(title,content) dinosaur)') AND published_at < 2030`;

expect(compiledQuery).toBe(expectedQuery);
});
});
51 changes: 6 additions & 45 deletions __tests__/statements/update_statement.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import QueryBuilder from '../../src/QueryBuilder';
import SphinxClient from '../../src/SphinxClient';
import Expression from '../../src/Statements/Expression';
require('iconv-lite').encodingExists('foo'); // fix bug with mysql2 and Jest

describe('Tests for UPDATE statement', () => {
Expand All @@ -10,7 +9,7 @@ describe('Tests for UPDATE statement', () => {
};
// UPDATE index SET col1 = newval1 [, ...] WHERE where_condition [OPTION opt_name = opt_value [, ...]]

test('create an update statement with a where condition', () => {
test('updates with a where condition', () => {
const conn = new SphinxClient(params);
const compiledQuery = new QueryBuilder(conn)
.update('rt')
Expand All @@ -22,7 +21,7 @@ describe('Tests for UPDATE statement', () => {
expect(compiledQuery).toBe(expectedQuery);
});

test('create an update statement with a match condition', () => {
test('updates with a match condition', () => {
const conn = new SphinxClient(params);
const compiledQuery = new QueryBuilder(conn)
.update('rt')
Expand All @@ -34,20 +33,20 @@ describe('Tests for UPDATE statement', () => {
expect(compiledQuery).toBe(expectedQuery);
});

test('create an update query with multiple conditions', () => {
test('updates with multiple conditions', () => {
const conn = new SphinxClient(params);
const compiledQuery = new QueryBuilder(conn)
.update('rt')
.set({title: 'UPDATE no dinosaurs in 2030!'})
.set({title: "UPDATE there\'re not dinosaurs in 2030!"})
.match(['title', 'content'], 'dinosaur')
.where('published_at', '<', 2030)
.generate();
const expectedQuery = `UPDATE rt SET title='UPDATE no dinosaurs in 2030!' WHERE MATCH('(@(title,content) dinosaur)') AND published_at < 2030`;
const expectedQuery = `UPDATE rt SET title='UPDATE there\\'re not dinosaurs in 2030!' WHERE MATCH('(@(title,content) dinosaur)') AND published_at < 2030`;

expect(compiledQuery).toBe(expectedQuery);
});

it('uses OPTION expression for customizing the search', () => {
it('updates with OPTION expression for customizing the search', () => {
const conn = new SphinxClient(params);
let compiledQuery = new QueryBuilder(conn)
.select('id')
Expand All @@ -58,43 +57,5 @@ describe('Tests for UPDATE statement', () => {
let expectedQuery = `SELECT id FROM rt_sales WHERE MATCH('(@product_name "iPhone XS")') OPTION ranker='sph04'`;

expect(compiledQuery).toBe(expectedQuery);

compiledQuery = new QueryBuilder(conn)
.select('id')
.from('rt_sales')
.match('product_name', '"iPhone XS"', false)
.orMatch('*', '"iphone apple"~4', false)
.option('ranker', Expression.raw('sph04'))
.option('field_weights', {product_name: 100})
.generate();
expectedQuery = `SELECT id FROM rt_sales WHERE MATCH('(@product_name "iPhone XS") | (@* "iphone apple"~4)') OPTION ranker=sph04,field_weights=(product_name=100)`;

expect(compiledQuery).toBe(expectedQuery);

compiledQuery = new QueryBuilder(conn)
.select('id')
.from('rt_sales')
.match('product_name', '"iPhone XS"')
.orMatch('*', '"iphone apple"~4', false)
.limit(5)
.option('ranker', Expression.raw('sph04'))
.option('field_weights', {product_name: 100})
.generate();
expectedQuery = `SELECT id FROM rt_sales WHERE MATCH('(@product_name \"iPhone XS\") | (@* "iphone apple"~4)') LIMIT 5 OPTION ranker=sph04,field_weights=(product_name=100)`;

expect(compiledQuery).toBe(expectedQuery);

compiledQuery = new QueryBuilder(conn)
.select('id')
.from('rt_sales')
.match('product_name', '"iPhone XS"')
.orMatch('*', '"iphone apple"~4', false)
.limit(5)
.option('ranker', Expression.raw('sph04'))
.option('field_weights', {product_name: 100, other: 1})
.generate();
expectedQuery = `SELECT id FROM rt_sales WHERE MATCH('(@product_name \"iPhone XS\") | (@* "iphone apple"~4)') LIMIT 5 OPTION ranker=sph04,field_weights=(product_name=100,other=1)`;

expect(compiledQuery).toBe(expectedQuery);
});
});
5 changes: 3 additions & 2 deletions src/QueryBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import InsertStatement from './Statements/InsertReplaceStatement';
import SelectStatement from './Statements/SelectStatement';
import TransactionStatement from './Statements/TransactionStatement';
import UpdateStatement from './Statements/UpdateStatement';
import DeleteStatement from './Statements/DeleteStatement';

export default class QueryBuilder {
// protected type: QueryType;
Expand Down Expand Up @@ -41,8 +42,8 @@ export default class QueryBuilder {
return new UpdateStatement(this.connection, index);
}

public delete() {

public delete(index: string): DeleteStatement {
return new DeleteStatement(this.connection, index);
}

public transaction(): TransactionStatement {
Expand Down
6 changes: 0 additions & 6 deletions src/QueryType.ts

This file was deleted.

115 changes: 115 additions & 0 deletions src/Statements/DeleteStatement.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import MatchExprStatement from './statement_expressions/MatchStatement';
import ClientInterface from '../ClientInterface';
import WhereStatement from './statement_expressions/WhereStatement';
import StatementBuilderBase from './StatementBuilderBase';

/**
* DELETE FROM index WHERE where_condition
*/
export default class DeleteStatement {
protected connection: ClientInterface;
protected index: string;
protected matchStatement: MatchExprStatement = new MatchExprStatement();
protected whereConditions: WhereStatement[] = [];

public constructor(connection: ClientInterface, index: string) {
this.connection = connection;
this.index = index;
}

/**
*
* @param columnExpr
* @param operator
* @param value
*/
public where(columnExpr: string, operator: string, value?: any): DeleteStatement {
if (value === undefined) {
value = operator;
operator = '=';
}

const condition = new WhereStatement(columnExpr, operator, value);
this.whereConditions = [...this.whereConditions, condition];

return this;
}

public whereIn(column: string, values: any[]) {
const condition = new WhereStatement(column, 'IN', values);
this.whereConditions = [...this.whereConditions, condition];

return this;
}

public whereNotIn(column: string, values: any[]) {
const condition = new WhereStatement(column, 'NOT IN', values);
this.whereConditions = [...this.whereConditions, condition];

return this;
}

public between(column: string, value1: any, value2: any) {
const condtion = new WhereStatement(column, 'BETWEEN', [value1, value2]);
this.whereConditions = [...this.whereConditions, condtion];

return this;
}

/**
* Adds an AND logical operator (by default) to the new full text condition.
* It recieves a field or an array of string fields to match against.
* "value" parameter is used for the text to match.
* If escapeValue is true (default) it will escape full text operators
* to prevent security issues, else the value will contain syntax FT operators
* to make possible use proximity, negation, exact phrase, and so forth.
*/
public match(fields: string[] | string, value: string, escapeValue: boolean = true) {
this.matchStatement.match(fields.length ? fields : undefined, value, escapeValue);

return this;
}

/**
* Adds an OR "|" logical operator to the new full text condition.
* It MUST be used after call "match" method because "orMatch" preppends
* the OR operator.
*/
public orMatch(fields: string[] | string, value: string, escapeValue: boolean = true) {
this.matchStatement.orMatch(fields.length ? fields : undefined, value, escapeValue);

return this;
}

public generate() : string {
let statement = 'DELETE FROM ';
statement += this.index;

const hasMatchStatement: boolean = this.matchStatement.getParts().length > 0;
const hasWhereStatements: boolean = this.whereConditions.length > 0;

if (hasWhereStatements || hasMatchStatement) {
statement += ' WHERE ';

if (hasMatchStatement) {
statement += `MATCH(${this.matchStatement.build()})`;
if (hasWhereStatements) {
statement += ' AND ';
}
}

let stringStatements: string[];
stringStatements = this.whereConditions.map((condition: StatementBuilderBase) => condition.build());
statement += stringStatements.join(' AND ');
}

return statement;
}

public execute() {
const query = this.generate();
// make query

return query;
}
}

0 comments on commit 83cac23

Please sign in to comment.