Удобства выборки данных
Далее, под словом «возвращает» буду разуметь второй параметр callback, а не результат вызова функции.
Выборка одной записи: connection.queryRow(sql, values, callback) возвращает хеш (ассоциативный массив), в котором имена полей становятся ключами (вместо того, чтобы получать массив в массиве через query).
connection.queryRow('SELECT * FROM Language where LanguageId=?', [3], function(err, row) { console.dir({queryRow:row}); /* Example: queryRow: { LanguageId: 3, LanguageName: 'Russian', LanguageSign: 'ru', LanguageISO: 'ru', Caption: 'Русский' } */ });
Выборка скаляра (то есть единичного значения): connection.queryValue(sql, values, callback) возвращает одно значение (вместо того, чтобы получать массив в массиве с одним значением). Удобно при выборке одного пол из одной записи, например Id по имени с указанием LIMIT 1 или функций count(*), max(field) и т.д.
connection.queryValue('SELECT LanguageName FROM Language where LanguageId=?', [8], function(err, name) { console.dir({queryValue:name}); /* Example: queryValue: 'Italiano' */ });
Выборка одной колонки: connection.queryArray(sql, values, callback) возвращает массив, заполненный значениями одного поля для каждой записи, из результата выполнения запроса. То есть, это выборка вертикальной колонки, в отличие от выборки горизонтальной записи queryRow.
connection.queryArray('SELECT LanguageSign FROM Language', [], function(err, result) { console.dir({queryHash:result}); /* Example: queryArray: [ 'de', 'en', 'es', 'fr', 'it', 'pl', 'ru', 'ua' ] */ });
Выборка хеша : connection.queryHash(sql, values, callback) возвращает хеш (ассоциативный массив) двухуровневой вложенности, где ключи первого уровня — значения первого поля из результата выполнения запроса, а ключи второго уровня — все поля результата запроса (включая и первое).
connection.queryHash( 'SELECT LanguageSign, LanguageId, LanguageName, Caption, LanguageISO FROM Language', [], function(err, result) { console.dir({queryHash:result}); /* Example: queryHash: { en: { LanguageSign: 'en', LanguageId: 2, LanguageName: 'English', Caption: 'Английский', LanguageISO: 'en' }, ru: { LanguageSign: 'ru', LanguageId: 3, LanguageName: 'Russian', Caption: 'Русский', LanguageISO: 'ru' }, de: { LanguageSign: 'de', LanguageId: 7, LanguageName: 'Deutsch', Caption: 'Немецкий', LanguageISO: 'de' }, it: { LanguageSign: 'it', LanguageId: 8, LanguageName: 'Italiano', Caption: 'Итальянский', LanguageISO: 'it' } } */ });
Выборка пар ключ/значение: connection.queryKeyValue(sql, values, callback) возвращает хеш (ассоциативный массив), где ключом будет первое поле из результата запроса запросе.
connection.queryKeyValue( 'SELECT LanguageISO, LanguageName FROM Language', [], function(err, keyValue) { console.dir({queryKeyValue:keyValue}); /* Example: keyValue: { en: 'English', ru: 'Russian', uk: 'Ukrainian', es: 'Espanol', fr: 'Francais', de: 'Deutsch', it: 'Italiano', pl: 'Poliski' } */ });
Удобства интроспекции
То есть, удобства получения метаданных, структур и параметров базы для их анализа и автоматического построения логики или интерфейсов по работы с этой базой.
Получение первичного ключа: connection.primary(table, callback) возвращает хеш (ассоциативный массив), с метаданными о первичном ключе, см. набор метаданных в примере.
connection.primary('Language', function(err, primary) { console.dir({primary:primary}); /* Example: primary: { Table: 'language', Non_unique: 0, Key_name: 'PRIMARY', Seq_in_index: 1, Column_name: 'LanguageId', Collation: 'A', Cardinality: 9, Sub_part: null, Packed: null, Null: '', Index_type: 'BTREE', Comment: '', Index_comment: '' } */ });
Получение внешних ключей: connection.foreign(table, callback) возвращает хеш (ассоциативный массив), с двойной вложенностью, на первом уровне имена внешних ключей, а на втором — метаданные, описывающие этот ключ. Набор полей см. в примере.
connection.foreign('TemplateCaption', function(err, foreign) { console.dir({foreign:foreign}); /* Example: foreign: { fkTemplateCaptionLanguage: { CONSTRAINT_NAME: 'fkTemplateCaptionLanguage', COLUMN_NAME: 'LanguageId', ORDINAL_POSITION: 1, POSITION_IN_UNIQUE_CONSTRAINT: 1, REFERENCED_TABLE_NAME: 'language', REFERENCED_COLUMN_NAME: 'LanguageId' }, fkTemplateCaptionTemplate: { CONSTRAINT_NAME: 'fkTemplateCaptionTemplate', COLUMN_NAME: 'TemplateId', ORDINAL_POSITION: 1, POSITION_IN_UNIQUE_CONSTRAINT: 1, REFERENCED_TABLE_NAME: 'template', REFERENCED_COLUMN_NAME: 'TemplateId' } */ });
Получение ограничений целостности: connection.constraints(table, callback) возвращает хеш (ассоциативный массив), с двойной вложенностью, на первом уровне имена ограничений целостности, а на втором — метаданные, описывающие каждое ограничение. Набор полей см. в примере.
connection.constraints('TemplateCaption', function(err, constraints) { console.dir({constraints:constraints}); /* Example: constraints: { fkTemplateCaptionLanguage: { CONSTRAINT_NAME: 'fkTemplateCaptionLanguage', UNIQUE_CONSTRAINT_NAME: 'PRIMARY', REFERENCED_TABLE_NAME: 'Language', MATCH_OPTION: 'NONE', UPDATE_RULE: 'RESTRICT', DELETE_RULE: 'CASCADE' }, fkTemplateCaptionTemplate: { CONSTRAINT_NAME: 'fkTemplateCaptionTemplate', UNIQUE_CONSTRAINT_NAME: 'PRIMARY', REFERENCED_TABLE_NAME: 'Template', MATCH_OPTION: 'NONE', UPDATE_RULE: 'RESTRICT', DELETE_RULE: 'CASCADE' } } */ });
Получение метаданных о полях таблицы: connection.fields(table, callback) возвращает массив с метаданными для каждого поля, в том чисте имя, тип, все модификаторы и флаги, комментарии (подробнее см. пример).
connection.fields('Language', function(err, fields) { console.dir({fields:fields}); /* Example: fields: { LanguageId: { Field: 'LanguageId', Type: 'int(10) unsigned', Collation: null, Null: 'NO', Key: 'PRI', Default: null, Extra: 'auto_increment', Privileges: 'select,insert,update,references', Comment: 'Id(EN),Код(RU)' }, LanguageName: { Field: 'LanguageName', Type: 'varchar(32)', Collation: 'utf8_general_ci', Null: 'NO', Key: 'UNI', Default: null, Extra: '', Privileges: 'select,insert,update,references', Comment: 'Name(EN),Имя(RU)' }, ... } */ });
Получение списка баз данных доступных по данному соединению: connection.databases(callback) возвращает массив имен баз (или «схем», как их иногда называют).
connection.databases(function(err, databases) { console.dir({databases:databases}); /* Example: databases: [ 'information_schema', 'mezha', 'mysql', 'performance_schema', 'test' ] */ });
Получение списка таблиц для текущего соединения: connection.tables(callback) возвращает хеш (ассоциативный массив) двойной вложенности, где на первом уровне ключи — имена таблиц, а на втором — метаданные для каждой таблицы.
connection.tables(function(err, tables) { console.dir({tables:tables}); /* Example: tables: { Language: { TABLE_NAME: 'Language', TABLE_TYPE: 'BASE TABLE', ENGINE: 'InnoDB', VERSION: 10, ROW_FORMAT: 'Compact', TABLE_ROWS: 9, AVG_ROW_LENGTH: 1820, DATA_LENGTH: 16384, MAX_DATA_LENGTH: 0, INDEX_LENGTH: 49152, DATA_FREE: 8388608, AUTO_INCREMENT: 10, CREATE_TIME: Mon Jul 15 2013 03:06:08 GMT+0300 (Финляндия (лето)), UPDATE_TIME: null, CHECK_TIME: null, TABLE_COLLATION: 'utf8_general_ci', CHECKSUM: null, CREATE_OPTIONS: '', TABLE_COMMENT: '_Language:Languages(EN),Языки(RU)' }, ... } */ });
Получение метаданных указанной таблицы: connection.tableInfo(table, callback) возвращает хеш (ассоциативный массив) с метаданными (подробнее см. в примере).
connection.tableInfo('Language', function(err, info) { console.dir({tableInfo:info}); /* Example: tableInfo: { Name: 'language', Engine: 'InnoDB', Version: 10, Row_format: 'Compact', Rows: 9, Avg_row_length: 1820, Data_length: 16384, Max_data_length: 0, Index_length: 49152, Data_free: 9437184, Auto_increment: 10, Create_time: Mon Jul 15 2013 03:06:08 GMT+0300 (Финляндия (лето)), Update_time: null, Check_time: null, Collation: 'utf8_general_ci', Checksum: null, Create_options: '', Comment: '' } */ });
Получение метаданных о всех ключах данной таблицы: connection.indexes(table, callback) возвращает хеш (ассоциативный массив)? ключами первого уровня в нем являются имена ключей базы данных (), а ключами второго уровня — метаданные о каждом ключе (см. пример для подробного списка метаданных).
connection.indexes('Language', function(err, info) { console.dir({tableInfo:info}); /* Example: indexes: { PRIMARY: { Table: 'language', Non_unique: 0, Key_name: 'PRIMARY', Seq_in_index: 1, Column_name: 'LanguageId', Collation: 'A', Cardinality: 9, Sub_part: null, Packed: null, Null: '', Index_type: 'BTREE', Comment: '', Index_comment: '' }, akLanguage: { Table: 'language', Non_unique: 0, Key_name: 'akLanguage', Seq_in_index: 1, Column_name: 'LanguageName', Collation: 'A', Cardinality: 9, Sub_part: null, Packed: null, Null: '', Index_type: 'BTREE', Comment: '', Index_comment: '' } } */ });
Получение процессов на сервере MySQL: connection.processes(callback) возвращает массив хешей, где для каждого процесса даны его параметры.
connection.processes(function(err, processes) { console.dir({processes:processes}); /* Example: processes: [ { ID: 62, USER: 'mezha', HOST: 'localhost:14188', DB: 'mezha', COMMAND: 'Query', TIME: 0, STATE: 'executing', INFO: 'SELECT * FROM information_schema.PROCESSLIST' }, { ID: 33, USER: 'root', HOST: 'localhost:39589', DB: null, COMMAND: 'Sleep', TIME: 1, STATE: '', INFO: null } ] */ });
Получение глобальных переменных MySQL: connection.globalVariables(callback)
connection.globalVariables(function(err, globalVariables) { console.dir({globalVariables:globalVariables}); /* Example: globalVariables: { MAX_PREPARED_STMT_COUNT: '16382', MAX_JOIN_SIZE: '18446744073709551615', HAVE_CRYPT: 'NO', PERFORMANCE_SCHEMA_EVENTS_WAITS_HISTORY_LONG_SIZE: '10000', INNODB_VERSION: '5.5.32', FLUSH_TIME: '1800', MAX_ERROR_COUNT: '64', ... } */ });
Получение глобального статуса MySQL: connection.globalStatus(callback)
connection.globalStatus(function(err, globalStatus) { console.dir({globalStatus:globalStatus}); /* Example: globalStatus: { ABORTED_CLIENTS: '54', ABORTED_CONNECTS: '2', BINLOG_CACHE_DISK_USE: '0', BINLOG_CACHE_USE: '0', BINLOG_STMT_CACHE_DISK_USE: '0', BINLOG_STMT_CACHE_USE: '0', BYTES_RECEIVED: '654871', BYTES_SENT: '212454927', COM_ADMIN_COMMANDS: '594', ... } */ });
Получение списка пользователей MySQL: connection.users(callback)
connection.users(function(err, users) { console.dir({users:users}); /* Example: users: [ { Host: 'localhost', User: 'root', Password: '*90E462C37378CED12064BB3388827D2BA3A9B689', Select_priv: 'Y', Insert_priv: 'Y', Update_priv: 'Y', Delete_priv: 'Y', Create_priv: 'Y', Drop_priv: 'Y', Reload_priv: 'Y', Shutdown_priv: 'Y', Process_priv: 'Y', File_priv: 'Y', Grant_priv: 'Y', References_priv: 'Y', Index_priv: 'Y', Alter_priv: 'Y', Show_db_priv: 'Y', Super_priv: 'Y', Create_tmp_table_priv: 'Y', Lock_tables_priv: 'Y', Execute_priv: 'Y', Repl_slave_priv: 'Y', Repl_client_priv: 'Y', Create_view_priv: 'Y', Show_view_priv: 'Y', Create_routine_priv: 'Y', Alter_routine_priv: 'Y', Create_user_priv: 'Y', Event_priv: 'Y', Trigger_priv: 'Y', Create_tablespace_priv: 'Y', ssl_type: '', ssl_cipher: <Buffer >, x509_issuer: <Buffer >, x509_subject: <Buffer >, max_questions: 0, max_updates: 0, max_connections: 0, max_user_connections: 0, plugin: '', authentication_string: '' }, ... ] */ });
Удобства генерации запросов
Ну и совсем уже барские удобства, позволяющие генерировать SQL или полностью или отдельные WHERE выражения. Я сам не сторонник такого сахара, но иногда бывает нужно автоматизировать генерацию запросов, которые заранее не известны и я позволяю себе такую роскошь.
Генерация условий: connection.where(conditions) работает синхронно, а не асинхронно, как другие функции, т.е. не использует callback. Возвращает построенное WHERE выражение SQL для conditions, описанных в стиле JSON. Нужно обязательно смотреть пример для понимания:
var where = connection.where({ id: 5, year: ">2010", price: "100..200", level: "<=3", sn: "*str?", label: "str", code: "(1,2,4,10,11)" }); console.dir(where); // Output: "id = 5 AND year > '2010' AND (price BETWEEN '100' AND '200') AND // level <= '3' AND sn LIKE '%str_' AND label = 'str' AND code IN (1,2,4,10,11)"
Выборка с условием: connection.select(table, whereFilter, callback)
connection.select('Language', '*', { LanguageId: "1..3" }, function(err, results) { console.dir({select:results}); });
Вставка записи: connection.insert(table, row, callback)
connection.insert('Language', { LanguageName: 'Tatar', LanguageSign:'TT', LanguageISO:'TT', Caption:'Tatar' }, function(err, recordId) { console.dir({insert:recordId}); });
Изменение записи: connection.update(table, row, callback)
connection.update('Language', { LanguageId: 25, LanguageName:'Tatarca', LanguageSign:'TT', LanguageISO:'TT', Caption:'Tatarca' }, function(err, affectedRows) { console.dir({update:affectedRows}); });
Вставка, если нет такой записи или изменение, если она уже есть: connection.upsert(table, row, callback)
connection.upsert('Language', { LanguageId: 25, LanguageName:'Tatarca', LanguageSign:'TT', LanguageISO:'TT', Caption:'Tatarca' }, function(err, affectedRows) { console.dir({upsert:affectedRows}); });
Получение количества записей в таблице по заданному фильтру или без фильтра: connection.count(table, whereFilter, callback)
connection.count('Language', { LanguageId: ">3" }, function(err, count) { console.dir({count:count}); /* Example: count: 9 */ });
Удаление записи или нескольких записей: connection.delete(table, whereFilter, callback)
connection.delete('Language', { LanguageSign:'TT' }, function(err, affectedRows) { console.dir({delete:affectedRows}); });
Варианты использования
1. На Github есть патч к драйверу node-mysql со всеми, приведенными выше функциями: github.com/felixge/node-mysql
2. Но я думаю, что поддерживать его я не стану, и подумываю про то, чтобы сделать отдельную библиотеку с более высоким уровнем абстракции, чем просто драйвер, но не такого высокого уровня как ORM библиотеки. То есть, я не хочу делать из этого громоздкую вещь, а позволить добавлять к соединению через примеси только нужные из трех групп функций. То есть, после создания соединения можно будет выбирать, нужна ли интроспекция, нужны ли простые функции выборки скаляров, массивов и хешей и нужны ли более сложные функции для генерации SQL выражений.
3. И третий вариант использования, это сервер приложений Impress для Node.js, в которые весь этот арсенал встроен. Две группы функций по выборке в Impress есть сразу у всех подключений к MySQL, они примешиваются автоматически, при открытии соединения, и только интроспекцию можно добавить через конфиг где нужно раскомментировать соответствующий плагин, чтобы набор плагинов для MySQL был такой:
plugins: { require: [ "db", "db.mysql", "db.mysql.introspection", ... ] },...
Тогда плагин автоматически примешается к каждому соединению: if (db.mysql.introspection) db.mysql.introspection(connection);
Тут искодники плагинов к Impress:
- https://github.com/tshemsedinov/impress/blob/master/lib/db.mysql.js
- https://github.com/tshemsedinov/impress/blob/master/lib/db.mysql.introspection.js
А по поводу выпуска этих удобств в качестве отдельной библиотеки, хочу посоветоваться в вами:
ссылка на оригинал статьи http://habrahabr.ru/post/198738/
Добавить комментарий