Socket
Socket
Sign inDemoInstall

mql2

Package Overview
Dependencies
53
Maintainers
1
Versions
40
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

    mql2

query builder


Version published
Weekly downloads
109
increased by2.83%
Maintainers
1
Install size
2.14 MB
Created
Weekly downloads
ย 

Readme

Source

MQL - Node.js ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ฟผ๋ฆฌ ๋นŒ๋”

ํŠน์ง•

  • INSERT, UPDATE, WHERE ์ ˆ ๋“ฑ์— ํ•„์š”ํ•œ ๋ณต์žกํ•œ ์ฟผ๋ฆฌ๋ฅผ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ฐ์ฒด๋ฅผ ํ†ตํ•ด ์‰ฝ๊ฒŒ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ผ๋ฐ˜์ ์ธ SQL ๋ฌธ๋ฒ•์„ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์–ด, ์„œ๋ธŒ ์ฟผ๋ฆฌ, ์กฐ์ธ ๋“ฑ์„ ์‰ฝ๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • SQL์„ ์„ธ๋ฐ€ํ•˜๊ฒŒ ํŠœ๋‹ํ•˜๊ณ  ๋ฐœ์ „์‹œํ‚ค๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค.
  • ๊ฐ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์ง€์›ํ•˜๋Š” ๋‹ค์–‘ํ•œ ์ตœ์‹  Operator ๋“ค์„ ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    • (์˜ˆ. https://www.postgresql.org/docs/current/static/functions-json.html)
  • SQL Injection ๊ณต๊ฒฉ์ด ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
  • Associations์„ ์œ„ํ•ด ๋ชจ๋ธ์„ ๋ฏธ๋ฆฌ ๊ตฌ์„ฑํ•ด๋‘˜ ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.
  • Transaction์„ ์‚ฌ์šฉํ•˜๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค.
  • ์ธ์ž์™€ ๊ฒฐ๊ณผ ๊ฐ’์„ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ๊ธฐ๋ณธ ๊ฐ’์œผ๋กœ๋งŒ(object, array, string, number, true, false, null) ๊ตฌ์„ฑํ•˜์—ฌ, ์กฐํ•ฉ์„ฑ์ด ๋†’๊ณ  JSON ๋ณ€ํ™˜ ๋น„์šฉ์ด ์—†์Šต๋‹ˆ๋‹ค.
  • PostgreSQL, MySQL ์ง€์›

๋ชฉ์ฐจ

์„ค์น˜

npm i mql2

์—ฐ๊ฒฐ

PostgreSQL

const { PostgreSQL } = require('mql2');
const { CONNECT } = PostgreSQL;
const POOL = await CONNECT({
  host: 'localhost',
  user: 'username',
  password: '1234',
  database: 'dbname'
});

PostgreSQL Connection ์˜ต์…˜

MQL์€ ๋‚ด๋ถ€์ ์œผ๋กœ node-postgres๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. CONNECT ํ•จ์ˆ˜์— ์‚ฌ์šฉ๋˜๋Š” ์˜ต์…˜์€ node-postgres์™€ ๋™์ผํ•ฉ๋‹ˆ๋‹ค. ๋””๋น„ ์—ฐ๊ฒฐ์ด๋‚˜ ์ปค๋„ฅ์…˜ ํ’€๊ณผ ๊ด€๋ จ๋œ ์ž์„ธํ•œ ์˜ต์…˜์€ node-postgres ์‚ฌ์ดํŠธ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

MySQL

const { MySQL } = require('mql2');
const { CONNECT } = MySQL;
const POOL = await CONNECT({
  host: 'localhost',
  user: 'username',
  password: '1234',
  database: 'dbname'
});

MySQL Connection ์˜ต์…˜

MQL์€ ๋‚ด๋ถ€์ ์œผ๋กœ mysql๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. CONNECT ํ•จ์ˆ˜์— ์‚ฌ์šฉ๋˜๋Š” ์˜ต์…˜์€ mysql๊ณผ ๋™์ผํ•ฉ๋‹ˆ๋‹ค. ๋””๋น„ ์—ฐ๊ฒฐ์ด๋‚˜ ์ปค๋„ฅ์…˜ ํ’€๊ณผ ๊ด€๋ จ๋œ ์ž์„ธํ•œ ์˜ต์…˜์€ mysql ์‚ฌ์ดํŠธ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฐ„๋‹จํ•œ ์ฟผ๋ฆฌ

const { QUERY } = POOL;
const id = 10;
const posts = await QUERY `SELECT * FROM posts WHERE id = ${id}`;
// [{ id: 10, ... }]

์„œ๋ธŒ ์ฟผ๋ฆฌ, ์กฐ์ธ

const type = 'TYPE1';
const limit = 10;

QUERY `
  SELECT * FROM table1 WHERE table2_id IN (
    SELECT id FROM table2 WHERE type = ${type} ORDER BY id DESC LIMIT ${limit}
  )
`;

const status = 'STATUS1';

QUERY `
  SELECT *
    FROM table1 AS t1, table2 AS t2
    WHERE t1.id = t2.table1_id AND t1.status = ${status}
    ORDER BY id DESC
    LIMIT 10
`;

CONNECT๋ฅผ ํ†ตํ•ด ์–ป์€ QUERY๋Š” connection pool์„ ์ด์šฉํ•ฉ๋‹ˆ๋‹ค.

ํ•จ์ˆ˜ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ

const POOL = await CONNECT();
const = {
  VALUES, IN, NOT_IN, EQ, SET, COLUMN, CL, TABLE, TB, SQL, MQL_DEBUG,
  QUERY,
  ASSOCIATE,
  LJOIN,
  TRANSACTION
} = POOL;

์ง€์›ํ•˜๋Š” ํ—ฌํผ ํ•จ์ˆ˜

EQ

const users = await QUERY `SELECT * FROM users WHERE ${EQ({
  email: 'dev@marpple.com',
  password: '1234'
})}`;
// [{ id: 15, email: 'dev@marpple.com', ... }]

IN

const users = await QUERY `SELECT * FROM users WHERE ${IN('id', [15, 19, 20, 40])}`;
// [{ id: 15, ...}, { id: 19, ...} ...]

NOT_IN

const users = await QUERY `SELECT * FROM users WHERE ${NOT_IN('id', [2, 4])} LIMIT 3 ORDER BY ID`;
// [{ id: 1, ...}, { id: 3, ...}, { id: 5, ...}]

VALUES

const post = { user_id: 10, body: 'hoho' };
await QUERY `
  INSERT INTO posts ${VALUES(post)}
`;
// INSERT INTO posts ("user_id", "body") VALUES (10, 'hohoho')

await QUERY `
  INSERT INTO coords ${VALUES([
    {x: 20},
    {y: 30},
    {x: 10, y: 20}
  ])}`;
// INSERT INTO coords ("x", "y") VALUES (20, DEFAULT), (DEFAULT, 30), (10, 20)

SET

await QUERY `
  UPDATE posts ${SET({ body: 'yo!', updated_at: new Date() })} WHERE id = ${post.id}
`;
// UPDATE posts SET "body" = 'yo!', "updated_at" = '2018-08-28T23:18:13.263Z' WHERE id = 10

COLUMN, CL

COLUMN == CL; // true

await QUERY `
  SELECT
    COLUMN('id', 'bb as cc', 't2.name', 't2.name as name2', { a: 'c' }, { 't3.a': 'd' })
      ...
`;
// SELECT
//   "id", "bb" AS "cc", "t2"."name", "t2"."name" AS "name2", "a" AS "c", "t3"."a" AS "d"
//     ...

TABLE, TB

TABLE == TB; // true

await QUERY `
  SELECT
    ...
    FROM TABLE('t1'), TABLE('tt as t2')
`;
// SELECT
//   ...
//   FROM "t1", "tt" AS "t2"

Associations

๊ธฐ๋ณธ

ASSOCIATE๋Š” connection pool์„ ์ด์šฉํ•ฉ๋‹ˆ๋‹ค.

/*
* users
*  - id
*  - name
*
* posts
*  - id
*  - user_id
*  - body

* comments
*  - id
*  - user_id
*  - post_id
*  - body
* */

const { ASSOCIATE } = POOL;

const posts = await ASSOCIATE `
  posts
    - user
    < comments
      - user
`;

posts[0].body; // ๋‚ด์šฉ
posts[0]._.user.name // ๊ธ€์“ด์ด ์ด๋ฆ„
posts[0]._.comments[0].body // ์ฝ”๋ฉ˜ํŠธ ๋‚ด์šฉ
posts[0]._.comments[0]._.user.name // ๋Œ“๊ธ€ ์ž‘์„ฑ์ž ์ด๋ฆ„

Polymorphic

/*
* photos
*  - attached_type
*  - attached_id
* */

await ASSOCIATE `
  posts
    - user
      p - photo
    p < photos
    < comments
      p < photos
`;
// SELECT * FROM photos WHERE attached_id IN (${map($ => $.id, posts)}) AND attached_type = 'photos';
// SELECT * FROM photos WHERE attached_id IN (${map($ => $.id, users)}) AND attached_type = 'users';
// SELECT * FROM photos WHERE attached_id IN (${map($ => $.id, comments)}) AND attached_type = 'comments';

Many to many

/*
* books
*  - id
*
* authors
*  - id
*  - name
*
* books_authors
*  - author_id
*  - book_id
* */

const books = await ASSOCIATE `
  books
    x authors
`;

books[0]._.authors[0].name; // ์ด๋ฆ„

const authors = await ASSOCIATE `
  authors
    x books ${{ xtable: 'books_authors' }}
`;

authors[0]._.books[0].name; // ์ฑ… ์ด๋ฆ„

์˜ต์…˜

/*
* ํ…Œ์ด๋ธ”๋ช…๊ณผ ์ปฌ๋Ÿผ๋ช…์ด ์ด๋ฏธ MQL ํฌ๋งท๊ณผ ๋™์ผํ•˜๊ฑฐ๋‚˜ ViEW ๋“ฑ์„ ์ด์šฉํ•ด ์ž˜ ๋งž์ถฐ๋†จ์„ ๋•Œ์—๋Š”
* ASSOCIATE์—๊ฒŒ ๋„˜๊ธด ๋ฌธ์ž์—ด๋“ค์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ž๋™์œผ๋กœ ํ…Œ์ด๋ธ”๋ช…๊ณผ ์ปฌ๋Ÿผ๋ช…๋“ค์„ ์ ์ ˆํžˆ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
* users
*  - id
* posts
*  - id
*  - user_id
* comments
*  - id
*  - post_id
*  - user_id
* likes
*  - attached_type
*  - attached_id
*  - user_id
* posts_tags
*  - post_id
*  - tag_id
* tags
*  - id
* */

ASSOCIATE `
  posts
    - user
    < comments
     - user
     p < likes
      - user
    p < likes
      - user
    x tags
`;

/*
* ์œ„ ์ƒํ™ฉ์—์„œ ์ปฌ๋Ÿผ๋“ค์„ ์ตœ์†Œํ™”ํ•ด์„œ ๊ฐ€์ ธ์˜ค๊ณ  ์‹ถ๊ฑฐ๋‚˜ ์ฟผ๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
* column์— ๊ธฐ๋ณธํ‚ค๋‚˜ ์™ธ๋ž˜ํ‚ค ๋“ฑ์„ ํฌํ•จ์‹œํ‚ค์ง€ ์•Š์•„๋„ ์ ์ ˆํžˆ ASSOCIATE ๋‚ด๋ถ€์—์„œ ์ถ”๊ฐ€ํ•˜์—ฌ ์ ์ ˆํžˆ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
* */

ASSOCIATE `
  posts ${SQL `WHERE is_hidden = false ORDER BY id DESC LIMIT ${10}`}
    - user
    < comments ${{
      column: COLUMN('body', 'updated_at')
    }}
     - user
     p < likes
      - user
    p < likes
      - user
    x tags
`;


/*
* ๋งŒ์ผ ํ…Œ์ด๋ธ”์ด ์•„๋ž˜์™€ ๊ฐ™๋‹ค๋ฉด ์˜ต์…˜์„ ํ†ตํ•ด ๋งค์นญ์„ ์‹œ์ผœ์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.
* members
*  - member_id
* articles
*  - id
*  - writer_id
* comments
*  - id
*  - article_id
*  - writer_id
* likes
*  - parent_name
*  - parent_id
*  - member_id
* tags_articles
*  - article_id
*  - tag_name
* tags
*  - name
* */

const posts = await ASSOCIATE `
  posts ${{
    table: 'articles' // ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ…Œ์ด๋ธ” ๋ช…์ด ๋‹ค๋ฅผ ๋•Œ
  }}
    - user ${{ // - ๋ฅผ ํ–ˆ์œผ๋ฏ€๋กœ ํ•˜๋‚˜๋ฅผ ๊ฐ์ฒด๋กœ ๊ฐ€์ ธ์˜ด
      left_key: 'writer_id', // articles๊ฐ€ ๊ฐ€์ง„ members.member_id๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ์ปฌ๋Ÿผ
      key: 'member_id', // members ํ…Œ์ด๋ธ”์ด ๊ฐ€์ง„ ํ‚ค
      table: 'members' // user์˜ ํ…Œ์ด๋ธ” ๋ช…
    }}
    < comments ${{ // < ๋ฅผ ํ–ˆ์œผ๋ฏ€๋กœ ๋ฐฐ์—ด๋กœ ์—ฌ๋Ÿฌ๊ฐœ๋ฅผ ๊ฐ€์ ธ์˜ด
      key: 'article_id' // articles์˜ id๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” comments๊ฐ€ ๊ฐ€์ง„ ์ปฌ๋Ÿผ
    }}
      - user ${{
        left_key: 'writer_id', // articles๊ฐ€ ๊ฐ€์ง„ members.member_id๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ์ปฌ๋Ÿผ
        key: 'member_id', // members ํ…Œ์ด๋ธ”์ด ๊ฐ€์ง„ ํ‚ค
        table: 'members' // user์˜ ํ…Œ์ด๋ธ” ๋ช…
      }}
      p < likes ${{ // p < ๋ฅผ ์ด์šฉํ•ด ํ•˜๋‚˜์˜ likes ํ…Œ์ด๋ธ”์„ ํ†ตํ•ด comments์™€ posts์˜ likes๋ฅผ ๊ตฌํ˜„
        poly_type: { parent_name: 'comments' },
        key: 'parent_id'
      }}
    p < likes ${{ // p < ๋ฅผ ์ด์šฉํ•ด ํ•˜๋‚˜์˜ likes ํ…Œ์ด๋ธ”์„ ํ†ตํ•ด comments์™€ posts์˜ likes๋ฅผ ๊ตฌํ˜„
      poly_type: { parent_name: 'articles' },
      key: 'parent_id'
    }}
    x tags ${{ // x ๋ฅผ ํ†ตํ•ด ์ค‘๊ฐ„ ํ…Œ์ด๋ธ”์„ join ํ•˜์—ฌ ๋‹ค๋Œ€๋‹ค ๊ด€๊ณ„ ๊ตฌํ˜„
      left_key: 'id', // articles.id (articles.id = tags_articles.article_id)
      left_xkey: 'article_id', // left_key์™€ ๋งค์นญ๋˜๋Š” tags_articles์˜ ํ‚ค article_id
      xtable: 'tags_articles', // ์ค‘๊ฐ„ ํ…Œ์ด๋ธ” ์ด๋ฆ„
      xkey: 'tag_name', // key์™€ ๋งค์นญ๋˜๋Š” tags_articles์˜ ํ‚ค tag_name
      key: 'name' // tags๊ฐ€ ๊ฐ€์ง„ ํ‚ค (tags_articles.tag_name = tags.name)
    }}
`;

์œ„์™€ ๊ฐ™์ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ํ…Œ์ด๋ธ”๋ช…๊ณผ ์‚ฌ์šฉํ•˜๊ณ ์žํ•˜๋Š” ์ด๋ฆ„์ด ๋‹ค๋ฅด๊ฑฐ๋‚˜, ASSOCIATE๊ฐ€ ์ž๋™์ƒ์„ฑํ•˜๋Š” ์ปฌ๋Ÿผ๋ช… ๋“ฑ๊ณผ ์‹ค์ œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ์ƒํƒœ๊ฐ€ ๋‹ค๋ฅผ ๊ฒฝ์šฐ ์˜ต์…˜์„ ์ด์šฉํ•˜์—ฌ ๋งž์ถฐ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ VIEW๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ฝ”๋“œ ๊ด€๋ฆฌ์— ์ข‹์Šต๋‹ˆ๋‹ค.

Hook

hook์„ ์ด์šฉํ•˜์—ฌ ๊ฐ€์ƒ ์ปฌ๋Ÿผ์ด๋‚˜, ์ •๋ ฌ, ํ•„ํ„ฐ ๋“ฑ์˜ ์ถ”๊ฐ€ ์ž‘์—…์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ž์‹ ์˜ ์•ˆ์ชฝ ๋ฐ์ดํ„ฐ๋“ค์ด ๋ชจ๋‘ ๋ถˆ๋ ค์ง„ ํ›„ ์‹คํ–‰๋˜์–ด ํ™œ์šฉํ•˜๊ธฐ ์ข‹์Šต๋‹ˆ๋‹ค.

const users = await ASSOCIATE `
  users ${{hook: users => users.map(u =>
    Object.assign({}, u, { _popular: !!u._.posts.find(p => p._is_best) })
  )}}
    < posts ${{hook: posts => posts.map(
      p => Object.assign({}, p, { _is_best: p._.comments.length > 1 }))}}
      - user
      < comments
       - user
`;

users[0]._popular; // true
users[0]._.posts[0]._is_best; // true
users[0]._.posts[1]._is_best; // false

Transaction

const { PostgreSQL } = require('mql2');
const { CONNECT } = PostgreSQL;
const POOL = await CONNECT({
  host: 'localhost',
  user: 'username',
  password: '1234',
  database: 'dbname',
  charset: 'utf8'
});
const { TRANSACTION } = POOL;
const { QUERY, COMMIT, ROLLBACK } = await TRANSACTION();

await QUERY `
  INSERT INTO posts ${VALUES(post)}
`;
await QUERY `
  UPDATE posts ${SET({ body: 'yo!', updated_at: new Date() })} WHERE id = ${post.id}
`;
await ROLLBACK();

TRANSACTION์„ ํ†ตํ•ด ์–ป์€ QUERY๋Š” ํ•˜๋‚˜์˜ connection์„ ์ด์šฉํ•ฉ๋‹ˆ๋‹ค. ROLLBACK์ด๋‚˜ COMMIT์„ ํ•˜๊ณ ๋‚˜๋ฉด ์•ž์„œ ํ•จ๊ป˜ ์–ป์—ˆ๋˜ QUERY ํ•จ์ˆ˜์˜ ์ปค๋„ฅ์…˜์€ ํ•ด์ œ๋˜๊ณ  ๋”์ด์ƒ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

DEBUG

MQL_DEBUG.LOG๋ฅผ true๋กœ ์„ค์ •ํ•œ ํ›„ QUERY๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ์ฝ˜์†”์— DB๋กœ ๋ณด๋‚ธ ์ฟผ๋ฆฌ๋“ค์„ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค.

MQL_DEBUG.LOG = true;
QUERY `SELECT ${"hi~"} as ho`;

// { text: 'SELECT $1 as ho', values: ['hi'] }

FAQs

Last updated on 03 Sep 2018

Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with โšก๏ธ by Socket Inc