İlk Veritabanını Oluşturma
Ders 3: İlk Veritabanını Oluşturma
Section titled “Ders 3: İlk Veritabanını Oluşturma”Öğrenme Hedefleri
Section titled “Öğrenme Hedefleri”Bu dersi tamamladıktan sonra:
- D1’de ilk veritabanınızı oluşturabileceksiniz
- Tablo oluşturma ve schema tasarımı yapabileceksiniz
- Veri ekleme ve temel CRUD işlemlerini yapabileceksiniz
- Wrangler ile D1 yönetimini öğreneceksiniz
İçerik İçindekiler
Section titled “İçerik İçindekiler”- Proje Kurulumu
- Veritabanı Oluşturma
- Tablo Tasarımı ve Oluşturma
- Veri Ekleme
- Temel Sorgular
- Pratik Proje
Proje Kurulumu
Section titled “Proje Kurulumu”1. Workers Projesi Oluşturma
Section titled “1. Workers Projesi Oluşturma”İlk olarak, yeni bir Workers projesi oluşturalım:
# Yeni proje oluşturnpm create cloudflare@latest my-d1-app
# Proje dizinine gitcd my-d1-app
# Bağımlılıkları yüklenpm installProje oluşturma sırasında size birkaç soru sorulacak:
- Project type: “Hello World” Worker seçin
- TypeScript: Evet seçin (önerilir)
- Deploy: Hayır seçin (önce yerel test edeceğiz)
2. Wrangler Yapılandırması
Section titled “2. Wrangler Yapılandırması”wrangler.toml dosyası oluşturulacak. Bu dosya projenizin yapılandırmasını içerir:
name = "my-d1-app"main = "src/index.ts"compatibility_date = "2024-01-01"Veritabanı Oluşturma
Section titled “Veritabanı Oluşturma”1. D1 Veritabanı Oluşturma
Section titled “1. D1 Veritabanı Oluşturma”Yeni bir D1 veritabanı oluşturalım:
npx wrangler d1 create users-dbÇıktı:
✅ Successfully created DB 'users-db' in region WEURCreated your new D1 database.
[[d1_databases]]binding = "DB" # i.e. available in your Worker on env.DBdatabase_name = "users-db"database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"2. Wrangler’a Database Binding Ekleme
Section titled “2. Wrangler’a Database Binding Ekleme”wrangler.toml dosyasına D1 binding ekleyelim:
name = "my-d1-app"main = "src/index.ts"compatibility_date = "2024-01-01"
[[d1_databases]]binding = "DB"database_name = "users-db"database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"Binding Nedir?
Binding, Worker kodunuzda D1 veritabanına erişmek için kullandığınız bir referanstır. env.DB ile erişebilirsiniz.
Tablo Tasarımı ve Oluşturma
Section titled “Tablo Tasarımı ve Oluşturma”1. Schema Tasarımı
Section titled “1. Schema Tasarımı”Basit bir kullanıcı yönetim sistemi için şu tabloları oluşturalım:
users Tablosu
Section titled “users Tablosu”CREATE TABLE users ( id INTEGER PRIMARY KEY AUTOINCREMENT, email TEXT NOT NULL UNIQUE, username TEXT NOT NULL UNIQUE, first_name TEXT, last_name TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP);posts Tablosu
Section titled “posts Tablosu”CREATE TABLE posts ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, title TEXT NOT NULL, content TEXT, published BOOLEAN DEFAULT 0, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users(id));2. Schema Dosyası Oluşturma
Section titled “2. Schema Dosyası Oluşturma”Projenizde schema klasörü oluşturalım ve schema SQL dosyamızı ekleyelim:
mkdir schemaschema/001_initial.sql dosyası oluşturalım:
-- schema/001_initial.sql
-- Users tablosuDROP TABLE IF EXISTS users;CREATE TABLE users ( id INTEGER PRIMARY KEY AUTOINCREMENT, email TEXT NOT NULL UNIQUE, username TEXT NOT NULL UNIQUE, first_name TEXT, last_name TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP);
-- Posts tablosuDROP TABLE IF EXISTS posts;CREATE TABLE posts ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, title TEXT NOT NULL, content TEXT, published BOOLEAN DEFAULT 0, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users(id));
-- IndexlerCREATE INDEX idx_users_email ON users(email);CREATE INDEX idx_users_username ON users(username);CREATE INDEX idx_posts_user_id ON posts(user_id);3. Schema’yı Uygulama
Section titled “3. Schema’yı Uygulama”Schema’yı local ve remote D1 veritabanına uygulayalım:
# Local veritabanına uygulanpx wrangler d1 execute users-db --local --file=./schema/001_initial.sql
# Remote (production) veritabanına uygulanpx wrangler d1 execute users-db --remote --file=./schema/001_initial.sqlVeri Ekleme
Section titled “Veri Ekleme”1. Manuel Veri Ekleme
Section titled “1. Manuel Veri Ekleme”Komut satırından veri ekleyelim:
# Users tablosuna veri eklenpx wrangler d1 execute users-db --local --command \ "INSERT INTO users (email, username, first_name, last_name) VALUES \
# Posts tablosuna veri eklenpx wrangler d1 execute users-db --local --command \ "INSERT INTO posts (user_id, title, content, published) VALUES \ (1, 'İlk Blog Yazım', 'Merhaba dünya! Bu ilk blog yazım.', 1), \ (2, 'TypeScript Tips', 'TypeScript kullanmanın avantajları...', 1), \ (1, 'Cloudflare Workers', 'Workers ile serverless development...', 0)"2. Veri Dosyasından İçe Aktarma
Section titled “2. Veri Dosyasından İçe Aktarma”data/seed.sql dosyası oluşturalım:
-- data/seed.sql
INSERT INTO users (email, username, first_name, last_name) VALUES
INSERT INTO posts (user_id, title, content, published) VALUES (1, 'İlk Blog Yazım', 'Merhaba dünya! Bu ilk blog yazım.', 1), (2, 'TypeScript Tips', 'TypeScript kullanmanın avantajları...', 1), (1, 'Cloudflare Workers', 'Workers ile serverless development...', 0), (3, 'React Hooks', 'React Hooks kullanımı hakkında her şey...', 1), (2, 'CSS Grid', 'CSS Grid ile modern layoutlar...', 1);Verileri içe aktaralım:
npx wrangler d1 execute users-db --local --file=./data/seed.sqlTemel Sorgular
Section titled “Temel Sorgular”1. SELECT - Veri Okuma
Section titled “1. SELECT - Veri Okuma”# Tüm kullanıcıları getirnpx wrangler d1 execute users-db --local --command "SELECT * FROM users"
# Sadece email ve username getirnpx wrangler d1 execute users-db --local --command \ "SELECT email, username FROM users"
# Belirli bir koşula göre filtrelenpx wrangler d1 execute users-db --local --command \ "SELECT * FROM users WHERE username = 'ahmet'"
# Sıralamanpx wrangler d1 execute users-db --local --command \ "SELECT * FROM users ORDER BY created_at DESC"
# Limit ve Offsetnpx wrangler d1 execute users-db --local --command \ "SELECT * FROM users LIMIT 5 OFFSET 2"2. JOIN - Tablo Birleştirme
Section titled “2. JOIN - Tablo Birleştirme”# Users ve Posts tablolarını birleştirnpx wrangler d1 execute users-db --local --command \ "SELECT users.username, posts.title FROM posts JOIN users ON posts.user_id = users.id"
# LEFT JOINnpx wrangler d1 execute users-db --local --command \ "SELECT users.username, COUNT(posts.id) as post_count FROM users LEFT JOIN posts ON users.id = posts.user_id GROUP BY users.id"3. UPDATE - Veri Güncelleme
Section titled “3. UPDATE - Veri Güncelleme”# Bir kullanıcıyı güncellenpx wrangler d1 execute users-db --local --command \ "UPDATE users SET first_name = 'Ahmet Can' WHERE username = 'ahmet'"
# Birden fazla alanı güncellenpx wrangler d1 execute users-db --local --command \ "UPDATE posts SET published = 1, updated_at = CURRENT_TIMESTAMP WHERE id = 3"4. DELETE - Veri Silme
Section titled “4. DELETE - Veri Silme”# Bir post'u silnpx wrangler d1 execute users-db --local --command \ "DELETE FROM posts WHERE id = 4"
# Belirli bir koşula göre silnpx wrangler d1 execute users-db --local --command \ "DELETE FROM posts WHERE published = 0"Pratik Proje
Section titled “Pratik Proje”Worker ile D1 Kullanımı
Section titled “Worker ile D1 Kullanımı”src/index.ts dosyasını oluşturalım:
export interface Env { DB: D1Database;}
export default { async fetch(request: Request, env: Env, ctx: ExecutionContext) { const url = new URL(request.url); const path = url.pathname;
// Tüm kullanıcıları listele if (path === "/users") { const { results } = await env.DB.prepare( "SELECT * FROM users ORDER BY created_at DESC" ).all();
return Response.json(results); }
// Belirli bir kullanıcıyı getir if (path.startsWith("/users/")) { const username = path.split("/")[2]; const { results } = await env.DB.prepare( "SELECT * FROM users WHERE username = ?" ) .bind(username) .all();
if (results.length === 0) { return Response.json({ error: "User not found" }, { status: 404 }); }
return Response.json(results[0]); }
// Yeni kullanıcı oluştur if (path === "/users" && request.method === "POST") { const body = await request.json();
const result = await env.DB.prepare( "INSERT INTO users (email, username, first_name, last_name) VALUES (?, ?, ?, ?)" ) .bind(body.email, body.username, body.first_name, body.last_name) .run();
return Response.json({ success: result.success, id: result.meta.last_row_id }, { status: 201 }); }
// Tüm post'ları listele if (path === "/posts") { const { results } = await env.DB.prepare(` SELECT posts.*, users.username FROM posts JOIN users ON posts.user_id = users.id ORDER BY posts.created_at DESC `).all();
return Response.json(results); }
return Response.json({ message: "D1 API", endpoints: ["/users", "/users/:username", "/posts"] }); },};Local Test
Section titled “Local Test”# Local development server'ı başlatnpm run dev
# Başka bir terminal'de test etcurl http://localhost:8787/userscurl http://localhost:8787/users/ahmetcurl http://localhost:8787/posts
# POST isteğicurl -X POST http://localhost:8787/users \ -H "Content-Type: application/json" \İyi Pratikler
Section titled “İyi Pratikler”1. Schema Yönetimi
Section titled “1. Schema Yönetimi”- ✅ Migration dosyalarını versiyon kontrolüne alın
- ✅ Her değişikliği ayrı bir migration dosyasında tutun
- ✅ Local ve remote’da aynı schema’yı kullanın
2. Index Kullanımı
Section titled “2. Index Kullanımı”- ✅ Sık sorgulanan sütunlara index ekleyin
- ✅ Foreign key’lere index ekleyin
- ❌ Gereksiz indexlerden kaçının (write performance etkiler)
3. Veri Tipleri
Section titled “3. Veri Tipleri”- ✅ Uygun veri tiplerini kullanın (TEXT, INTEGER, REAL)
- ✅ NULL constraints kullanın
- ✅ UNIQUE constraints ile veri bütünlüğünü sağlayın
4. Security
Section titled “4. Security”- ❌ Asla SQL injection’e açık kod yazmayın
- ✅ Her zaman prepared statements kullanın
- ✅ Param binding kullanın
Bu derste aşağıdaki konuları öğrendiniz:
✅ Workers projesi kurulumu ✅ D1 veritabanı oluşturma ✅ Tablo tasarımı ve schema oluşturma ✅ Veri ekleme ve temel CRUD işlemleri ✅ Worker ile D1 entegrasyonu ✅ Local development ve test
Sonraki Ders
Section titled “Sonraki Ders”Bir sonraki dersimizde “Temel SQL Komutları” başlığı altında:
- Detaylı SELECT sorguları
- JOIN çeşitleri ve kullanımı
- Aggregation fonksiyonları
- Subquery’ler konularını inceleyeceğiz.
Kaynaklar
Section titled “Kaynaklar”Alıştırma Soruları
Section titled “Alıştırma Soruları”- D1 binding nedir ve neden kullanılır?
- Schema tasarımı yaparken nelere dikkat etmelisiniz?
- Foreign key constraint nedir ve nasıl kullanılır?
- Local ve remote veritabanı arasındaki fark nedir?
- Worker kodunda D1’e nasıl erişirsiniz?
Ders Süresi: 60 dakika Zorluk Seviyesi: Başlangıç Ön Koşullar: Ders 2: D1’e Giriş