Dart и MySQL

Dart — язык программирования, созданный Google.
Dart позиционируется в качестве замены/альтернативы JavaScript, страдающего от «фундаментальных» изъянов, которые невозможно исправить путём эволюционного развития. (Википедия)

Dart

Замена так замена. Вот только Dart «умеет» и на server-side работать. Получается, что один язык может использоваться как на front-end, так и на back-end.

Для более близкого знакомства с языком я выбрал простую задачку по выборке данных из БД (MySQL), а так же последующую обработку полученных данных.

Из коробки Dart с MySQL работать не умеет (как и со многими другими DB). Однако, если несколько отличных решений от «third-party» разработчиков (ссылка). sqljocky — это как раз то, что надо. Стоит отдельно сказать про Pub’ы в Dart. Это отдельные пакеты, которые НЕ надо устанавливать себе пачками только для того, что бы «посмотреть, а что оно вообще такое». В Dart Editor (а с Dart только в нем пока можно нормально работать) в разделе Tools есть пункт «Pub Get», по нажатии на который редактор подтянет все пакеты, которые указаны как зависимости для Вашего проекта. Такие зависимости указываются в файле pubspec.yaml. Пример такого файла:

name: myFirstApplication
description: A sample command-line application
dependencies:
  sqljocky: any
  // тут может быть еще много пунктов

После имени пакета через двоеточие указывается его необходимая версия (вот более удачный пример файла pubspec.yaml).

Если Dart Editor почему-то не хочет запускаться, то есть несколько вещей которые надо сделать, а потом уже гуглить:
1. Оставить только ASCII-символы в пути установки редактора.
2. Обновить JDK.

Подключение пакетов осуществляется таким образом:

import 'package:sqljocky/sqljocky.dart';
import 'package:sqljocky/utils.dart';
import 'package:options_file/options_file.dart';
import 'dart:async';

Сторонние пакеты поключаются с помощью слова «package», а «коробочные» — словом «dart».

Выполнение программы на Dart начинается с вызова функции main. С учетом условия задачи, помимо main будет еще одна функция, которая вытянет данные из БД (назовем ее getStats). В main же будет обработка полученных данных:

void main() {
  getStats().then((stats) {
     // Тут будет код
  });
}

Что за then?! В Dart есть такая штука как Future. Оф. документация говорит, что Future используется для получения еще не доступного значения, или ошибки, когда-нибудь в будущем. Метод then вызывает переданный ему callback, когда Future возвращает значение. Зачем вообще Future? Небольшой мануал есть в документации. Кратко: если надо что-то выполнить асинхронно (продолжив выполнение программы сразу после вызова), а ответ обработать тогда, когда он будет получен, то Future самое то. Чем-то напоминает $.deferred.

Функция getStats как раз и возращает Future. Надо бы посмотреть на ее код:

Future<List> getStats() {
  var pool = new ConnectionPool(host: 'localhost', port: 3306, user: 'root', password: 'KronuS', db: 'dota2statistic_2014_01_09', max: 5);
  var ret = new Completer<List>();
  var overall_heroes = 10, overall_combos = (overall_heroes - 1) / 2 * overall_heroes;
  var data = [];
  for (var h1 = 1; h1 <= overall_heroes; h1++) {
    for (var h2 = h1 + 1; h2 <= overall_heroes; h2++) {
      pool.query('''
         ТУТ БОЛЬШОЙ МНОГОСТРОЧНЫЙ ЗАПРОС
        ''').then((result) {
        var wins = 0, loses = 0;
        result.forEach((match) {
          if (match.radiant_win == match.team) {
            wins++;
          }
          else {
            loses++;
          }
        }).then((dynamic) {
          data.add([h1, h2, wins, loses]);
          if (data.length >= overall_combos) {
            ret.complete(data);
          }
        });
      });
    };
  };
  return ret.future;
}

Для начала устанавливаем соединение с БД используя ConnectionPool (из пакета sqljocky). С параметрами все понятно (max — количество одновременных соединений). Далее идет объявление Completer’a. Если кратко, это cпособ получения Future-объектов (которые потом можно завершить, получив значение, или обработь ошибку). В заголовке нашей функции указано, что она вернет Future<List>. В треугольных скобках указывается «реальный» тип данных. То есть, на выходе (в then) будет объект List с какими-то данными. Если посмотреть в конец функции, то видно, что возвращается «ret.future» (экземпляр Future).

overall_heroes и overall_combos — это вспомогательные данные, которые нужны для вычислений. overall_combos по своей сути является размером списка, который вернет функция, а так же «флагом», когда надо сделать Completer.complete. data — это тот самый List, который вернет функция, когда будут выполненые все запросы к БД. Эти запросы выполняются в двух вложенных циклах и следущая итерация цикла не ждет, пока выполнится запрос из предыдущей. Это происходит потому что метод query возращает Future. Таким образом получается, что когда выполнялся все запросы доподлинно не известно. Но известно, что каждый запрос записывает данные в ret. Соопоставляя его размер и overall_combos, можно понять, когда все запросы завершились и нужно выполнить ret.complete (передав в него data).

Посмотрим, что в Dart’e есть для работы с List. Есть реально много 🙂 Радует, что «из коробки» доступны сортировка и фильтрация.

getStats возращает List[ [int, int, int, int], [int, int, int, int],… ]. Если мне надо отсортировать его по убыванию суммы последних двух элементов каждой строчки, то код будет такой:

stats.sort((x, y) => (y[2] + y[3]).compareTo(x[2] + x[3]));

Если же надо по возрастанию, то:

stats.sort((x, y) => (x[2] + x[3]).compareTo(y[2] + y[3]));

Довольно просто. Разве что стоит обратить внимание на запись аргумента метода sort. Это функция в «короткой» форме. Короткая форма записывается в одну строчку без ключевых слов. Ее «объявление» и тело разделены через «=>». Она всегда возвращает результат того выражения, которое находится в ее теле. В коде выше вернется результат метода compareTo.

Вторая задача — отложить в отдельный список строки, где сумма последних двух элементов равна 0:

var notUsedCombos = stats.where((f) => f[2] + f[3] == 0).toList();

where принимает параметром функцию с аргументом, который является элементом списка stats. Опять-таки используем короткую форму записи. Да, where возращает не список, а Iterable, который преобразуется в список с помощью метода toList.

Первое знакомство с Dart’ом можно считать законченным. Язык весьма интересный и с кучей разных особенностей (от синтаксиса до концептуальных принципов).

, , , ,

Оставить комментарий

Top ↑ | Main page | Back