Modeller üzerinde SQL yazmak yönetimi zorlaştırdığı için bir SQL oluşturucu kütüphaneye ihtiyacımızın olduğunu hissettim. Bir kaç araştırma yaptım fakat SQL'i daha basit nasıl yazarız konusunda yine tereddütlerim oldu baktığım kütüphaneler de bir sürü method içeriyordu. Eğer ben çok method kullanacaksam zaten SQL kullanırım ne gerek ve benim SQL oluşturucuya. Araştırdığım ve hoşuma giden kütüphaneler:
https://www.npmjs.com/package/sqlmaker
https://www.npmjs.com/package/squel
Fakat ben bu kütüphaneleri kullanmak istemedim :/ 2016 sıralarında kendi yazdığım bir kütüphane aklıma geldi. Dedim şuna bir bakayım (PHP üzerinde yazmıştım o sıralar). Bir SQL oluşturucu için gerekli çoğu methodu yazmışım ve bu çok basit. Sonra dedim ben bunu JavaScript'e çeviririm :) Standartlarını bozarak da olsa çevirebildim. Ve ismine
Birkaç uğraş ve çaba ile yayınladım ve npm üzerinde de paylaştım. Projemize kurmak için:
npm i sqlmaster --save
Nasıl kullanılacağını dokümanına yazdım. Biz ilk işimize user modelden başlayalım. Hemen insert sorgumuzu yazabiliriz. api/models/users.js dosyasını düzenleyelim.
const database = require('../../database');
const sm = require('sqlmaster');
class Users {
insert(user) {
var query = sm
.from('users')
.insert({
name: user.name,
email: user.email,
date: new Date(),
})
.exec();
return new Promise((resolve, reject) => {
database.execute(query, (err, res) => {
if (err !== null) {
reject(err)
} else {
resolve(true);
}
})
})
}
isExist(email) {
var query = sm
.from('users')
.where('email = :email', {
':email': email
})
.select([
"email"
])
.exec();
return new Promise((resolve, reject) => {
database.execute(query, (err, res) => {
if (err !== null) {
reject(err)
} else {
if (res.rows.length > 0)
return resolve(true); // kullanıcı var
return resolve(false); // kullanıcı eklenmemiş
}
})
})
}
}
module.exports = new Users();
Artık oyunumuzun asıl amacına gelelim yani "Oyunları yönetelim!"
İlk önce satranç'ın kurallarından bahsettiğim yazımdan bahsedeyim biraz. Aslında satranç'ın FEN ve SAN üzerinden neredeyse tüm modellemelerini yapabileceğimizi söylemiştik. Kısaca FEN, oyunun son durumu. SAN, oyunda yapılan tüm hareketlerdi. Peki biz buna göre nasıl bir tablo oluşturacağız ona bakalım.
Oyun için toplamda 3 adet tablo olacak bunlar: games, game_fen, game_san. Şunları içerecekler:
id | from | to | date | from_date | to_date |
---|---|---|---|---|---|
oyunun id'si | oyunu teklif eden veya açan kişinin id'si | oyunu kabul eden kişinin id'si | oyunun başlama tarihi | (kalan zamanı) oyunu açan kişinin oyunun başlangıç tarihine süre eklenmiş (ör: 10dk) tarihi | (kalan zamanı) oyunu kabul eden kişinin oyunun başlangıç tarihine süre eklenmiş (ör: 10dk) tarihi |
id | fen |
---|---|
oyunun id'si | oyunu fen değeri |
id | san |
---|---|
oyunun id'si | oyunu san değeri |
Oyunun san değeri belirli bir uzunlukta olmadığından bunun alan tipine TEXT vereceğiz. FEN değeri de aynı şekilde belirli bir uzunluğa sahip değil ama TEXT gibi bir ifade için ise çokta uzun değil. Bir kaç araştırma yaptım ama kesin bir sonuca varamadım en son 144 karakter olabileceği konusunda konuşmalar buldum:
http://www.talkchess.com/forum/viewtopic.php?topic_view=threads&p=531397&t=49083
http://www.talkchess.com/forum/viewtopic.php?t=49083
http://rybkaforum.net/cgi-bin/rybkaforum/topic_show.pl?tid=8689
Ama ben kesin bir sonuç bulunamadığını göz önüne alarak 255 karakter verme konusunda karar kıldım. Eğer ki 255 karakteri bile geçebilecek bir FEN olabilirse buna sonra değiniriz.
CREATE TABLE games (id SERIAL PRIMARY KEY, "from" INT, "to" INT, date DATE, from_date DATE, to_date DATE);
CREATE TABLE game_fen (id INT PRIMARY KEY, fen CHAR(255));
CREATE TABLE game_san (id INT PRIMARY KEY, san TEXT);
Ve son olarak kullanıcıların giriş yapmasını sağlayacak bir sistem daha kurmalıyız. Yani şifresini tutmalıyız. Bunun için user_password diye bir tablo oluşturalım.
id | password |
---|---|
kullanıcının id'si | kullanıcının şifresi |
CREATE TABLE user_password (id INT PRIMARY KEY, password CHAR(128));
Şifreleme işlemi için pbkdf2Sync kullanacağız. user_password tablosu için bir model oluşturalım. api/models/userPassword.js dosyasını şöyle oluşturalım:
const database = require('../../database');
const sm = require('sqlmaster');
const crypto = require('crypto');
class UserPassword {
insert (id, password) {
return new Promise((resolve, reject) => {
if (!password)
return reject(new Error('password is null'));
password = crypto.pbkdf2Sync(password, 'satranc', 100000, 64, 'sha512').toString('hex');
var query = sm
.from('user_password')
.insert({
id: id,
password: password,
})
.exec();
database.execute(query, (err, res) => {
if (err !== null) {
reject(err)
} else {
resolve(true);
}
})
})
}
}
module.exports = new UserPassword();
api/models/users.js dosyasını şöyle düzenleyelim:
const database = require('../../database');
const sm = require('sqlmaster');
const UserPassword = require('./userPassword');
class Users {
insert(user) {
var self = this;
var query = sm
.from('users')
.insert({
name: user.name,
email: user.email,
date: new Date(),
})
.returning('id')
.exec();
return new Promise((resolve, reject) => {
database.execute(query, (err, res) => {
if (err !== null) {
reject(err)
} else {
// üstte yazılan returning sayesinde insert edilince id gelmesini sağlıyor.
UserPassword.insert(res.rows[0].id, user.password).then(res => {
resolve(true);
}, reject);
}
})
})
}
...
Diğer controller'ların erişmesi için api/models/index.js dosyasına bir satır ekleyelim ve şöyle olsun:
exports.Users = require('./users');
exports.UserPassword = require('./userPassword');
Böylelikle kullanıcılar artık password değerini gönderdiğinde onu da kaydetmiş olacak. Bu haftaki bölüm bu kadardı diğer bölümde görüşmek üzere.
Düşündüklerin nedir ?