Как написать клиент базы данных командной строки всего за 10 минут с помощью OCLIF из TypeScript

1656645129 kak napisat klient bazy dannyh komandnoj stroki vsego za 10

Майкл Хангер

1*34f_Ia_d5E6WZPBQdKjhBw

На этой неделе я наткнулся на «OCLIF, Open Source Command Line Framework» от SalesForce/Heroku в среднем сообщении Джеффа Дики.

Я был заинтригован, это выглядело очень легко и понятно (благодаря TypeScript), и я знал из прошлого опыта, что CLI содержит много дел и шаблонов. Документация и примеры тоже выглядели очень хорошо.

Я провел много времени в обеих оболочках neo4j и cypher-shell, как на Java, поэтому я хотел попробовать JavaScript (JS).

Используя драйвер neo4j-javascript для визуализации графиков, я знал, что это довольно просто и быстро.

Драйвер посылает запросы Cypher через бинарный протокол Bolt в базу данных, а также обрабатывает разумную маршрутизацию, транзакции и повторные попытки.

Для хорошего выхода я выбрал ascii-table аккуратная библиотека JS для создания хороших таблиц для терминала.

По сути, вы должны предоставить a bolt-url, имя пользователя, и пароль и а запрос бежать, так что я представляю нашего клиента таким.

boltsh -a bolt://host:port -u neo4j -p pa55w0rd \  "MATCH (n:Person) RETURN n.name, n.age LIMIT 10"

Видео

Я записал сеанс выполнения этой кодировки. Это сводится к 15-минутному времени работы, в основном благодаря набору текста. Не стесняйтесь смотреть это в 2 раза 🙂

Запуск экземпляра Neo4j

Чтобы запустить Neo4j с некоторыми данными, у вас есть два варианта. Вы можете установить Neo4j Desktop, являющееся электронным приложением для управления базами данных, и создать проект с локальной пустой базой данных. Или вы можете запустить Neo4j Sandbox и выбрать Blank Sandbox.

Обратите внимание на IP-адрес сервера и болт порт, а также имя пользователя и пароль с вкладки «Детали».

В обоих случаях после запуска Neo4j Browser, который является просто хорошим интерфейсом на основе React (и также использует neo4j-javascript-driver), введите и запустите в верхней командной строке.

:play movie graph

Это дает вам слайд-шоу, где на второй странице вы видите огромное заявление о создании образцов данных. Нажмите и запустите это, и вы увидите визуализацию Тома Хэнкса с кучей его фильмов и некоторыми режиссерами.

0*YsONV_kfRt-vuECP
0*be_udZXNJUtwdVYZ

Начало работы с OCLIF

Это очень просто – просто решите, хотите ли вы клиента с несколькими или одной командой, и запустите соответствующий npx (npm package runner) команда.

npx oclif single boltsh

Это задает вам несколько вопросов об имени, лицензии и github-repo, а также генерирует скелет, в нашем случае для однокомандного CLI.

Чтобы проверить, работает ли все, вы можете запустить ./bin/run и должен увидеть такой результат:

./bin/run
hello world from /Users/mh/d/js/boltsh/src/index.ts!

Итак, мы можем найти код редактирования в этом файле, который является классом Command. Открывая его в редакторе, мы видим, куда добавить описание, пример использования и флажки, упомянутые выше.

Мы устанавливаем все флажки на обязательные и придаем значение по умолчанию для address и user. Затем мы также добавляем query аргумент, который также обязателен.

import { Command, flags } from '@oclif/command'
class Boltsh extends Command {  static description = 'Execute Cypher Queries via Bolt'
  static examples = [    `$ boltsh -a bolt://localhost -u neo4j -p test \                 "MATCH (n:Person) return n.name"n.nameKeanu ReevesTom Hanks...`,  ]
  static flags = {    version: flags.version({ char: 'v' }),    help: flags.help({ char: 'h' }),
    address: flags.string({ char: 'a', description: 'bolt address',                       required: true, default: 'bolt://localhost' }),    user: flags.string({ char: 'u', description: 'neo4j user',                      required: true, default: 'neo4j' }),    password: flags.string({ char: 'p', required: true,                      description: 'user password' }),  }
  static args = [{ name: 'query', required: true,                    description: 'Cypher Query to Run' }]
  async run() {    const { args, flags } = this.parse(Boltsh)
    this.log(`boltsh: ${flags.address} ${flags.user}               ${args.query} from ${__filename}!`)  }}
export = Boltsh

Мы выводим входные данные командной строки и запускаем. Как приятный побочный эффект, run Команда также запускает компилятор TypeScript, так что нам не нужно делать это вручную.

./bin/run -p test "MATCH (n:Person) RETURN n.name"
boltsh: bolt://localhost neo4j MATCH (n:Person) RETURN n.name from /Users/mh/d/js/boltsh/src/index.ts!

Классно, теперь мы можем добавить драйвер neo4j и отправить запрос на сервер:

yarn add neo4j-driver

Добавьте импорт сверху:

import * as neo4j from 'neo4j-driver'

Здесь вы найдете детали драйвера API Neo4j.

  1. Мы создадим драйвер с нашим адресом, пользователем и паролем и получим сеанс, используемый для выполнения запроса.
  2. Получите результаты и выведите ключи записей первой строки в качестве заголовков и значения всех записей в качестве строк, разделенных табуляцией.
  3. Внизу мы также выводим общее количество строк и время, взятое из результата-сводки.

(Обратите внимание, что драйвер Neo4j использует свой тип Number для Numbers, поскольку Javascript не может выражать 64-разрядные числа.)

async run() {  const { args, flags } = this.parse(Boltsh)
  const driver = neo4j.v1.driver(flags.address,                    neo4j.v1.auth.basic(flags.user, flags.password))  const session = driver.session()  const result = await session.run(args.query)  session.close()  driver.close()  const records = result.records;  if (records.length > 0) {    // header    this.log(records[0].keys.join("\t"))    // rows    records.forEach(r => this.log(                    r.keys.map(k => r.get(k)).join("\t")))
    this.log(`Returned ${records.length} row(s) in              ${result.summary.resultAvailableAfter.toNumber() +                result.summary.resultConsumedAfter.toNumber()} ms.`)  } else {    this.log('No Results.')  }}

Если мы запустим тест еще раз, он просто сработает. Круто!

./bin/run -p test "MATCH (n:Person) RETURN n.name limit 2"
n.nameKeanu ReevesCarrie-Anne MossReturned 2 row(s) in 3 ms.

Теперь мы можем сделать это хорошим с помощью ascii-table

yarn add ascii-table

Поскольку ASCII-таблица не поставляется с определением TypeScript, компилятор выдает ошибку – поэтому мы должны объявить модуль в отдельном файле `src/ambient.d.ts`:

declare module 'ascii-table';

Снова добавьте импорт. На этот раз мы добавляем ненужный флаг -t переключающий режим стола.

import * as AsciiTable from 'ascii-table'

Затем мы строим и выводим AsciiTable вместо обычного текста, если этот флажок установлен.

static flags = {  // ...  table: flags.boolean({ char: 't', description: 'Table Format' })}
async run() {  const { args, flags } = this.parse(Boltsh)
  const driver = neo4j.v1.driver(flags.address,                   neo4j.v1.auth.basic(flags.user, flags.password))  const session = driver.session()  const result = await session.run(args.query)  session.close()  driver.close()  const records = result.records;
  if (records.length > 0) {    // extract data to be rendered    const data = { heading: records[0].keys,           rows: records.map(r => r.keys.map(k => r.get(k))) }
    if (flags.table) {      const table = AsciiTable.factory(data)      this.log(table.toString())    } else {      this.log(data.heading.join("\t"))      data.rows.forEach(r => this.log(r.join("\t")))    }
    this.log(`Returned ${records.length} row(s) in              ${result.summary.resultAvailableAfter.toNumber() +                  result.summary.resultConsumedAfter.toNumber()} ms.`)  } else {    this.log('No Results.')  }}

Итак, давайте попробуем это и посмотрим, как выглядит наша таблица:

./bin/run -p test -t "MATCH (n:Person) RETURN n.name limit 10"
.--------------------.|       n.name       ||--------------------|| Keanu Reeves       || Carrie-Anne Moss   || Laurence Fishburne || Hugo Weaving       || Lilly Wachowski    || Lana Wachowski     || Joel Silver        || Emil Eifrem        || Charlize Theron    || Al Pacino          |'--------------------'Returned 10 row(s) in 25 ms.

Кроме того, более сложный запрос выглядит хорошо (за исключением того, что он слишком широк для Medium, поэтому снимок экрана). Это отображает имена людей, год рождения и три фильма, с которыми они связаны.

1*sR0hkTOmoblU7jRx1Tedvg

Что приятно в OCLIF, так это то, что он поставляется с аккумуляторами. К примеру, мы можем бегать boltsh --help чтобы получить соответствующую страницу справки:

./bin/run --helpExecute Cypher Queries via Bolt
USAGE  $ boltsh QUERY
ARGUMENTS  QUERY  Cypher Query to Run
OPTIONS  -a, --address=address    (required) [default: bolt://localhost] bolt address  -h, --help               show CLI help  -p, --password=password  (required) user password  -u, --user=user          (required) [default: neo4j] neo4j user  -v, --version            show CLI version
EXAMPLE  $ boltsh -a bolt://localhost -u neo4j -p test \           "MATCH (n:Person) return n.name"  n.name  Keanu Reeves  Tom Hanks  ...

В статье, упомянутой в начале, Джефф показывает, как создать многокомандный CLI. Код в основном такой же, как и наш, с той лишь разницей, что у вас есть несколько команд.

Просмотрите документацию и примеры OCLIF.

Фреймворк имеет инфраструктуру плагинов, и уже есть несколько плагинов, таких как самообновление. Я надеюсь, мы увидим больше.

Я считаю, что OCLIF действительно прекрасно сделали люди из Heroku благодаря Джеффу Дики.

Классно, миссия выполнена, теперь остается только отправить на GitHub и опубликовать на npm.

1*i-Jkaoqfh-INzSkxOUrU7A

Так почему бы вам не попробовать и не создать свой CLI?

Счастливого взлома!

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *