Skip to content

Commit

Permalink
Add prettier
Browse files Browse the repository at this point in the history
  • Loading branch information
felixmosh committed Apr 12, 2022
1 parent c326840 commit 9985634
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 88 deletions.
1 change: 1 addition & 0 deletions .husky/.gitignore
@@ -0,0 +1 @@
_
4 changes: 4 additions & 0 deletions .husky/pre-commit
@@ -0,0 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

npx lint-staged
98 changes: 52 additions & 46 deletions __tests__/index.spec.js
Expand Up @@ -15,10 +15,9 @@ const db = knex({
user: process.env.MYSQL_USER,
password: process.env.MYSQL_PASSWORD,
database: process.env.MYSQL_DATABASE,
}
},
});


function getById(id) {
return db('persons').where({ id }).first();
}
Expand All @@ -30,37 +29,39 @@ describe('onDuplicateUpdate', () => {

describe('validation', () => {
it('should throw if applied to none insert query', () => {
expect(() => db('persons').select('id').onDuplicateUpdate(''))
.toThrowError('onDuplicateUpdate error: should be used only with insert query.');
expect(() => db('persons').select('id').onDuplicateUpdate('')).toThrowError(
'onDuplicateUpdate error: should be used only with insert query.'
);
});

it('should throw if no columns given', () => {
expect(() => db.insert({ id: 1, name: 'test' }).into('persons').onDuplicateUpdate())
.toThrowError('onDuplicateUpdate error: please specify at least one column name.');
expect(() =>
db.insert({ id: 1, name: 'test' }).into('persons').onDuplicateUpdate()
).toThrowError('onDuplicateUpdate error: please specify at least one column name.');
});
it('should throw if columns are not string or object', () => {
expect(() => db.insert({ id: 1, name: 'test' }).into('persons').onDuplicateUpdate(false))
.toThrowError('onDuplicateUpdate error: expected column name to be string or object.');
expect(() =>
db.insert({ id: 1, name: 'test' }).into('persons').onDuplicateUpdate(false)
).toThrowError('onDuplicateUpdate error: expected column name to be string or object.');
});
it('should throw if insert is empty array', () => {
expect(() => db.insert([]).into('persons').onDuplicateUpdate('whatever'))
.toThrowError('onDuplicateUpdate error: empty insert statement.');
expect(() => db.insert([]).into('persons').onDuplicateUpdate('whatever')).toThrowError(
'onDuplicateUpdate error: empty insert statement.'
);
});
});

describe('behaviour', () => {
it('should allow insert new row', async () => {
const person = { id: 2, name: 'test' };
await db.insert(person).into('persons')
.onDuplicateUpdate('name');
await db.insert(person).into('persons').onDuplicateUpdate('name');
const insertPerson = await getById(2);
expect(insertPerson).toEqual(expect.objectContaining(person));
});

it('should update on duplicate', async () => {
await db.insert({ id: 3, name: 'test3' }).into('persons');
await db.insert({ id: 3, name: 'test33' }).into('persons')
.onDuplicateUpdate('name');
await db.insert({ id: 3, name: 'test33' }).into('persons').onDuplicateUpdate('name');
const person = await getById(3);

expect(person.name).toBe('test33');
Expand All @@ -69,11 +70,13 @@ describe('onDuplicateUpdate', () => {
it('should allow updating multiple columns', async () => {
const id = 4;
await db.insert({ id, name: 'test4', email: '1@1.com' }).into('persons');
await db.insert({
id,
name: 'test5',
email: '5@5.com'
}).into('persons')
await db
.insert({
id,
name: 'test5',
email: '5@5.com',
})
.into('persons')
.onDuplicateUpdate('name', 'email');
const person = await getById(id);

Expand All @@ -83,45 +86,48 @@ describe('onDuplicateUpdate', () => {
it('should allow specifying a value for a column when updating multiple', async () => {
const id = 5;
await db.insert({ id, name: 'test6', email: '6@6.com' }).into('persons');
await db.insert({
id,
name: 'test6',
email: '6@6.com'
}).into('persons')
.onDuplicateUpdate({ 'email': 'updated-email', 'name': 'update-name' });
await db
.insert({
id,
name: 'test6',
email: '6@6.com',
})
.into('persons')
.onDuplicateUpdate({ email: 'updated-email', name: 'update-name' });

const person = await getById(id);
expect(person).toEqual(expect.objectContaining({
name: 'update-name',
email: 'updated-email',
}));
expect(person).toEqual(
expect.objectContaining({
name: 'update-name',
email: 'updated-email',
})
);
});

it('should allow specifying a value for a column when updating multiple and mix types', async () => {
const id = 6;
await db.insert({ id, name: 'test6', email: '6@6.com' }).into('persons');
await db.insert({
id,
name: 'test6',
email: '6@6.com'
}).into('persons')
.onDuplicateUpdate({ 'email': 'updated-email' }, 'name');
await db
.insert({
id,
name: 'test6',
email: '6@6.com',
})
.into('persons')
.onDuplicateUpdate({ email: 'updated-email' }, 'name');

const person = await getById(id);
expect(person).toEqual(expect.objectContaining({
name: 'test6',
email: 'updated-email',
}));
expect(person).toEqual(
expect.objectContaining({
name: 'test6',
email: 'updated-email',
})
);
});

it('should correctly escape field with ? character', async () => {
await db
.insert({ id: 7, name: 'other value' })
.into('persons');
await db
.insert({ id: 7, name: '?' })
.into('persons')
.onDuplicateUpdate('name');
await db.insert({ id: 7, name: 'other value' }).into('persons');
await db.insert({ id: 7, name: '?' }).into('persons').onDuplicateUpdate('name');
const person = await getById(7);

expect(person.name).toBe('?');
Expand Down
44 changes: 22 additions & 22 deletions lib/index.js
Expand Up @@ -10,36 +10,36 @@ module.exports.attachOnDuplicateUpdate = function attachOnDuplicateUpdate() {
throw new Error('onDuplicateUpdate error: please specify at least one column name.');
}

const { placeholders, bindings } = columns.reduce((result, column) => {
if (typeof column === 'string') {
result.placeholders.push(`??=Values(??)`);
result.bindings.push(column, column);
} else if (column && typeof column === 'object') {
Object.keys(column).forEach((key) => {
result.placeholders.push(`??=?`);
result.bindings.push(key, column[key]);
});
} else {
throw new Error('onDuplicateUpdate error: expected column name to be string or object.');
}

return result;
}, { placeholders: [], bindings: [] });

const {
sql: originalSQL,
bindings: originalBindings,
} = this.toSQL();
const { placeholders, bindings } = columns.reduce(
(result, column) => {
if (typeof column === 'string') {
result.placeholders.push(`??=Values(??)`);
result.bindings.push(column, column);
} else if (column && typeof column === 'object') {
Object.keys(column).forEach((key) => {
result.placeholders.push(`??=?`);
result.bindings.push(key, column[key]);
});
} else {
throw new Error('onDuplicateUpdate error: expected column name to be string or object.');
}

return result;
},
{ placeholders: [], bindings: [] }
);

const { sql: originalSQL, bindings: originalBindings } = this.toSQL();

if (!originalBindings.length) {
throw new Error('onDuplicateUpdate error: empty insert statement.')
throw new Error('onDuplicateUpdate error: empty insert statement.');
}

const newBindings = [...originalBindings, ...bindings];

return this.client.raw(
`${originalSQL} on duplicate key update ${placeholders.join(', ')}`,
newBindings,
newBindings
);
});
};
45 changes: 25 additions & 20 deletions package.json
Expand Up @@ -2,35 +2,39 @@
"name": "knex-on-duplicate-update",
"version": "2.1.3",
"description": "Simple patcher for Knex. It adds the .onDuplicateUpdate() function to knex's query builder.",
"keywords": [
"knex",
"on duplicate update",
"upsert"
],
"homepage": "https://github.com/felixmosh/knex-on-duplicate-update#readme",
"bugs": {
"url": "https://github.com/felixmosh/knex-on-duplicate-update/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/felixmosh/knex-on-duplicate-update.git"
},
"license": "ISC",
"author": "Felixmosh",
"main": "lib/index.js",
"types": "types.d.ts",
"files": [
"lib/*",
"types.d.ts"
],
"scripts": {
"release": "release-it",
"test": "jest",
"test:types": "tsd",
"version": "auto-changelog -p && git add CHANGELOG.md",
"release": "release-it"
"version": "auto-changelog -p && git add CHANGELOG.md"
},
"repository": {
"type": "git",
"url": "git+https://github.com/felixmosh/knex-on-duplicate-update.git"
"lint-staged": {
"*.ts": [
"prettier --write" ]
},
"keywords": [
"knex",
"on duplicate update",
"upsert"
],
"author": "Felixmosh",
"license": "ISC",
"bugs": {
"url": "https://github.com/felixmosh/knex-on-duplicate-update/issues"
},
"homepage": "https://github.com/felixmosh/knex-on-duplicate-update#readme",
"peerDependencies": {
"knex": ">= 0.95.1"
"jest": {
"testEnvironment": "node"
},
"devDependencies": {
"@types/jest": "^27.0.1",
Expand All @@ -40,11 +44,12 @@
"jest": "^27.0.6",
"knex": "0.95.9",
"mysql": "^2.18.1",
"prettier": "^2.6.2",
"release-it": "^14.4.1",
"tsd": "^0.17.0"
},
"jest": {
"testEnvironment": "node"
"peerDependencies": {
"knex": ">= 0.95.1"
},
"release-it": {
"git": {
Expand Down
5 changes: 5 additions & 0 deletions prettier.config.js
@@ -0,0 +1,5 @@
module.exports = {
printWidth: 100,
trailingComma: 'es5',
singleQuote: true,
};
5 changes: 5 additions & 0 deletions yarn.lock
Expand Up @@ -3393,6 +3393,11 @@ prepend-http@^2.0.0:
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897"
integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=

prettier@^2.6.2:
version "2.6.2"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.6.2.tgz#e26d71a18a74c3d0f0597f55f01fb6c06c206032"
integrity sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==

pretty-format@^27.0.0, pretty-format@^27.0.6:
version "27.0.6"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.0.6.tgz#ab770c47b2c6f893a21aefc57b75da63ef49a11f"
Expand Down

0 comments on commit 9985634

Please sign in to comment.