Въведение

В този урок ще изградим уеб приложение, използвайки AdonisJS и ще го интегрираме с Materialize, за да създадем табло за управление в реално време, базирано на поточно предаване на данни, използвайки стандартен SQL.

Materialize ви позволява да дефинирате изгледи, които искате да поддържате върху вашите данни, точно както бихте направили с всяка SQL таблица, и след това да получите резултатите в реално време, за разлика от традиционните бази данни, които често действат така, сякаш никога преди не им е задаван този въпрос.

Предпоставки

Трябва да имате инсталирани следните неща, преди да започнете:

Какво е Материализиране

Materialize е база данни за поточно предаване, която взема данни, идващи от източници като Kafka, PostgreSQL, S3 кофи и други, и ви позволява ефективно да ги трансформирате в реално време с помощта на SQL.

За разлика от традиционната база данни, Materialize е в състояние постепенно да поддържа изгледи върху поточните данни, предоставяйки свежи и правилни резултати при пристигането на нови данни. Това означава, че вместо да преизчислява изгледа от нулата всеки път, когато трябва да се актуализира, той върши работа само пропорционално на промените в своите входове, така че е бърз и ефективен.

В контекста на уеб разработката, Materialize може да се използва като бекенд за захранване на приложения в реално време (както ще видим в тази демонстрация)!

Пускане на демонстрация на Materialize

За целите на този урок ще стартираме следната демонстрация на Materialize:

Материализирайте — Демонстрация на разбор на журнали

Настройката на демото е следната:

Тук няма да навлизаме в твърде много подробности, но ако не сте преминавали през тази демонстрация преди, не забравяйте да я прочетете!

За да стартирате демонстрацията, изпълнете следните стъпки:

Първо, преди да стартирате демонстрацията, трябва да клонирате хранилището:

cd mz-http-logs
docker-compose up -d

С това ще имате готов и работещ екземпляр на Materialize. След това ще подготвим нашата инсталация на AdonisJS и ще използваме AdonisJS, за да създадем нашите източници и изгледи на Materialize!

Какво е AdonisJS

AdonisJS е уеб рамка за Node.js. Той включва всичко, от което се нуждаете, за да създадете напълно функционално уеб приложение или API.

AdonisJS е вдъхновен от Laravel и има собствен ORM, поддръжка за удостоверяване и CLI инструмент, наречен Ace, който е много подобен на Artisan.

Накрая ще разширим демонстрацията на Log parsing Materialize и ще имаме следната настройка:

Инсталирайте AdonisJS

Нека започнем с инсталирането на AdonisJS. За да направите това, ще трябва да изпълните следната команда:

След като стартирате това, ще бъдете помолени да изберете структура на проекта. Ще можете да избирате между API, уеб приложение и минимално възможно приложение на AdonisJS:

CUSTOMIZE PROJECT ❯ Select the project structure ... Press to select
api (Tailored for creating a REST API server)
❯ web (Traditional web application with server-rendered templates) 
slim (A smallest possible AdonisJS application)

За този урок нека започнем с приложението web! С помощта на клавишите със стрелки изберете web и натиснете Enter.

След това ще бъдете помолени да изберете име за проекта, ще оставя това като hello-materialize, но не се колебайте да изберете друго име.

След това ще натисна enter и ще кажа „да“ на останалите настройки:

❯ Enter the project name · hello-materialize ❯ Setup eslint? (y/N) · y ❯ Configure webpack encore for compiling frontend assets? (y/N) › y

Това ще създаде екземпляр на проекта и може да отнеме до минута, за да завърши:

След като сте готови, можете да cd в новата директория на проекта:

cd hello-materialize

След това стартирайте уеб сървъра:

node ace serve --watch

Ако идвате от света на Laravel, това би било точно като да стартирате php artisan serve. Инструментът ace CLI е точно като artisan и се предлага с много същите функции.

За да проверите всички ace команди, можете да стартирате: node ace.

Инсталиране на Lucid

Lucid е AdonisJS ORM. Той е доста подобен на Laravel Eloquent.

Lucid идва с Active Record ORM, Query Builder, Migrations, Seeds и Factories.

Нека да го инсталираме! За да направите това, просто изпълнете следната команда:

След като приключите, ще трябва да направите бърза конфигурация.

Конфигуриране на Lucid

За да конфигурирате Lucid, трябва да изпълните следната команда ace:

Ще бъдете помолени да изберете драйвера на базата данни, който искате да използвате. Тъй като Materialize е кабелно съвместим с PostgreSQL, можете да се свържете с него, като използвате всеки pg драйвер; тук, не забравяйте да изберете PostgreSQL!

https://user-images.githubusercontent.com/21223421/142431728-ac88085b-34cb-4ebb-83c7-b0cae9fb455d.png

След това ще бъдете помолени да изберете къде искате да покажете инструкциите за конфигурация. Избрах In the terminal, който отпечатва необходимите променливи на средата, които трябва да добавите към вашия .env файл.

Конфигурирайте променливите Materialize env

За да позволим на нашето приложение AdonisJS да се свърже с Materialize, трябва да променим детайлите PG_* във файла .env.

С любимия си текстов редактор отворете файла .env и актуализирайте променливите на средата PG_ до:

DB_CONNECTION=pg 
PG_HOST=localhost 
PG_PORT=6875 
PG_USER=materialize 
PG_PASSWORD= 
PG_DB_NAME=materialize

Това ще позволи на AdonisJS да се свърже с Materialize точно както при свързване с PostgreSQL.

Едно нещо, което трябва да имате предвид е, че Materialize все още не поддържа пълния системен каталог на PostgreSQL (работим по него!), което означава, че ORM като Lucid, Prisma, Sequelize или TypeORM може да се провалят по време на някои опити за взаимодействие с Materialize. Докато работим за разширяване на покритието на pg_catalog, интеграцията с тези инструменти постепенно ще се подобрява!

Създаване на контролер

Нека създадем контролер, където ще добавим функционалността, която ще ни позволи да се свържем с Materialize!

Тъй като демонстрацията на Materialize симулира журнал на приложение с много посетители, нека извикаме нашия AdonisJS контролер VisitorsController:

Това ще създаде контролен файл на:

app/Controllers/Http/VisitorsController.ts

След това нека създадем маршрутите, които ще ни трябват!

Създаване на маршрутите на AdonisJS

Вашият файл с маршрути се съхранява на адрес start/routes.ts. Там можем да посочим URL адресите на нашите приложения и да ги съпоставим с различни контролери и методи!

Все още нямаме готови методи, но знаем, че ще ни трябват следните маршрути:

  • /source: Когато бъде посетен, този маршрут ще създаде материализиран източник
  • /view: При посещение този маршрут ще създаде материализиран изглед
  • /visitors: Този маршрут ще върне поток от събития с всички последни промени в нашия материализиран изглед
  • /: Това ще бъде целевата страница, където ще показваме поточните данни, които получаваме от крайната точка /visitors и Materialize

Отворете вашия файл с маршрути на адрес start/routes.ts и го актуализирайте така, че да има следното съдържание:

import Route from '@ioc:Adonis/Core/Route' 
Route.get('/', 'VisitorsController.index') 
Route.get('/visitors', 'VisitorsController.visitors') Route.get('/source', 'VisitorsController.source') 
Route.get('/view', 'VisitorsController.view')

След това нека добавим метод, който ще ни позволи да създадем материализиран източник, както е описано в Демонстрация на материализиране на анализ на журнали!

Създаване на материализиран източник от регистрационни файлове

Ако осъществявате достъп до Materialize директно чрез SQL клиент (като psql), за да получите достъп до данни от непрекъснато генериран лог файл, ще изпълните следния оператор:

Нека да видим как можем да направим това чрез AdonisJS!

Първо отворете файла app/Controllers/Http/VisitorsController.ts с любимия си текстов редактор.

Първоначално файлът ще има следното съдържание:

Има няколко неща, които бихме искали да направим:

// import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import Database from '@ioc:Adonis/Lucid/Database'
export default class VisitorsController {
public async source({request, response}) {
//Using Ludic to connect to Materialize, we are executing a CREATE SOURCE statement
const res = await Database.rawQuery(
`CREATE SOURCE requests
FROM FILE '/log/requests' WITH (tail = true)
FORMAT REGEX '(\\?P<ip>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) - - \[(\\?P<ts>[^]]+)\] "(\\?P<path>(\\?:GET /search/\\\?kw=(\\?P<search_kw>[^ ]*) HTTP/\d\.\d)|(\\?:GET /detail/(\\?P<product_detail_id>[a-zA-Z0-9]+) HTTP/\d\.\d)|(\\?:[^"]+))" (\\?P<code>\d{3}) -';`
);
return res;
}
}

Сега, ако посетите /source URL през вашия браузър ( http://127.0.0.1:3333/source), това ще създаде вашия източник на Materialize:

Създаване на материализиран изглед

Може да сте запознати с материализирани изгледи от света на традиционните бази данни като PostgreSQL, които по същество са кеширани заявки. Уникалната характеристика тук е, че материализираният изглед, който ще създадем, автоматично се поддържа актуален.

Нека направим същото като преди, но да създадем материализиран изглед въз основа на нашия файлов източник! За да направите това, нека създадем метод, наречен view със следното съдържание:

Добавете това веднага след края на метода source

public async view({request, response}) {
//Using Ludic to connect to Materialize, we are executing a CREATE VIEW statement
const res = await Database.rawQuery(
`CREATE OR REPLACE MATERIALIZED VIEW unique_visitors AS
SELECT count(DISTINCT ip) FROM requests;`
);
return res;
}

Нашият материализиран изглед ще покаже броя на уникалните посетители, преминаващи през нашето демонстрационно приложение.

За да създадете изгледа, посетете /view URL чрез вашия браузър (напр. http://127.0.0.1:3333/view).

С това нашият изглед ще бъде създаден и можем да преминем към следващата стъпка!

Създаване на поток от събития

Можете да направите запитване към новия материализиран изглед, който току-що създадохме, както обикновено със стандартен оператор SELECT:

SELECT * FROM unique_visitors;

Въпреки това, за да се възползваме напълно от постепенно актуализирания материализиран изглед направо от нашето приложение AdonisJS, вместо да питаме Materialize със стандартен SELECT, за да получим състоянието на изгледа в даден момент, ще използваме израз TAIL, за да поискаме поток от актуализации при промяна на изгледа.

public async visitors({request, response}) {
// First we set a header to identify that this would be an event stream
response.response.setHeader('Content-Type',  'text/event-stream');
// Then we declare a TAIL cursor
await Database.rawQuery('BEGIN');
await Database.rawQuery('DECLARE visitors_c CURSOR FOR TAIL unique_visitors');
// Finally we use FETCH in a loop to retrieve each batch of results as soon as it is ready
while (true) {
const res = await Database.rawQuery('FETCH ALL visitors_c');
response.response.write(`data: ${JSON.stringify(res.rows)}\n\n`)
}
}

За повече информация относно TAIL, не забравяйте да проверите официалната документация тук:

„Материализирайте TAIL изявление“.

Ако сега посетите /visitors URL чрез вашия браузър, ще видите следния резултат:

След това нека създадем изглед, където ще използваме крайната точка /visitors като източник на събитие и непрекъснато ще актуализираме нашата уеб страница.

Показване на броя на уникалните посетители във фронтенда

Първо, преди да започнем, уверете се, че сте изпълнили следната команда, за да конфигурирате Encore, който се използва за компилиране и обслужване на предните активи за вашето приложение AdonisJS:

node ace configure encore

След това създайте нов файл на:

resources/views/visitors.edge

И добавете следното съдържание:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Materialize and AdonisJS</title>
@entryPointStyles('app')
@entryPointScripts('app')
</head>
<body>
<main>
<div>
<h1 class="title"> Hi there! </h1>
<p class="subtitle">
The number of unique visitors is: <strong><span id="count"></span></strong>
</p>
</div>
</main>
<script>
var eventSource = new EventSource("http://127.0.0.1:3333/visitors");
const count = 0;
eventSource.onmessage = function(e) {
const data  = JSON.parse(e.data)
//const count = omit(data, 'mz_timestamp', 'mz_diff', 'mz_progressed')
const { mz_diff, mz_progressed } = data;
data.forEach(entry => {
if(entry.mz_diff == -1){
console.log('Old count: ' + entry.count)
} else {
console.log('New count: ' + entry.count)
let countDiv = document.getElementById("count");
countDiv.innerHTML = entry.count;
}
})
};
</script>
</body>
</html>

Кратък преглед на основните неща, които трябва да имате предвид:

  • new EventSource: Първо дефинираме нов EventSource и определяме нашата /visitors крайна точка.
  • eventSource.onmessage: След това слушаме за нови съобщения, които да се показват в EventStream.
  • JSON.parse(e.data): След това анализираме нашите данни
  • data.forEach: Накрая стартираме цикъл и актуализираме брояча на общите уникални посетители на страницата.

Сега, ако посетите вашето приложение AdonisJS, ще видите следния резултат:

Както можете да видите, вместо да правим огромно количество AJAX заявки, ние просто се включваме в потока и поддържаме нашата уеб страница актуална с най-новите промени от Materialize!

Заключение

Това е почти всичко! Вече създадохте уеб приложение, използвайки AdonisJS, което се свързва с Materialize и изтегля броя на уникалните посетители от вашето приложение, когато се регистрират нови данни.

Като следваща стъпка не забравяйте да се насочите към Materialize Docs и да изпробвате някои от наличните демонстрации:

„Материализиране на демонстрации“

За да научите повече за AdonisJS, можете също да намерите документацията тук:

Документация на AdonisJS

Можете да намерите връзка към изходния код на AdonisJS от тази демонстрация тук:

Поточно предаване на данни с демонстрационни файлове Materialize и AdonisJS

За да научите повече за Streaming SQL, не забравяйте да проверите тази публикация тук:

Поточно предаване на SQL: Какво е това, защо е полезно?

Надяваме се, че това е било полезно!

Първоначално публикувано на https://devdojo.com.