المحولات والتحويل

تسمح لك المحولات والوصولات بتحويل قيم سمات Sutando عند استرجاعها أو تعيينها على مثيلات النموذج.

الوصولات والمحولات

تعريف الوصول

لتعريف الوصول، قم بإنشاء طريقة مسماة بصيغة camelCase attribute{Attribute} في النموذج لتمثيل السمة القابلة للوصول. يتوافق اسم هذه الطريقة مع تمثيل السمة الحقيقية للنموذج/حقل قاعدة البيانات.

في هذا المثال، سنقوم بتعريف وصول للسمة first_name. سيتم استدعاء الوصول تلقائيًا بواسطة Sutando عند محاولة استرجاع قيمة السمة first_name:

import { BaseModel, AttributeModel } from "kawkab";
 
class User extends Model {
  attributeFirstName() {
    return AttributeModel.make({
      get: value => value.toUpperCase()
    })
  }
}

تُعيد جميع طرق الوصول مثيل Attribute الذي يحدد كيفية الوصول إلى السمة وكيفية تغيير السمة. في هذا المثال، نقوم فقط بتعريف كيفية الوصول إلى الخاصية. للقيام بذلك، نقدم المعامل get إلى منشئ فئة Attribute.

كما ترى، يتم تمرير القيمة الأصلية للعمود إلى الوصول، مما يسمح لك بالتلاعب بالقيمة وإعادتها. للوصول إلى قيمة الوصول، يمكنك ببساطة الوصول إلى السمة first_name على مثيل النموذج:

const user = await User.query().find(1);
 
const firstName = user.first_name;

:::tip إذا كنت ترغب في إضافة هذه القيم المحسوبة إلى تمثيلات الكائن / JSON لنموذجك، ستحتاج إلى إضافتها. :::

في بعض الأحيان قد تحتاج وصولك إلى تحويل سمات نموذج متعددة إلى “كائن قيمة” واحد. للقيام بذلك، يمكن لوصولك قبول معامل ثاني attributes، الذي سيتم تزويده تلقائيًا إلى الوصول وسيحتوي على كائن يحتوي على جميع سمات النموذج الحالية:

attributeFullName() {
  return AttributeModel.make({
    get: (value, attributes) => `${attributes.first_name} ${attributes.last_name}`
  })
}

تعريف المحول

لتعريف المحول، يمكنك تقديم المعامل set عند تعريف السمة الخاصة بك. دعونا نعرف محولًا للسمة first_name. سيتم استدعاء هذا المحول تلقائيًا عندما نحاول تعيين قيمة السمة first_name على النموذج:

import { BaseModel, AttributeModel } from "kawkab";
 
class User extends Model {
  attributeFirstName() {
    return AttributeModel.make({
      get: value => value.toUpperCase(),
      set: value => value.toLocalLowerCase()
    })
  }
}

سيستقبل المحول القيمة التي يتم تعيينها على السمة، مما يسمح لك بالتلاعب بالقيمة وتعيين القيمة المعدلة على خاصية attributes الداخلية لنموذج Sutando. لاستخدام محولنا، نحتاج فقط إلى تعيين السمة first_name على نموذج Sutando:

const user = User.query().find(1);
 
user.first_name = 'Sally';

في هذا المثال، سيتم استدعاء رد الاتصال set بالقيمة Sally. ثم سيقوم المحول بتطبيق وظيفة toLocalLowerCase على الاسم وتعيين قيمته الناتجة في attributes الداخلية للنموذج.

تحويل سمات متعددة

في بعض الأحيان قد يحتاج محولك إلى تعيين سمات متعددة على النموذج الأساسي. للقيام بذلك، يمكنك إرجاع كائن من رد الاتصال set. يجب أن يتوافق كل مفتاح في الكائن مع سمة أساسية / عمود قاعدة بيانات مرتبط بالنموذج:

attributeFullName() {
  return AttributeModel.make({
    get: (value, attributes) => `${attributes.first_name} ${attributes.last_name}`,
    set: (value) => ({
      first_name: value.split(' ')[0],
      last_name: value.split(' ')[1],
    }),
  });
}

تحويل السمات

يوفر تحويل السمات وظيفة مشابهة للوصولات والمحولين دون الحاجة إلى تعريف أي طرق إضافية على النموذج الخاص بك. بدلاً من ذلك، توفر خاصية casts للنموذج طريقة مريحة لتحويل السمات إلى أنواع بيانات شائعة.

يجب أن تكون خاصية casts كائنًا حيث يكون المفتاح هو اسم السمة التي يتم تحويلها والقيمة هي النوع الذي ترغب في تحويل العمود إليه. الأنواع المدعومة للتحويل هي:

  • integer int
  • float double
  • string
  • boolean bool
  • collection
  • date
  • datetime
  • json object

لإظهار تحويل السمات، دعونا نحول السمة is_admin، التي يتم تخزينها في قاعدة البيانات كعدد صحيح (0 أو 1) إلى قيمة منطقية:

import { BaseModel } from "kawkab";
 
class User extends Model {
  // السمات التي يجب تحويلها.
  casts = {
    is_admin: 'boolean',
  };
}

بعد تعريف التحويل، سيتم دائمًا تحويل السمة is_admin إلى منطقية عند الوصول إليها، حتى إذا تم تخزين القيمة الأساسية في قاعدة البيانات كعدد صحيح:

const user = await User.query().find(1);
 
if (user.is_admin) {
  // ...
}

:::tip يجب ألا تعرف أبدًا تحويلًا (أو سمة) تحمل نفس اسم العلاقة أو تعيين تحويل للمفتاح الأساسي للنموذج. :::

تحويل JSON

يعتبر تحويل json مفيدًا بشكل خاص عند العمل مع الأعمدة التي يتم تخزينها كسلسلة JSON. على سبيل المثال، إذا كانت قاعدة البيانات الخاصة بك تحتوي على نوع حقل JSON أو TEXT يحتوي على JSON مسلسل، فإن إضافة تحويل json إلى تلك السمة سيقوم تلقائيًا بإلغاء تسلسل السمة عند الوصول إليها على النموذج الخاص بك:

import { BaseModel } from "kawkab";
 
class User extends Model {
    // السمات التي يجب تحويلها.
    casts = {
      options: 'json',
    };
}

بمجرد تعريف التحويل، يمكنك الوصول إلى السمة options وسيتم تلقائيًا إلغاء تسلسلها من JSON إلى كائن. عند تعيين قيمة السمة options، سيتم تلقائيًا تسلسل الكائن المعطى مرة أخرى إلى JSON للتخزين:

import { BaseModel } from "kawkab";
 
const user = await User.query().find(1);
 
const options = user.options;
 
options.key = value;
 
user.options = options;
 
await user.save();

:::tip لا يمكن لتعديل السمات نفسها مباشرةً تحديث بيانات النموذج، لذلك فإن الاستخدام التالي غير صحيح:

const user = await User.query().find(1);
 
user.options.key = value;

:::

تحويل التاريخ

بشكل افتراضي، سيقوم Sutando بتحويل أعمدة created_at و updated_at إلى مثيلات Date. يمكنك تحويل سمات تاريخ إضافية عن طريق تعريف تحويلات تاريخ إضافية داخل خاصية casts الخاصة بالنموذج الخاص بك. عادةً ما يجب تحويل التواريخ باستخدام أنواع تحويل datetime.

عند تعريف تحويل date أو datetime، يمكنك أيضًا تحديد تنسيق التاريخ. سيتم استخدام هذا التنسيق عند تسلسل النموذج إلى كائن أو JSON:

casts = {
  created_at: 'datetime:YYYY-MM-DD',
};

يمكنك تخصيص تنسيق التسلسل الافتراضي لجميع تواريخ النموذج الخاص بك عن طريق تعريف طريقة serializeDate على النموذج الخاص بك. لا تؤثر هذه الطريقة على كيفية تنسيق تواريخك للتخزين في قاعدة البيانات:

const dayjs = require('dayjs');
 
class User extends Model {
  serializeDate(date) {
    return dayjs(date).format('YYYY-MM-DD');
  }
}

لتحديد التنسيق الذي يجب استخدامه عند تخزين تواريخ النموذج فعليًا داخل قاعدة البيانات الخاصة بك، يجب عليك تعريف خاصية dateFormat على النموذج الخاص بك:

class User extends Model {
  dateFormat = 'X'
}

قائمة بجميع التنسيقات المتاحة

التنسيقالناتجالوصف
YY18السنة برقمين
YYYY2018السنة بأربعة أرقام
M1-12الشهر، يبدأ من 1
MM01-12الشهر، برقمين
MMMJan-Decاسم الشهر المختصر
MMMMJanuary-Decemberاسم الشهر الكامل
D1-31يوم الشهر
DD01-31يوم الشهر، برقمين
d0-6يوم الأسبوع، الأحد كـ 0
ddSu-Saاسم اليوم المختصر
dddSun-Satاسم اليوم القصير
ddddSunday-Saturdayاسم اليوم الكامل
H0-23الساعة
HH00-23الساعة، برقمين
h1-12الساعة، 12 ساعة
hh01-12الساعة، 12 ساعة، برقمين
m0-59الدقيقة
mm00-59الدقيقة، برقمين
s0-59الثانية
ss00-59الثانية، برقمين
SSS000-999المللي ثانية، برقمين
Z+05:00الفرق عن توقيت جرينتش، ±HH:mm
ZZ+0500الفرق عن توقيت جرينتش، ±HHmm
AAM PM
aam pm
Q1-4الربع
Do1st 2nd … 31stيوم الشهر مع الترتيب
k1-24الساعة، يبدأ من 1
kk01-24الساعة، برقمين، يبدأ من 1
X1360013296الطابع الزمني Unix بالثواني
x1360013296123الطابع الزمني Unix بالمللي ثانية

تحويل التاريخ، التسلسل، والمناطق الزمنية

بشكل افتراضي، ستقوم تحويلات date و datetime بتسلسل التواريخ إلى سلسلة تاريخ ISO-8601 UTC (2012-12-12T12:25:36.000000Z)، بغض النظر عن المنطقة الزمنية المحددة في خيار تكوين المنطقة الزمنية لتطبيقك.

إذا تم تطبيق تنسيق مخصص على تحويل date أو datetime، مثل datetime:YYYYY-MM-DD HH:mm:ss، سيتم استخدام المنطقة الزمنية UTC أثناء تسلسل التاريخ.

التحويلات المخصصة

لدى Sutando مجموعة متنوعة من أنواع التحويل المدمجة والمفيدة؛ ومع ذلك، قد تحتاج أحيانًا إلى تعريف أنواع التحويل الخاصة بك. جميع فئات التحويل المخصصة تمتد CastsAttributes. يجب على الفئات التي تنفذ هذه الواجهة تعريف طريقة get و set. تكون طريقة get مسؤولة عن تحويل قيمة خام من قاعدة البيانات إلى قيمة تحويل، بينما يجب أن تحول طريقة set قيمة التحويل إلى قيمة خام يمكن تخزينها في قاعدة البيانات. كمثال، سنعيد تنفيذ نوع التحويل المدمج json كنوع تحويل مخصص:

// casts/json.js
const { Model, CastsAttributes } from "kawkab";
 
class Json extends CastsModel {
  // تحويل القيمة المعطاة.
  static get(model, key, value, attributes) {
    try {
      return JSON.parse(value);
    } catch (e) {
      return null;
    }
  }
 
  // تحضير القيمة المعطاة للتخزين.
  static set(model, key, value, attributes) {
    return JSON.stringify(value);
  }
}

بمجرد تعريف نوع تحويل مخصص، يمكنك إرفاقه بسمة نموذج باستخدام فئته:

const Json = require('./casts/json');
 
class User extends Model {
  // السمات التي يجب تحويلها.
  casts = {
    options: Json,
  };
}