منشئ الاستعلامات
يوفر منشئ الاستعلامات واجهة مريحة وسلسة لإنشاء وتشغيل استعلامات قاعدة البيانات. يمكن استخدامه لتنفيذ معظم عمليات قاعدة البيانات في تطبيقك ويعمل بشكل مثالي مع جميع أنظمة قواعد البيانات المدعومة من Kawkab.
يسمح لك منشئ استعلامات Kawkab بكتابة وتنفيذ استعلامات SQL.
لقد قمنا بتقسيم منشئي الاستعلامات إلى الفئات التالية:
- منشئ الاستعلامات القياسي يسمح لك ببناء استعلامات SQL لعمليات التحديد والتحديث والحذف.
- منشئ استعلامات الإدراج يسمح لك ببناء استعلامات SQL لعمليات الإدراج.
- منشئ الاستعلامات الخام يتيح لك كتابة وتنفيذ الاستعلامات من سلسلة SQL خامة.
تشغيل استعلامات قاعدة البيانات
تشغيل استعلامات SQL
بمجرد تكوين اتصال قاعدة البيانات الخاصة بك، يمكنك استخدام طريقة raw
لتشغيل استعلام أساسي:
import { db } from "kawkab";
const response = await db.raw('SET TIME_ZONE = ?', ['UTC']);
سيكون الرد ما ستعيده مكتبة SQL الأساسية (مثل mysql2) عادةً في استعلام عادي، لذلك قد ترغب في الاطلاع على توثيق المكتبة الأساسية التي يتم تنفيذ الاستعلام عليها لتحديد كيفية التعامل مع الرد.
استرجاع جميع الصفوف من جدول
يمكنك استخدام طريقة table
المقدمة من DB لبدء استعلام. تعيد طريقة table
مثيل منشئ استعلام سلس للجدول المحدد، مما يتيح لك ربط المزيد من القيود على الاستعلام ثم استرجاع نتائج الاستعلام باستخدام طريقة get
:
import { db } from "kawkab";
const users = await db.table('users').get();
تعيد طريقة get
مصفوفة تحتوي على نتائج الاستعلام حيث يكون كل نتيجة كائن. يمكنك الوصول إلى قيمة كل عمود عن طريق الوصول إلى العمود كخاصية للكائن:
const users = await db.table('users').get();
users.map(user => {
console.log(user.name);
})
استرجاع صف أو عمود واحد من جدول
إذا كنت بحاجة فقط إلى استرجاع صف واحد من جدول قاعدة البيانات، يمكنك استخدام طريقة first
:
const user = await db.table('users').where('name', 'John').first();
console.log(user.email);
لاسترجاع صف واحد بواسطة قيمة عمود id
الخاصة به، استخدم طريقة find
:
const user = await db.table('users').find(3);
استرجاع قائمة بقيم الأعمدة
إذا كنت ترغب في استرجاع مصفوفة تحتوي على قيم عمود واحد، يمكنك استخدام طريقة pluck
. في هذا المثال، سنسترجع مجموعة من عناوين المستخدمين:
const titles = await db.table('users').pluck('title');
titles.map(title => {
console.log(title)
});
تقسيم النتائج
إذا كنت بحاجة إلى العمل مع آلاف من سجلات قاعدة البيانات، فكر في استخدام طريقة chunk
. تسترجع هذه الطريقة جزءًا صغيرًا من النتائج في كل مرة وتغذي كل جزء إلى إغلاق للمعالجة. على سبيل المثال، دعنا نسترجع جدول users
بالكامل في أجزاء من 100 سجل في كل مرة:
await db.table('users').orderBy('id').chunk(100, users => {
users.map(user => {
// افعل شيئًا...
})
});
يمكنك إيقاف معالجة الأجزاء الإضافية عن طريق إرجاع false
من الإغلاق:
await db.table('users').orderBy('id').chunk(100, users => {
// معالجة السجلات...
return false;
});
التجميعات
يوفر منشئ الاستعلامات أيضًا مجموعة متنوعة من الطرق لاسترجاع القيم المجمعة مثل العد، max
، min
، avg
، و sum
. يمكنك استدعاء أي من هذه الطرق بعد بناء استعلامك:
const count = await db.table('users').count();
const price = await db.table('orders').max('price');
بالطبع، يمكنك دمج هذه الطرق مع بنود أخرى لتعديل كيفية حساب قيمة التجميع الخاصة بك:
const price = await db.table('orders')
.where('finalized', 1)
.avg('price');
تحديد ما إذا كانت السجلات موجودة
بدلاً من استخدام طريقة count
لتحديد ما إذا كانت أي سجلات موجودة تطابق قيود استعلامك، يمكنك استخدام طرق exists
:
const isExists = await table('orders').where('finalized', 1).exists()
if (isExists) {
// ...
}
عبارات التحديد
تحديد بند التحديد
قد لا ترغب دائمًا في تحديد جميع الأعمدة من جدول قاعدة البيانات. باستخدام طريقة select
، يمكنك تحديد بند “select” مخصص للاستعلام:
const users = await db.table('users')
.select('name', 'email as user_email')
.get();
تسمح لك طريقة distinct
بإجبار الاستعلام على إعادة نتائج متميزة:
const users = await db.table('users').distinct().get();
التعبيرات الخام
في بعض الأحيان قد تحتاج إلى إدراج سلسلة اعتباطية في استعلام. لإنشاء تعبير سلسلة خام، يمكنك استخدام طريقة raw
:
const users = await db.table('users')
.select(db.raw('count(*) as user_count, status'))
.where('status', '<>', 1)
.groupBy('status')
.get();
الطرق الخام
بدلاً من استخدام طريقة raw
، يمكنك أيضًا استخدام الطرق التالية لإدراج تعبير خام في أجزاء مختلفة من استعلامك. لا يمكن لـ Kawkab ضمان أن أي استعلام يستخدم التعبيرات الخام محمي ضد ثغرات حقن SQL.
whereRaw
يمكن استخدام طرق whereRaw
لإدخال بند “where” خام في استعلامك. تقبل هذه الطرق مصفوفة اختيارية من الربط كوسيطة ثانية:
const orders = await db.table('orders')
.whereRaw('price > IF(state = "TX", ?, 100)', [200])
.get();
havingRaw
يمكن استخدام طرق havingRaw
و orHavingRaw
لتوفير سلسلة خام كقيمة لبند “having”. تقبل هذه الطرق مصفوفة اختيارية من الربط كوسيطة ثانية:
const orders = await db.table('orders')
.select('department', db.raw('SUM(price) as total_sales'))
.groupBy('department')
.havingRaw('SUM(price) > ?', [2500])
.get();
orderByRaw
يمكن استخدام طريقة orderByRaw
لتوفير سلسلة خام كقيمة لبند “order by”:
const orders = await db.table('orders')
.orderByRaw('updated_at - created_at DESC')
.get();
groupByRaw
يمكن استخدام طريقة groupByRaw
لتوفير سلسلة خام كقيمة لبند “group by”:
const orders = await db.table('orders')
.select('city', 'state')
.groupByRaw('city, state')
.get();
الانضمامات
بند الانضمام الداخلي
يمكن أيضًا استخدام منشئ الاستعلامات لإضافة بنود الانضمام إلى استعلاماتك. لتنفيذ “انضمام داخلي” أساسي، يمكنك استخدام طريقة join
على مثيل منشئ الاستعلام. يتم تمرير اسم الجدول الذي تحتاج إلى الانضمام إليه كوسيطة أولى لطريقة join
، بينما تحدد الوسائط المتبقية قيود الأعمدة للانضمام. يمكنك حتى الانضمام إلى جداول متعددة في استعلام واحد:
const users = await db.table('users')
.join('contacts', 'users.id', '=', 'contacts.user_id')
.join('orders', 'users.id', '=', 'orders.user_id')
.select('users.*', 'contacts.phone', 'orders.price')
.get();
بند الانضمام الأيسر / الأيمن
إذا كنت ترغب في تنفيذ “انضمام أيسر” أو “انضمام أيمن” بدلاً من “انضمام داخلي”، استخدم طرق leftJoin
أو rightJoin
. تحتوي هذه الطرق على نفس التوقيع مثل طريقة الانضمام:
const users = await db.table('users')
.leftJoin('posts', 'users.id', '=', 'posts.user_id')
.get();
const users = await db.table('users')
.rightJoin('posts', 'users.id', '=', 'posts.user_id')
.get();
بند الانضمام المتقاطع
يمكنك استخدام طريقة crossJoin
لتنفيذ “انضمام متقاطع”. تولد الانضمامات المتقاطعة منتجًا ديكارتيًا بين الجدول الأول والجدول المنضم:
const sizes = await db.table('sizes')
.crossJoin('colors')
.get();
بنود الانضمام المتقدمة
يمكنك أيضًا تحديد بنود انضمام أكثر تقدمًا. للبدء، مرر إغلاقًا كوسيطة ثانية لطريقة join
.
await db.table('users')
.join('contacts', () => {
this.on('users.id', '=', 'contacts.user_id').orOn(/* ... */);
})
.get();
الاتحادات
يوفر منشئ الاستعلامات أيضًا طريقة مريحة “لاتحاد” استعلامين أو أكثر معًا. على سبيل المثال، يمكنك إنشاء استعلام أولي واستخدام طريقة union
لاتحاده مع المزيد من الاستعلامات:
const first = db.table('users')
.whereNull('first_name');
const users = await db.table('users')
.whereNull('last_name')
.union(first)
.get();
بالإضافة إلى طريقة union
، يوفر منشئ الاستعلامات طريقة unionAll
. لن تحتوي الاستعلامات التي يتم دمجها باستخدام طريقة unionAll
على نتائجها المكررة التي تمت إزالتها. تحتوي طريقة unionAll
على نفس توقيع طريقة union
.
بنود “where” الأساسية
بنود “where”
يمكنك استخدام طريقة where
الخاصة بمنشئ الاستعلامات لإضافة بنود “where” إلى الاستعلام. يتطلب الاستدعاء الأكثر أساسية لطريقة where
ثلاث وسائط. الوسيطة الأولى هي اسم العمود. الوسيطة الثانية هي عامل التشغيل، والذي يمكن أن يكون أي من العوامل التي يدعمها قاعدة البيانات. الوسيطة الثالثة هي القيمة التي يتم مقارنتها بقيمة العمود.
على سبيل المثال، يسترجع الاستعلام التالي المستخدمين حيث تكون قيمة عمود votes
مساوية لـ 100
وقيمة عمود age
أكبر من 35
:
const users = await db.table('users')
.where('votes', '=', 100)
.where('age', '>', 35)
.get();
للتسهيل، إذا كنت ترغب في التحقق من أن العمود يساوي قيمة معينة، يمكنك تمرير القيمة كوسيطة ثانية لطريقة where
. سيفترض Kawkab أنك ترغب في استخدام عامل التشغيل =
:
const users = await db.table('users').where('votes', 100).get();
كما ذكرنا سابقًا، يمكنك استخدام أي عامل تشغيل يدعمه نظام قاعدة البيانات الخاص بك:
const users = await db.table('users')
.where('votes', '>=', 100)
.get();
const users = await db.table('users')
.where('votes', '<>', 100)
.get();
const users = await db.table('users')
.where('name', 'like', 'T%')
.get();
بنود “or Where”
عند ربط استدعاءات طريقة where
الخاصة بمنشئ الاستعلامات، سيتم ربط بنود “where” معًا باستخدام عامل التشغيل and
. ومع ذلك، يمكنك استخدام طريقة orWhere
لربط بند بالاستعلام باستخدام عامل التشغيل or
. تقبل طريقة orWhere
نفس الوسائط مثل طريقة where
:
const users = await db.table('users')
.where('votes', '>', 100)
.orWhere('name', 'John')
.get();
إذا كنت بحاجة إلى تجميع شرط “or” داخل أقواس، يمكنك تمرير إغلاق كوسيطة أولى لطريقة orWhere
:
const users = await db.table('users')
.where('votes', '>', 100)
.orWhere(query => {
query.where('name', 'Abigail')
.where('votes', '>', 50);
})
.get();
سينتج المثال أعلاه SQL التالي:
select * from users where votes > 100 or (name = 'Abigail' and votes > 50)
بنود “where Not”
يمكن استخدام طرق whereNot
و orWhereNot
لنفي مجموعة معينة من قيود الاستعلام. على سبيل المثال، يستثني الاستعلام التالي المنتجات التي هي في التخفيضات أو التي لديها سعر أقل من عشرة:
const products = await db.table('products')
.whereNot(() => {
this.where('clearance', true).orWhere('price', '<', 10);
})
.get();
بنود “where” الإضافية
whereBetween / orWhereBetween
تتحقق طريقة whereBetween
من أن قيمة العمود تقع بين قيمتين:
const users = await db.table('users')
.whereBetween('votes', [1, 100])
.get();
whereNotBetween / orWhereNotBetween
تتحقق طريقة whereNotBetween
من أن قيمة العمود تقع خارج قيمتين:
const users = await db.table('users')
.whereNotBetween('votes', [1, 100])
.get();
whereIn / whereNotIn / orWhereIn / orWhereNotIn
تتحقق طريقة whereIn
من أن قيمة العمود المعطاة موجودة داخل المصفوفة المعطاة:
const users = await db.table('users')
.whereIn('id', [1, 2, 3])
.get();
تتحقق طريقة whereNotIn
من أن قيمة العمود المعطاة ليست موجودة في المصفوفة المعطاة:
const users = await db.table('users')
.whereNotIn('id', [1, 2, 3])
.get();
whereNull / whereNotNull / orWhereNull / orWhereNotNull
تتحقق طريقة whereNull
من أن قيمة العمود المعطاة هي NULL:
const users = await db.table('users')
.whereNull('updated_at')
.get();
تتحقق طريقة whereNotNull
من أن قيمة العمود ليست NULL:
const users = await db.table('users')
.whereNotNull('updated_at')
.get();
WhereX
هناك طريقة أنيقة لتحويل هذا:
const users = await User.query().where('approved', 1).get();
const posts = await Post.query().where('views_count', '>', 100).get();
إلى هذا:
const users = await User.query().whereApproved(1).get();
const posts = await Post.query().whereViewsCount('>', 100).get();
التجميع المنطقي
في بعض الأحيان قد تحتاج إلى تجميع عدة بنود “where” داخل أقواس لتحقيق التجميع المنطقي المطلوب لاستعلامك. في الواقع، يجب عليك عمومًا دائمًا تجميع استدعاءات طريقة orWhere
داخل أقواس لتجنب سلوك الاستعلام غير المتوقع. لتحقيق ذلك، يمكنك تمرير إغلاق إلى طريقة where
:
const users = await db.table('users')
.where('name', '=', 'John')
.where(() => {
this.where('votes', '>', 100).orWhere('title', '=', 'Admin');
})
.get();
كما ترى، يوجه تمرير إغلاق إلى طريقة where
منشئ الاستعلام لبدء مجموعة قيود. سيتلقى الإغلاق مثيل منشئ استعلام يمكنك استخدامه لتعيين القيود التي يجب أن تكون موجودة داخل مجموعة الأقواس. سينتج المثال أعلاه SQL التالي:
select * from users where name = 'John' and (votes > 100 or title = 'Admin')
الترتيب، التجميع
الترتيب
طريقة orderBy
تسمح لك طريقة orderBy
بفرز نتائج الاستعلام حسب عمود معين. يجب أن تكون الوسيطة الأولى التي تقبلها طريقة orderBy
هي العمود الذي ترغب في الفرز حسبه، بينما تحدد الوسيطة الثانية اتجاه الفرز وقد تكون إما asc
أو desc
:
const users = await db.table('users')
.orderBy('name', 'desc')
.get();
للفرز حسب أعمدة متعددة، يمكنك ببساطة استدعاء orderBy
بقدر ما هو ضروري:
const users = await db.table('users')
.orderBy('name', 'desc')
.orderBy('email', 'asc')
.get();
طرق latest
و oldest
تسمح لك طرق latest
و oldest
بترتيب النتائج بسهولة حسب التاريخ. بشكل افتراضي، سيتم ترتيب النتيجة حسب عمود created_at
الخاص بالجدول. أو يمكنك تمرير اسم العمود الذي ترغب في الفرز حسبه:
const user = await db.table('users')
.latest()
.first();
الترتيب العشوائي
يمكن استخدام طريقة inRandomOrder
لفرز نتائج الاستعلام عشوائيًا. على سبيل المثال، يمكنك استخدام هذه الطريقة لجلب مستخدم عشوائي:
const randomUser = await db.table('users')
.inRandomOrder()
.first();
إزالة الترتيبات الموجودة
تزيل طريقة clearOrder
جميع بنود “order by” التي تم تطبيقها مسبقًا على الاستعلام:
const query = db.table('users').orderBy('name');
const unorderedUsers = await query.clearOrder().get();
التجميع
طرق groupBy
و having
كما قد تتوقع، يمكن استخدام طرق groupBy
و having
لتجميع نتائج الاستعلام. تشبه توقيع طريقة having
توقيع طريقة where
:
const users = await db.table('users')
.groupBy('account_id')
.having('account_id', '>', 100)
.get();
يمكنك استخدام طريقة havingBetween
لتصفية النتائج ضمن نطاق معين:
const report = await db.table('orders')
.selectRaw('count(id) as number_of_orders, customer_id')
.groupBy('customer_id')
.havingBetween('number_of_orders', [5, 15])
.get();
يمكنك تمرير وسائط متعددة إلى طريقة groupBy
للتجميع حسب أعمدة متعددة:
const users = await db.table('users')
.groupBy('first_name', 'status')
.having('account_id', '>', 100)
.get();
لبناء بنود “having” أكثر تقدمًا، راجع طريقة havingRaw
.
الحد والإزاحة
طرق skip
و take
يمكنك استخدام طرق skip
و take
لتحديد عدد النتائج التي يتم إرجاعها من الاستعلام أو لتخطي عدد معين من النتائج في الاستعلام:
const users = await db.table('users').skip(10).take(5).get();
بدلاً من ذلك، يمكنك استخدام طرق limit
و offset
. هذه الطرق مكافئة وظيفيًا لطرق take
و skip
، على التوالي:
const users = await db.table('users')
.offset(10)
.limit(5)
.get();
عبارات الإدراج
يوفر منشئ الاستعلامات أيضًا طريقة insert
التي يمكن استخدامها لإدراج سجلات في جدول قاعدة البيانات. تقبل طريقة insert
مصفوفة من أسماء الأعمدة والقيم:
await db.table('users').insert({
email: 'kayla@example.com',
votes: 0
});
يمكنك إدراج عدة سجلات دفعة واحدة عن طريق تمرير مصفوفة من المصفوفات. تمثل كل مصفوفة سجلًا يجب إدراجه في الجدول:
await db.table('users').insert([
{ email: 'picard@example.com', votes: 0 },
{ email: 'janeway@example.com', votes: 0 },
]);
عبارات التحديث
بالإضافة إلى إدراج السجلات في قاعدة البيانات، يمكن لمنشئ الاستعلامات أيضًا تحديث السجلات الموجودة باستخدام طريقة update
. تقبل طريقة update
، مثل طريقة insert
، مصفوفة من أزواج الأعمدة والقيم التي تشير إلى الأعمدة التي يجب تحديثها. تعيد طريقة update
عدد الصفوف المتأثرة. يمكنك تقييد استعلام التحديث باستخدام بنود where:
await db.table('users')
.where('id', 1)
.update({
votes: 1
});
الزيادة والنقصان
يوفر منشئ الاستعلامات أيضًا طرقًا مريحة لزيادة أو نقصان قيمة عمود معين. تقبل كل من هاتين الطريقتين وسائط واحدة على الأقل: العمود الذي يجب تعديله. يمكن توفير وسيطة ثانية لتحديد المقدار الذي يجب زيادة أو نقصان العمود به:
await db.table('users').increment('votes');
await db.table('users').increment('votes', 5);
await db.table('users').decrement('votes');
await db.table('users').decrement('votes', 5);
عبارات الحذف
يمكن استخدام طريقة delete
الخاصة بمنشئ الاستعلامات لحذف السجلات من الجدول. تعيد طريقة delete
عدد الصفوف المتأثرة. يمكنك تقييد عبارات الحذف عن طريق إضافة بنود “where” قبل استدعاء طريقة delete
:
const deleted = await db.table('users').delete();
const deleted = await db.table('users').where('votes', '>', 100).delete();
القفل المتشائم
يتضمن منشئ الاستعلامات أيضًا بعض الوظائف لمساعدتك في تحقيق “القفل المتشائم” عند تنفيذ عبارات select
الخاصة بك. لتنفيذ عبارة باستخدام “قفل مشترك”، يمكنك استدعاء طريقة forShare
. يمنع القفل المشترك تعديل الصفوف المحددة حتى يتم تأكيد معاملتك:
await db.table('users')
.where('votes', '>', 100)
.forShare()
.get();
بدلاً من ذلك، يمكنك استخدام طريقة forUpdate
. يمنع قفل “للتحديث” تعديل السجلات المحددة أو اختيارها باستخدام قفل مشترك آخر:
await db.table('users')
.where('votes', '>', 100)
.forUpdate()
.get();