Lovefield

Материал из Национальной библиотеки им. Н. Э. Баумана
Последнее изменение этой страницы: 08:44, 22 февраля 2019.
Lovefield
Apache Geode
Постоянный выпуск: 2.1.12
Написана на: JavaScript
Операционная система: cross-platform
Лицензия: Apache License 2.0
Веб-сайт google.github.io/lovefield/

Lovefield - это реляционная БД для web-приложений, написанная на языке JavaScript. Она предоставляет SQL-подобный синтаксис и кросс-браузерную работу (на данный момент поддерживаются Chrome 37+, Firefox 31+, IE 10+, IE Edge, и Safari 10+), а так же является быстрой, безопасной, и легкой в использовании.

Особенности

Поскольку начиная с 2010 года сообществу так и не удалось выработать стандарт для WebSQL, в этой области не существовало реляционной БД, которая могла обеспечить полноценную кросс-браузерность.[Источник 1] Имеющиеся решения — IndexedDB и LocalStorage были по сути объектно-ориентированными хранилищами и не имели свойств,которыми обладают реляционные БД. Lovefield создан, чтобы заполнить этот пробел в подобном ПО. Он предоставляет мощный и гибкий движок запросов. В качестве бэкэнда в нем используется IndexedDB. Синтаксис самих SQL-запросов декларативен, т.е. отсутствует прямой парсинг запросов, что делает систему устойчивой к SQL-инъекциям, а также простой в изучении для разработчиков, уже хорошо знакомых с традиционным SQL. На данные момент движок Lovefield реализует такую функциональность:

  • Поддержка запросов select, insert, update и delete;
  • Простая семантика транзакций для обеспечения атомарности операций;
  • Возможность задания ограничений для проверки сохранения целостности (primary key, unique, nullable/not-nullable).
  • Поддержка агрегатных функций(count, min, max, sum, avg, stddev, distinct);
  • Поддержка группировки в SELECT-запросах через выражение «group by»;
  • Возможность формирования запросов, охватывающих несколько таблиц (INNER JOIN, OUTER JOIN);
  • Более простой, чем в IndexedDB, механизм изменения схемы данных;
  • Кроссбраузерность — поддерживаются браузеры Chrome 37+, Firefox 31+, IE 10+, IE Edge, и Safari 10+

В плане производительности новый движок использует оптимизатор запросов, который оценивает различные варианты выполнения и выбирает наиболее эффективный. Lovefield обеспечивает приемлемую производительность для БД размером до 50 тысяч строк.

Установка

  1. Установить Gulp (если ещё не установлен),
    npm install -g gulp
  2. Установить Bower (если ещё не установлен),
    npm install -g bower
  3. Создать зависимость с package.json,
    npm install
  4. Создать зависимость bower.json,
    bower install
  5. Запустить локальный web-сервер,
    gulp debug
  6. Перейти по адресу http://localhost:8000/todo.html

Использование

Чтобы добавить Lovefield в проект Ionic, вы установите его с помощью npm. [Источник 2]

npm install lovefield 

А затем добавьте оператор импорта. В этом примере мы импортируем все в пространство имен lf.

import * as lf from 'lovefield';

Когда приложению понадобится сохранить данные с помощью Lovefield, сначала придется определить схему. Как и любая база данных SQL, Lovefield должен знать таблицы, столбцы, ограничения и индексы, прежде чем он сможет вставлять, запрашивать, обновлять и удалять данные. Для создания схемы приложение должно вызвать функцию lf.schema.create.

const schemaBuilder = lf.schema.create('users', 1);

Первый параметр указывает имя базы данных, а второй параметр - номер версии. Lovefield поддерживает обновления базы данных, и вам нужно увеличивать этот номер версии каждый раз, когда меняется схема. Более подробную информацию об обновлениях базы данных смотрите в официальной документации. С помощью объекта схемы приложение может определять таблицы и столбцы. Как и в обычной базе данных SQL, таблица состоит из столбцов, и каждому столбцу присвоено имя и тип данных.

  schemaBuilder.createTable('User').
  addColumn('id', lf.Type.INTEGER).
  addColumn('username', lf.Type.STRING).
  addColumn('email', lf.Type.STRING).
  addColumn('note', lf.Type.STRING).
  addColumn('age', lf.Type.INTEGER).
  addColumn('active', lf.Type.BOOLEAN).
  addColumn('created', lf.Type.DATE_TIME).
  addNullable(['note']).
  addPrimaryKey(['id'], true).
  addIndex('idxEmail', ['email'], false, lf.Order.ASC);
  • В дополнение к типам данных, которые мы видим в этом примере, Lovefield поддерживает number, ArrayBuffer и любой объект JavaScript. Смотрите подробное описание типов данных в документации.
  • По умолчанию столбцы, добавленные с помощью addColumn, не обнуляются. Если приложения должны хранить нулевые значения в определенных столбцах, они должны пометить эти столбцы вызовом addNullable как обнуляемые. Столбец note в этом примере может содержать нулевые значения.
  • Схема определяет id столбца в качестве первичного ключа. Второй параметр функции addPrimaryKey указывает, что первичный ключ является полем автонумерации. Если вы хотите использовать автономные номера, столбец должен иметь тип integer. Число начинается с 1 и увеличивается на 1 каждый раз, когда Lovefield вставляет новую строку. Когда первичный ключ настроен как autonumber, вам не нужно добавлять столбец в операторе вставки.
  • Lovefield также поддерживает индексы. Первый параметр функции addIndex присваивает индексу имя, второй параметр указывает столбцы, входящие в этот индекс, третий параметр указывает, является ли индекс уникальным, а последний параметр задает порядок индекса. Приложение может добавлять в таблицу несколько индексов.
  • Lovefield также поддерживает внешние ключи с функцией addForeignKey, а с помощью функции addUnique можно добавлять уникальные ограничения.
  • Все функции, связанные со схемой, являются синхронными операциями, а все операции базы данных, такие как подключение, запрос, обновление, удаление, являются асинхронными и возвращают обещание.

Соединение

С помощью объекта schema приложение может открыть базу данных используя функцию connect.

let userDb;
let user;
  
schemaBuilder.connect()
  .then(db => {
    userDb = db;
    user = db.getSchema().table('User');

    return userDb.delete().from(user).exec();
  })

Lovefield сохраняет данные по умолчанию в IndexedDB. В качестве альтернативы приложение может выбрать серверную часть памяти, которая хранит данные только в памяти. Полезно, когда вы хотите использовать мощные возможности запросов Lovefield, но не имеете требования сохранять данные. Третий вариант-Firebase, который сохраняет данные в одноимённой БД.

Для переключения поставщика хранилища функция connect принимает объект JavaScript в качестве параметра.

schemaBuilder.connect({storeType: lf.schema.DataStoreType.MEMORY}).....

schemaBuilder.connect({storeType: lf.schema.DataStoreType.FIREBASE, 
                       firebase: databaseRef}).....

Если выбран параметр Firebase, приложение также должно предоставить свойство firebase, чтобы предоставить уже подключенную и аутентифицированную ссылку на базу данных Firebase.

Функция connect возвращает обещание с объектом database. С этим объектом приложение получает доступ к таблице с db.getSchema().table('User'). Затем код выполняет инструкцию delete для удаления каждой строки, которая в данный момент хранится в таблице. Lovefield не поддерживает операторы SQL в Строковой форме, как можно было бы ожидать от обычной базы данных SQL. Приложение должно создать запрос с шаблоном builder, подобным API, но результат выглядит очень похожим на операторы SQL

SQL: delete from User

LoveField: userDb.delete().from(user).exec()

Вставка

Для вставки строк приложение должно вызвать функцию createRow из объекта схемы таблицы и предоставить столбцам их значения в качестве объекта JavaScript. Ключи объекта должны совпадать с именами столбцов.

const newRows = [];

  let row = user.createRow({
      username: 'john',
      email: 'john@test.com',
      age: 27,
      active: true,
      created: new Date()
  });
  newRows.push(row);
      row = user.createRow({
      username: 'ralph',
      email: 'ralph@test.com',
      age: 32,
      active: true,
      created: new Date(),
      note: 'the admin'
  });
  newRows.push(row);

  row = user.createRow({
      username: 'jodie',
      email: 'jodie@test.com',
      age: 23,
      active: false,
      created: new Date()
  });
  newRows.push(row);

  return userDb.insertOrReplace().into(user).values(newRows).exec();

Для вставки строк приложение вызывает функцию insert или insertOrReplace из объекта базы данных. insertOrReplace проверяет, содержит ли новая строка значение первичного ключа, и заменяет строку тем же ключом в таблице, когда она уже существует. Когда новая строка содержит первичный ключ, который еще не сохранен в таблице, или строка не определяет ключ, и таблица использует autonumber первичный ключ insertOrReplace вставляет строку в таблицу.

Примечание: Если в таблице не указан первичный ключ в схеме приложение не может вызвать insertOrReplace. Функция values ожидают массив строк. Даже если приложение хочет вставить только одну строку, оно должно обернуть ее в массив: values([row]).

Получение данных

С помощью запроса select приложение может получать данные из базы данных. SQL-запрос, подобный этому select * from User, очень похож на тот, что используется в Lovefield userDb.select().from(user).exec().then(rows => .....

Как и все другие операции базы данных, выбранные являются асинхронными и возвращают обещание. Обещание содержит выбранные строки в виде массива объектов. Например, приложение может получить доступ к идентификатору первой строки с помощью строк этого кода rows[0].id. Lovefield поддерживает проекции, указывая столбцы в качестве параметров функции select. Когда вы вызываете select без каких-либо параметров Lovefield предполагает выбрать оператор select*. Результат инструкции select можно отсортировать с помощью orderBy.

userDb.select(user.username)
      .from(user)
      .orderBy(user.username, lf.Order.DESC)
      .exec()

Lovefield поддерживает несколько операторов orderBy.

userDb.select(user.username)
      .from(user)
      .orderBy(user.username, lf.Order.DESC)
      .orderBy(user.id)
      .exec()

Этот оператор сначала сортирует строки по имени пользователя в порядке убывания, и когда имена одинаковы, он упорядочивает их по идентификатору в порядке возрастания. Условия поиска поддерживаются функцией where. Запрос, который выбирает всех активных пользователей будет выглядеть следующим образом

userDb.select()
      .from(user)
      .where(user.active.eq(true))
      .exec()

Lovefield поддерживает функцию сравнения как функции объекта столбца (например, user.active.eq) Вы найдете список всех поддерживаемых функций в документации. Для объединения нескольких предикатов Lovefield предоставляет вспомогательные функции lf.op.and, lf.op.or и lf.op.no.

userDb.select()
      .from(user)
      .where(
          lf.op.and(
             user.active.eq(true), 
             user.age.gt(30)
          )
       )
      .exec()

Lovefield включает поддержку функций groupBy и aggregate.

Запрос, вычисляющий среднее значение и количество строк

userDb.select(lf.fn.avg(user.age), lf.fn.count(user.id))
      .from(user)
      .exec())

Условия Group by добавляются в запрос с помощью функции groupBy.

userDb.select(lf.fn.count(user.id), user.active)
      .from(user)
      .groupBy(user.active)
      .exec()

Другие функции, включенные в Lovefield, - это функции limit и skip для ограничения возвращаемых строк и пропуска определенного количества строк. Lovefield также способен выполнять запросы с соединениями. [Источник 3]

Обновление

Обновления выполняются с помощью функции update

userDb.update(user)
      .set(user.active, true)
      .where(user.active.eq(false))
      .exec()

Примечание. Lovefield не поддерживает инструкции update с вычисляемыми значениями: update User set age = age + 1

Источники

  1. LoveField // GitHub. [2015-2018] Дата обновления: 30.07.2018. URL: https://google.github.io/lovefield/ (Дата обращения: 10.10.2018)
  2. Lovefield, a SQL database engine for the web // Ralph's Blog. [2017-2018] Дата обновления: 29.11.2018. URL: https://golb.hplar.ch/2017/02/Lovefield-a-SQL-database-engine-for-the-web.html#connect (Дата обращения: 10.12.2018)
  3. Lovefield Specification // GitHub [2015-2018] Дата обновления: 30.07.2018. URL: https://github.com/google/lovefield/blob/master/docs/spec/04_query.md#414-limiters-and-order (Дата обращения: 10.10.2018)