Skip to content

JS-библиотека для построения Базы Данных с SQL-подобным API на основе Google-таблиц и Google-скрипта. Как Firebase 🔥, только свой. Всего 4 кБ !!! 😋

Notifications You must be signed in to change notification settings

AlbertSadykovOfficial/JSQL

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

20 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

JSQL

JSQL - небольшая библиотека для построения Базы Данных на основе Google-таблиц. Теперь и для Google APIv3 😋

🚀 Всего 4 кБ !!!

alt text

Github Page Demo:

https://albertsadykovofficial.github.io/JSQL/index.html

Примечание к использованию:

✅ Можно использовать как набор разнородных файлов из каталога lib/parts/.

✅ Можно использовать файлы каталога lib/all_in_one/ как (ВСЕ В ОДНОМ).

Настройка для использования:

Для использования вам нужно:

  1. Создать Google-таблицу,

    1.1 Опубликовать ее для всех,

    1.2 Создать несколько листов по нужде (лист - это таблица нашей БД)

    1.3 Скопировать ее хэш

  2. Создать два Google-скрипта

    2.1 Всавить содежимое скриптов из папки google_script (https://github.com/AlbertSadykovOfficial/JSQL/blob/master/lib/google_script/) в свои скрипты ИЛИ отсюда: (https://script.google.com/home/projects/1Zuugnn0eKfMxsVGUjc3aXoLhRZAk6EHMPZ-7h2Cqn03RAL4FMkTmd5Ic/edit)

    2.2 Вставить в переменную SHEET_KEY (в скриптах) - хэш своей таблицы

    2.3 Сохранить изменения.

    2.4 Опубликовать скрипт как веб-приложение, сделать его выполнение доступным всем.

    2.5 Скопировать ХЭШи 2х таблиц

Параметр Значение
grab_script_hash Ключ ссылки на скрипт сбора данных (скрипт должен быть публичным)
change_script_hash Ключ ссылки на скрипт изменения данных(скрипт должен быть публичным)
[table_name.., .. ] Имя листа в таблице.

Далле следует скачать библиотеку (к примеру callback min верию) и добавить ее:

<script src="my_project/js/JSQL_callback.min.js"></script>

После этого (после добавления библиотеки) нужно создать объект, необходимый для функционирования бибилиотеки.

Параметры объявления:

let JSQL = new JSQL_constructor(grab_script_hash, change_script_hash, [table_name_1, table_name_2, ...]);

Пример:

let JSQL = new JSQL_constructor('AKfycbx_aLxhvDyzScnCWIfX4jyl4dvLpwvJovqwxYZ2D8ybixzE-mhKulJ5vwBj1KsoFqzjAw', 
                                'AKfycbyYYihG8l7QthbD8Pcu6M9jYtyv57Q9KWM15iIQhFKEJL06ed7GKo5SCaXzS1_pGxeaDg', 
                                ['main', 'members', 'sandbox']);

Терминология

В терминологии библиотеки:

  • Google-Таблица -> База данных.
  • Отдельные Листы Google-Таблицы -> таблицы Базы данных Т.е. далее, к примеру, table_name - это не имя Google-таблиц, а имя листа Google-таблицы.

Общая рекомендация перед примерами использования

Стоит понимать, что это библиотека некий эмулятор взаимодействия с БД. Обычно БД находится на одном компьютере с серверным скриптом и время общения между ними-миимально. У нас же другой вариант - мы получаем данные с сервера, обрабатываем их у себя и отправляем данные обратно... Давольно немало времени тратится на передачу данных в одну сторону, а потом в другую. Это, конечно, порождает проблемы с синхронизацией данных. Если данные меняются каждые несколько секунд - не проблема. Но если период обновления около секунды - это проблема.

Отсюда первая рекомендация - не используйте библиотеку для высоконагруженных приложений, она скорее для простых приложений или для демострации возможности приложения без поднятия сервера (самое то для начинающих).

Вторая рекомендация (для async)- не вызывайте кучу команд сразу в одной функции, особенно это касается последовательности: SELECT -> INSERT или UPDATE или DELETE -> а потом опять SELECT. Пока данные вставляются вызов SELECT во 2й раз не успеет считать новые данные, он скорее всего считает старые. Лучше делать небольшие функции с 1м вызовом SELECT в начале, а затем нужной нам функцией -> Вставить, Обновить или Удалить. Тогда времени должно хватить. Также лучше пытайтесь изменять (доабвлять, удалять) данные одной командой вместо нескольких, для этого есть специлальный синтаксис.

Пример плохого применения:

INSERT('sandbox', [['username', user1],['level', level1],['say', says1]]);
INSERT('sandbox', [['username', user2],['level', level2],['say', says2]]);
INSERT('sandbox', [['username', user3],['level', level3],['say', says3]]);

Пример хорошего применения, лучше 1 команда, чем предыдущие 3.

INSERT('sandbox', [
			['username', [user1, user2, user3]],
			['level', [level1, level2, level3]],
			['say', [says1, says2, says3]]
		]);

Варианты библиотеки

Есть 2 варианта библиотеки, они оличаются функциям приема данных:

  1. Варинат callback (Promise)
  2. Вариант async/await (!!! ВНИМАНИЕ: НЕ РАБОТАЕТ С APIv3 (на 12.10.2021), Планируется устраниенеи этой проблемы !!!)

Функция извлечения данных из БД периодически по каким-то причинам не срабатывает. В таком случае я выбрасываю ошибку. Вы можете отловить эту ошибку и снова попробовать сделать запрос на получение данных. В callback-варианте я запрашиваю данные 1 раз целиком и потом с ними работаю. Все команды в callback-фунции оперируют данными, которые мы получили на вход функции. Напротив, в варианте async/await для любой операции кроме INSERT требуется получение данных от БД. Соответсвенно, при использовании async/await кол-во обращений к БД повышается, а значит, повышается и частота возникновния ошибок. Поэтому я расскажу о callback-варианте в первыую очередь, а что выбрать - реать вам.


Примеры использования (для callback-варианта)

Вызвать функцию

Чтобы получить данные из google-таблицы, следует вызвать функцию queryJSQL(). Функция выполнит асинхронный запрос к таблице и вернет результат в callback-функцию, которую мы указали. Результатом функции при успешном выполнении является массив коллекций. При ошибке - ошибка, поэтому, чтобы не упал код можно поставить try/catch.

Принимающая callback-функция должна иметь только 1 аргумент (data)!

Параметры:

Параметр Значение
error_f callback-функция при ошибке
success_f callback-функция при успешном получении данных
table_name имя таблицы (листа) из которой извлекаем данные

Синтаксис:

queryJSQL(error_f, success_f, table_name); 

Пример:

queryJSQL(console.log, select_data, 'main');
queryJSQL(custom_log, update_data, 'members');
queryJSQL(custom_alert, insert_data, 'sandbox');

Дальше массив данных приходит в указанную нами функцию, через некоторое время. ВАЖНЫЙ МОМЕНТ: Данные приходят как текст. Его необходимо преобразовать в JSON вначале функции для нормальной работы всех функций:

function select_data(значения_из_БД)
{
	значения_из_БД_JSON = JSON.parse(значения_из_БД);
	...наш код
	...тут можно использовать функции, приведенные ниже
}

Команды

SELECT

Синтаксис:

SELECT('значения из БД', 
		[имя_колонки_1, имя_колонки_2,..., имя_колонки_N], 
		[ 
			[имя_колонки, ВЫРАЖЕНИЕ, [значение_1, значение_2, ..., значение_N]], 
			[имя_колонки, ВЫРАЖЕНИЕ, [значение_1, значение_2, ..., значение_N]],
			...
		]);

Пример:

function select_data(data)
{
	data = JSON.parse(data);
	user_mail = '[email protected]';
	from_date = new Date('1980-01-01');
	to_date   = new Date('2099-01-01');
	
	result = SELECT(data, ['mail', 'city', 'date', 'doctype'], 
			[ 
				['mail','!=', user_mail], 
				['date', 'from', [from_date]],
				['date', 'to', [to_date]],
			]);
}

COUNT

Синтаксис абсолютно такой же как и у SELECT:

COUNT('значения из БД', 
		[имя_колонки_1, имя_колонки_2,..., имя_колонки_N], 
		[ 
			[имя_колонки, ВЫРАЖЕНИЕ, [значение_1, значение_2, ..., значение_N]], 
			[имя_колонки, ВЫРАЖЕНИЕ, [значение_1, значение_2, ..., значение_N]],
			...
		]);

INSERT

Синтаксис:

INSERT('таблица', [
                      [ имя_колонки, [значение_1, значение_2, ..., значение_N]],
                      [ имя_колонки, [значение_1, значение_2, ..., значение_N]],
                       ...
                    ]);

Пример:

function insert_data(data)
{
	block = document.getElementById('insert_example_block');

	user = block.getElementsByClassName('UserName')[0].value;
	level = block.getElementsByClassName('level')[0].value;
	says = block.getElementsByClassName('say')[0].value;
	
	INSERT('sandbox', [
		                   ['username', user],
		                   ['level', level],
		                   ['say', says]
	                 ]);
}

UPDATE

Синтаксис:

  UPDATE('значения из БД','таблица', [
                                          [ имя_колонки, новое_значение],
                                          [ имя_колонки, новое_значение],
                                            ...
                                        [,
                                        [
                                          [имя_колонки, ВЫРАЖЕНИЕ, [значение_1, значение_2, ..., значение_N]],
                                          [имя_колонки, ВЫРАЖЕНИЕ, [значение_1, значение_2, ..., значение_N]],
                                            ...
                                      [));_

Пример:

function update_data(data)
{
	data = JSON.parse(data);
	block = document.getElementById('update_example_block');

	set_column = block.getElementsByClassName('column')[0].value;
	set_value = block.getElementsByClassName('set_input')[0].value;

	where_column = 'ID';
	where_value = block.getElementsByClassName('where_input')[0].value;

	UPDATE(data, 'sandbox', [
					[set_column, set_value],
				],
				[
					[where_column, '=', where_value],
				]
	);
}

DELETE

Синтаксис:

  DELETE('значения из БД', 'таблица', [
                                          [имя_колонки, ВЫРАЖЕНИЕ, [значение_1, значение_2, ..., значение_N]],
                                          [имя_колонки, ВЫРАЖЕНИЕ, [значение_1, значение_2, ..., значение_N]],
                                          ...
                                      ]);

Пример:

function delete_data(data)
{
	data = JSON.parse(data);
	block = document.getElementById('delete_example_block');

	column = block.getElementsByClassName('column')[0].value;
	value = block.getElementsByClassName('input_section')[0].value;

	DELETE( data, 'sandbox', [
					[column, 'LIKE', value]
				 ]);
}

Примеры использования (для async/await-варианта) (!!! ВНИМАНИЕ: НЕ РАБОТАЕТ С APIv3 (на 12.10.2021), Планируется устраниенеи этой проблемы !!!)

Другой вариант использования - использование библиотеки с функционалом async/await. Напомню особенность таких функций:

  • await может использоваться только внутри async-функций, это обязывает писать async перед всеми функциями, в которых намеривается использование библиотеки.

При работе с async/await использование очень напоминает стандартное поведение при программировании на серверных языках (к примеру, php). Мы так же получаем данные в переменную, потом их последовательно обрабатываем, а не как в варианте с callback получаем все и сразу, а потом уже разбираем полученные данные.

Почему тогда не использовать этот вариант, раз он так хорош? Причины:

  • Он рабаотет не так стабильно как вариант с callback, периодически выдавал ошибку CORS Missing Allow Origin, возможно из-за очень частых запросов, так или иначе, варинат с callback не так часто ругался, но все же иногда бывает.
  • Требует ставить async перед всеми функциями, которые будут обращатсья к БД (хотя это не такая весомая причина)
  • Не успевает. В следующем примере идет SELECT, затем INSERT и UPDATE, а затем опять SELECT. Стоит ожидать, что данные при 1м вызове SELECT и 2м будут отличаться, но это не совсем так...
    • Причина 1. В логике отправки данных. Отправка UPDATE и DELETE состоит из 2х этапов:
      • 1й - Выбрать id строк через SELECT, которые удовлетворяют условию.
      • 2й - Отправить данные через iframe Так вот, 1й этап хорошо отрабатывает, async/await срабатывают, но вот окончания 2го этапа функция await не дожидается, пока данные заносятся, мы уже снова можем вызвать SELECT и получить устаревшие данные.
    • Причина 2. Google-таблице нужно немного времени, чтобы отобразить изменения, поэтому если мы в короткий промежуток времени (каким является время выполнения кода) вызовем несколько функций подряд, то таблица еще не отобразит изменения и мы получим старые данные. Поэтому между операциями считывания (SELECT) нужно делать паузы и, НАВЕРНОЕ, стоит использовать их больше одной за функцию.

В оправдание async:

  • В callback варианте SELECT вообще не обращается к БД, а работает как фильтр над принятми данными, поэтому он тоже при вызове SELECT видит не новые данные скаолько бы мы INSERT и UPDATE не вызывали.

Изменения синтаксиса по сравнению с callback-вариантом:

  • Теперь мы не передаем в функции массив данных, теперь параметры функций еще больше схожи с реальным синтаксисом SQL.

Синаксис :

 SELECT('Имя_таблицы', 
		[имя_колонки_1, имя_колонки_2,..., имя_колонки_N], 
		[ 
			[имя_колонки, ВЫРАЖЕНИЕ, [значение_1, значение_2, ..., значение_N]], 
			[имя_колонки, ВЫРАЖЕНИЕ, [значение_1, значение_2, ..., значение_N]],
			...
		]);

Пример функции:

async function async_example()
{
	// Пример Извлечения данных и подсчета
	let data = await SELECT('sandbox', 
					['UserName', 'level'], 
					[
						['id', '!=', '10']
					]);
	let count= await COUNT('sandbox', [['id', '!=', '10']]);
	console.log(data, count); 
	
	// Вносим данные
	INSERT('sandbox', [
				['username', 'Аль-Ка-Пони'],
				['level', '35'],
				['say', 'Макфа']
			    ]);

	// Обновляем данные
	await UPDATE('sandbox', [
					['level', 'oVER 999']
				  ], 
				  [
					['Username', 'LIKE', 'Имба'],
				  ]);

	// Получим больше данных и выведем их в таблицу
	data = await SELECT('sandbox', 
					['ID' ,'UserName', 'level', 'say'], 
					[
						['id', '!=', '10']
					]);

	// Как видно, изменения не успели примениться
	// 1й вызов равен 2му, несмотря на то что между ними мы изменяли данные.
	console.log(data); 

	// Эта функция выводит данные в таблицу, ее нет в составе библиотеки
	print_result_as_array(
				['ID' ,'UserName', 'level', 'say'], 
				['ID', 'Имя', 'Уровень', 'Сказал'], 
				data
			      );
}

Преимущества async над callback:

  • Не надо вызывать специальную функцию queryJSQL() для вызова функции
  • Более удобный и интуитивный синтаксис, схожий с оригинальной работой с БД.

Недостатки async в сравнении с callback

  • Менее стабилен - главный минус.
  • Требует перед всеми функциями, которые его используют, писать async

About

JS-библиотека для построения Базы Данных с SQL-подобным API на основе Google-таблиц и Google-скрипта. Как Firebase 🔥, только свой. Всего 4 кБ !!! 😋

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published