Skip to content

Commit

Permalink
refactor: break implementation into normalize/replacement/query (#156)
Browse files Browse the repository at this point in the history
  • Loading branch information
cyjake committed Aug 11, 2021
1 parent a02b495 commit 6f9874c
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 61 deletions.
57 changes: 20 additions & 37 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ function createSpine(opts) {
return class Spine extends Bone {};
}

const rReplacementKey = /\s:(\w+)\b/g;

class Realm {
constructor(opts = {}) {
const { client, dialect, database, ...restOpts } = {
Expand Down Expand Up @@ -169,63 +171,44 @@ class Realm {
* @memberof Realm
*/
async query(query, values, opts = {}) {
let res, fieldRes, restRes = {};
if (values && typeof values === 'object' && !Array.isArray(values)) {
query = query + ' ';
let valueResults = [];
const replaceTemplates = query.match(/\s:\w+\s/g);
const templateKeys = replaceTemplates.map((t) => t.trim().split(':')[1]);
let replacementKeys;
let replacements = {};
if ('replacements' in values) {
const { model, connection } = values;
replacements = values.replacements;
if (replacements == null) {
throw new Error('[leoric] replacements not match with values in raw query');
}
opts.replacements = values.replacements;
if (model) opts.model = model;
if (connection) opts.connection = connection;
} else {
replacements = values;
}
replacementKeys = Object.keys(replacements);
if (replaceTemplates.length > replacementKeys.length) {
throw new Error('[leoric] replacements not match with values in raw query');
opts.replacements = values;
}
for (const templateKey of templateKeys) {
if (!replacementKeys.includes(templateKey)) {
throw new Error('[leoric] replacements not match with values in raw query');
}
valueResults.push(replacements[templateKey]);
values = [];
}

const replacements = opts.replacements || {};
query = query.replace(rReplacementKey, function replacer(m, key) {
if (!replacements.hasOwnProperty(key)) {
throw new Error(`unable to replace :${key}`);
}
query = query.replace(/\s:\w+\s/g, '?');
values.push(replacements[key]);
return '?';
});

const { rows, fields, ...others } = await this.driver.query(query, valueResults, opts);
restRes = others;
res = rows;
fieldRes = fields;
} else {
const { rows, fields, ...others } = await this.driver.query(query, values, opts);
restRes = others;
res = rows;
fieldRes = fields;
}
const { rows, ...restRes } = await this.driver.query(query, values, opts);
const results = [];

let results = [];
if (res && res.length && opts.model && opts.model.prototype instanceof this.Bone) {
if (rows && rows.length && opts.model && opts.model.prototype instanceof this.Bone) {
const { attributeMap } = opts.model;

for (const data of res) {
for (const data of rows) {
const instance = opts.model.instantiate(data);
for (const key in data) {
if (!attributeMap.hasOwnProperty(key)) instance[key] = data[key];
}
results.push(instance);
}
}

return {
rows: results.length? results : res,
fields: fieldRes,
rows: results.length > 0 ? results : rows,
...restRes
};
}
Expand Down
48 changes: 24 additions & 24 deletions test/unit/realm.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ describe('=> Realm', () => {
database: 'leoric',
models: [ User, Post ],
});

await realm.connect();
const createdAt = new Date();
const post = await Post.create({ title: 'title', authorId: 1, createdAt });
Expand All @@ -234,14 +234,14 @@ describe('=> Realm', () => {
assert(rows.length === 1);
assert(rows[0] instanceof Post);
assert(post1.authorId === rows[0].authorId);

// work with join table
const user = await User.create({ id: 1, nickname: 'userName', status: 1, email: 'aaa@h.com' });

const { rows: rows1 } = await realm.query(`
SELECT Post.*, users.nickname as authorName
FROM articles as Post
LEFT JOIN users
SELECT Post.*, users.nickname as authorName
FROM articles as Post
LEFT JOIN users
ON users.id = Post.author_id
WHERE users.id = ?
`, [ user.id ], { model: Post });
Expand All @@ -258,7 +258,7 @@ describe('=> Realm', () => {
database: 'leoric',
models: [ User, Post ],
});

await realm.connect();
const createdAt = new Date();
const post = await Post.create({ title: 'title', authorId: 1, createdAt });
Expand All @@ -269,15 +269,15 @@ describe('=> Realm', () => {
assert(rows.length === 1);
assert(rows[0] instanceof Post);
assert(post1.authorId === rows[0].authorId);

// work with join table
const user = await User.create({ id: 1, nickname: 'userName', status: 1, email: 'aaa@h.com' });

const { rows: rows1 } = await realm.query(`
SELECT Post.*, users.nickname as authorName
FROM articles as Post
LEFT JOIN users
ON users.id = Post.author_id
SELECT Post.*, users.nickname as authorName
FROM articles as Post
LEFT JOIN users
ON users.id = Post.author_id
WHERE users.id = :userId
`, {
userId: user.id
Expand All @@ -295,7 +295,7 @@ describe('=> Realm', () => {
database: 'leoric',
models: [ User, Post ],
});

await realm.connect();
const createdAt = new Date();
const post = await Post.create({ title: 'title', authorId: 1, createdAt });
Expand All @@ -310,14 +310,14 @@ describe('=> Realm', () => {
assert(rows.length === 1);
assert(rows[0] instanceof Post);
assert(post1.authorId === rows[0].authorId);

// work with join table
const user = await User.create({ id: 1, nickname: 'userName', status: 1, email: 'aaa@h.com' });

const { rows: rows1 } = await realm.query(`
SELECT Post.*, users.nickname as authorName
FROM articles as Post
LEFT JOIN users
SELECT Post.*, users.nickname as authorName
FROM articles as Post
LEFT JOIN users
ON users.id = Post.author_id
WHERE users.id = :userId
AND users.status = :status
Expand All @@ -340,9 +340,9 @@ describe('=> Realm', () => {
database: '/tmp/leoric.sqlite3',
models: [ Post ],
});

await realm.connect();

const createdAt = new Date();
await Post.create({ title: 'title', authorId: 1, createdAt });
const { rows } = await realm.query('SELECT * FROM articles');
Expand All @@ -356,23 +356,23 @@ describe('=> Realm', () => {
database: 'leoric',
models: [ User, Post ],
});

await realm.connect();
const createdAt = new Date();
const post1 = await Post.create({ title: 'title1', authorId: 2, createdAt });
await assert.rejects(async () => {
await realm.query('SELECT * FROM articles where title = :title AND author_id = :authorId', {
title: post1.title
}, { model: Post });
}, 'Error: [leoric] replacements not match with values in raw query');
}, /Error: unable to replace :authorId/);

await assert.rejects(async () => {
await realm.query('SELECT * FROM articles where title = :title AND author_id = :authorId', {
replacements: {
title: post1.title,
}
}, { model: Post });
}, 'Error: [leoric] replacements not match with values in raw query');
}, /Error: unable to replace :authorId/);

await assert.rejects(async () => {
await realm.query('SELECT * FROM articles where title = :title AND author_id = :authorId', {
Expand All @@ -381,17 +381,17 @@ describe('=> Realm', () => {
hello: 'ye'
}
}, { model: Post });
}, 'Error: [leoric] replacements not match with values in raw query');
}, /Error: unable to replace :authorId/);

await assert.rejects(async () => {
await realm.query('SELECT * FROM articles where title = :title', {
replacements: null
}, { model: Post });
}, 'Error: [leoric] replacements not match with values in raw query');
}, /Error: unable to replace :title/);

await assert.rejects(async () => {
await realm.query('SELECT * FROM articles where title = :title', null, { model: Post });
}, "Error: ER_BAD_FIELD_ERROR: Unknown column 'authorId' in 'where clause'");
}, /Error: unable to replace :title/);

});
});
Expand Down

0 comments on commit 6f9874c

Please sign in to comment.