1. ماڈل اور فیلڈ بنیادیات

1.1. ماڈل تعریف کی تعارف

ORM فریم ورک میں، ماڈل کو استعمال کیا جاتا ہے تاکہ اطلاقی کو اینٹٹی ٹائپس کے درمیان تعلقات اور ڈیٹا بیس کے ٹیبلز کے درمیان میپنگ رشتے کی تشریح کر سکے۔ ماڈل اینٹٹی کی خصوصیات اور تعلقات، اور ان کے ساتھ منسلک ڈیٹا بیس اختیارات کی تعریف کرتا ہے۔ ent فریم ورک میں، ماڈلز عام طور پر ہمیں گراف میں اینٹٹی ٹائپس جیسے User یا Group کی تشریح کرنے کے لئے استعمال ہوتے ہیں۔

ماڈل کی تعارف عموماً اینٹٹٹی کے فیلڈز (یا خصوصیات) اور ایجز (یا تعلقات)، اور کچھ ڈیٹا بیس سپیسفک ترتیبات کی تشریح شامل ہوتی ہے۔ یہ تشریحات ہمیں اینٹٹی کی ساخت، خصوصیات، اور تعلقات کا تعریف کرنے میں مدد فراہم کرتی ہیں، اور ماڈل کے بنیاد پر متعلقہ ڈیٹا بیس ٹیبل ساخت کرنے کے لئے استعمال کی جاسکتی ہیں۔

1.2. فیلڈ کا جائزہ

فیلڈز وہ حصہ ہیں جو اینٹٹٹی کی خصوصیات کو ظاہر کرتے ہیں۔ یہ اینٹٹٹی کی خصوصیات کی تشریح کرتے ہیں، مثلاً نام، عمر، تاریخ، وغیرہ۔ ent فریم ورک میں، فیلڈ کے ٹائپس میں مختلف بنیادی ڈیٹا ٹائپس شامل ہیں، مثلاً integer، string، boolean، time، وغیرہ، اور کچھ SQL خصوصی ٹائپس جیسے UUID، []byte، JSON، وغیرہ شامل ہیں۔

نیچے دی گئی جدول میں، ent فریم ورک کے سپورٹ کردہ فیلڈ ٹائپس دکھایا گیا ہے:

ٹائپ تفصیل
int عددی ٹائپ
uint8 غیر منفی 8 بٹ عددی ٹائپ
float64 فلوٹنگ پوائنٹ ٹائپ
bool بولیئن ٹائپ
string اسٹرنگ ٹائپ
time.Time ٹائم ٹائپ
UUID یونیورسل یونیک ایڈنٹفائیر ٹائپ
[]byte بازوں کا ایرے ٹائپ (صرف SQL)
JSON JSON ٹائپ (صرف SQL)
Enum اینم ٹائپ (صرف SQL)
دوسرے دیگر ٹائپس (مثلاً پوسٹگریس رینج)

2. فیلڈ خصوصیت کی تفصیلات

2.1. ڈیٹا ٹائپس

ینٹٹی ماڈل میں ایک آٹریبیوٹ یا فیلڈ کا ڈیٹا ٹائپ وہ شکل تعین کرتا ہے جس میں ڈیٹا ذخیرہ کیا جا سکتا ہے۔ اسے ent فریم ورک میں ماڈل کی تعریف کا اہم حصہ تصور کیا جاتا ہے۔ نیچے دیے گئے کچھ عام ڈیٹا ٹائپس ہیں جو ent فریم ورک میں استعمال ہوتے ہیں۔

import (
    "time"

    "entgo.io/ent"
    "entgo.io/ent/schema/field"
)

// یوزر اسکیما۔
type User struct {
    ent.Schema
}

// یوزر کے فیلڈز۔
func (User) Fields() []ent.Field {
    return []ent.Field{
        field.Int("age"),             // عددی ٹائپ
        field.String("name"),         // اسٹرنگ ٹائپ
        field.Bool("active"),         // بولیئن ٹائپ
        field.Float("score"),         // فلوٹنگ پوائنٹ ٹائپ
        field.Time("created_at"),     // ٹائم اسٹیمپ ٹائپ
    }
}
  • int: عددی قیمتوں کو ظاہر کرتا ہے، جو int8، int16، int32، int64 وغیرہ ہوسکتے ہیں۔
  • string: اسٹرنگ ڈیٹا کو ظاہر کرتا ہے۔
  • bool: بولیئن قیمتوں کو ظاہر کرتا ہے، عموماً پرچمز کے طور پر استعمال ہوتا ہے۔
  • float64: فلوٹنگ پوائنٹ نمبرز کو ظاہر کرتا ہے، float32 بھی استعمال کیا جا سکتا ہے۔
  • time.Time: وقت کو ظاہر کرتا ہے، عموماً اسٹیمپس یا تاریخی ڈیٹا کے لئے استعمال ہوتا ہے۔

یہ فیلڈ ٹائپز میپنگ کے لئے استعمال ہوں گے، علاوہ ازیں، ent مختلف پیچیدہ ٹائپس جیسے کہ UUID، JSON، enums (اِنم)، اور خصوصی ڈیٹا بیس ٹائپس جیسے []byte (صرف SQL) اور دیگر (صرف SQL) کا سپورٹ بھی فراہم کرتا ہے۔

2.2. ڈیفالٹ قیمتیں

فیلڈز کو ڈیفالٹ قیمتوں کے ساتھ تشکیل دی جا سکتی ہیں۔ اگر اینٹٹی کو تخلیق کرتے وقت متناظر قیمت ذکر نہیں کی گئی ہو تو ڈیفالٹ قیمت کا استعمال ہوگا۔ ڈیفالٹ قیمت ایک مضبوط قیمت یا ایک تناسبی ترتیب سے حاصل کردہ قیمت میں سے ہوسکتی ہے۔ ایک سٹیٹک ڈیفالٹ قیمت تعین کرنے کے لئے .Default میتھاڈ کا استعمال کیا جاتا ہے، یا سبقت سے پیدا ہونے والی ڈیفالٹ قیمت تشکیل دینے کے لئے .DefaultFunc کا استعمال کیا جاتا ہے۔

// یوزر اسکیما۔
func (User) Fields() []ent.Field {
    return []ent.Field{
        field.Time("created_at").
            Default(time.Now),  // `time.Now` کی مضبوط ڈیفالٹ قیمت
        field.String("role").
            Default("user"),   // ایک مستقل اسٹرنگ قیمت
        field.Float("score").
            DefaultFunc(func() float64 {
                return 10.0  // ایک تفصیلی قیمت جو ایک فنکشن کے ذریعے تشکیل دی گئی ہے
            }),
    }
}

2.3. فیلڈ کی اختیاری پن اور صفر قیمتیاں

پہلے ہی طور پر، فیلڈز ضروری ہوتے ہیں۔ اختیاری فیلڈ کا اعلان کرنے کے لئے .Optional() میتھڈ کا استعمال کریں۔ اختیاری فیلڈز ڈیٹا بیس میں قابل مستراح فیلڈز کے طور پر اعلان ہوں گے۔ Nillable اختیار فیلڈ کو صرف nil پر تعینات کرنے دیتا ہے، جو فرق کرتا ہے ایک فیلڈ کی صفر قیمت اور غیر تعینات حالت کے درمیان۔

// یوزر سکیما۔
func (User) Fields() []ent.Field {
    return []ent.Field{
        field.String("nickname").Optional(), // اختیاری فیلڈ ضروری نہیں ہے
        field.Int("age").Optional().Nillable(), // Nillable فیلڈ کو nil پر تعین  ممکن بناتا ہے
    }
}

یوزر سکیما کا موجودہ ماڈل استعمال کرتے وقت، age فیلڈ صفر قیمتوں کے علاوہ nil قیمتیں بھی قبول کر سکتا ہے۔

2.4. فیلڈ یکتائی

یکتائی والے فیلڈز یہ یقینی بناتے ہیں کہ ڈیٹا بیس میں کوئی دوہری قیمتیں نہیں ہیں۔ یکتائی فیلڈ کا اعلان کرنے کے لئے Unique() میتھڈ کا استعمال کریں۔ جب ڈیٹا کی عظمت ایک اہم ضرورت ہو، جیسے یوزر ای میل یا یوزر نام، تو یکتائی والے فیلڈز کا امتحان کریں۔

// یوزر سکیما۔
func (User) Fields() []ent.Field {
    return []ent.Field{
        field.String("email").Unique(),  // یونیک فیلڈ دوہری ای میل ایڈریسوں کے داخلے کو روکنے کے لئے
    }
}

یہ دوہری قیمتوں کے داخلے روکنے کے لئے زیریں ڈیٹا بیس میں یکتائی پابندی پیدا کرے گا۔

2.5. فیلڈ انڈیکسنگ

فیلڈ انڈیکسنگ ڈیٹا بیس کوئیریز کی کارکردگی کو بہتر بنانے کے لئے استعمال ہوتی ہے، خاص طور پر بڑے ڈیٹا بیسوں میں۔ ent فریم ورک میں، .Indexes() میتھڈ کا استعمال کر کے انڈیکس بنایا جا سکتا ہے۔

import "entgo.io/ent/schema/index"

// یوزر سکیما۔
func (User) Indexes() []ent.Index {
    return []ent.Index{
        index.Fields("email"),  // 'email' فیلڈ پر انڈیکس بنائیں
        index.Fields("name", "age").Unique(), // یکتائی اختیاری انڈیکس بنائیں
    }
}

انڈیکسز درخواست کرنے والے فیلڈز کے لئے استعامل ہو سکتے ہیں، لیکن اہم نوٹ کرنا ہوگا کہ زیادہ انڈیکسز کا استعمال لکھنے کی کارکردگی میں کمی کر سکتا ہے، لہذا انڈیکس بنانے کا فیصلہ واقعی حالات پر مبنی ہونا چاہئے۔

2.6. کسٹم ٹیگز

ent فریم ورک میں، آپ StructTag میتھڈ کا استعمال کر کے جنریٹڈ انٹٹٹی سٹرکچر فیلڈز میں کسٹم ٹیگز شامل کر سکتے ہیں۔ یہ ٹیگز جیسے جیسے جیسے جیسے ایپلیکیشن جیسے جیسے یہ شروع ہوں، ان کی استعمال فیصلے کو بہتر بنانے میں بہتری عرض کرتی ہیں۔ نیچے دیے گئے مثال میں، ہم name فیلڈ کے لئے کسٹم JSON اور XML ٹیگز شامل کریں گے۔

// یوزر کے فیلڈز۔
func (User) Fields() []ent.Field {
    return []ent.Field{
        field.String("name").
            // StructTag میتھڈ کا استمال کر کے کسٹم ٹیگز شامل کریں
            // یہاں، 'name' فیلڈ کے لئے JSON ٹیگ کو 'username' پر رکھیں اور جب فیلڈ خالی ہو (omitempty) تو اسے نظرانداز کریں
            // علاوہ ازیں، ایکس ایم ایل ٹیگ بنانے کے لئے 'name' سیٹ کریں
            StructTag(`json:"username,omitempty" xml:"name"`),
    }
}

جب JSON یا XML کے ساتھ اینکوڈ کرتے ہیں، omitempty اختیار بتاتا ہے کہ اگر name فیلڈ خالی ہو تو پھر یہ فیلڈ اینکوڈنگ کے نتیجے سے نکال دیا جائے گا۔ یہ APIز لکھتے وقت ریسپانس بادی کو کم کرنے کے لئے بہتری کے لئے بہت کار آمد ہے۔

یہ بھی دکھاتا ہے کہ ایک ہی فیلڈ کے لئے کئی تیگز سیٹ کرنے کا طریقہ۔ JSON ٹیگز json کی کلید استعمال کرتی ہیں، XML ٹیگز xml کی کلید استعمال کرتی ہیں، اور یہ اسراعی جبائیں کا استعمال کرتی ہیں جیسے encoding/json اور encoding/xml جب سٹرکچر کو اینکوڈنگ یا ڈی کوڈنگ کرنے کے لئے پارس کرتے ہیں۔

3. فیلڈ ولیدیشن اور پابندیاں

فیلڈ ولیدیشن ڈیٹا بیس ڈیزائن کا اہم پہلو ہے تاکہ ڈیٹا کے استقامت اور درستی کو یقینی بنایا جاسکے۔ اس سیکشن میں، ہم بنیادی ولیدیٹرز، کسٹم ولیدیٹرز، اور مختلف پابندیوں کا استعمال کر کے انٹٹی ماڈل کی استقامت اور کوالٹی کو بہتر کرنے پر غور کریں گے۔

3.1. مضمون مقرر کنندگان

فریم ورک مختلف کے فیلڈوں پر عمومی ڈیٹا درستی کی چیک کرنے والے عام مقرر کنندگان فراہم کرتا ہے۔ ان مقرر کنندگان کا استعمال ترقی کے عمل کو آسان بنا سکتا ہے اور فریلڈوں کے لئے درست ڈیٹا کی رنج یا فارمیٹ کو فوراً تعین کر سکتا ہے۔

یہاں کچھ مثالیں فراہم کی گئی ہیں:

  • اعدادی قسموں کے لئے مقرر کنندگان:
    • Positive(): فیلڈ کی قیمت کا تصدیق کرتا ہے کہ یہ مثبت عدد ہے۔
    • Negative(): فیلڈ کی قیمت کا تصدیق کرتا ہے کہ یہ منفی عدد ہے۔
    • NonNegative(): فیلڈ کی قیمت کا تصدیق کرتا ہے کہ یہ منفی نہیں عدد ہے۔
    • Min(i): فیلڈ کی قیمت کا تصدیق کرتا ہے کہ یہ دی گئی کم سے کم قیمت i سے زیادہ ہے۔
    • Max(i): فیلڈ کی قیمت کا تصدیق کرتا ہے کہ یہ دی گئی زیادہ سے زیادہ قیمت i سے کم ہے۔
  • string قسم کے لئے مقرر کنندگان:
    • MinLen(i): مقرر کرتا ہے کہ مسلسل کی کم ترین لمبائی کی تصدیق کرتا ہے۔
    • MaxLen(i): مقرر کرتا ہے کہ مسلسل کی زیادہ ترین لمبائی کی تصدیق کرتا ہے۔
    • Match(regexp.Regexp): تصدیق کرتا ہے کہ مسلسل مقرر کردہ عام صورت کے مطابق ہے یا نہیں۔
    • NotEmpty: تصدیق کرتا ہے کہ مسلسل خالی نہیں ہے۔

چلیں ایک عملی مثال پر نظر ڈالتے ہیں۔ اس مثال میں ایک User ماڈل بنایا گیا ہے، جس میں ایک غیر منفی عددی قسم کا age فیلڈ اور ایک email فیلڈ شامل ہیں جس کا فکس فارمیٹ ہے:

func (User) Fields() []ent.Field {
    return []ent.Field{
        field.Int("age").
            Positive(),
        field.String("email").
            Match(regexp.MustCompile(`^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$`)),
    }
}

3.2. اپنے مقرر کنندگان

جبکہ مضمون مقرر کنندگان کئی عام ضابطہ ضابطہ لیں سکتے ہیں، کبھی کبھار آپ کو مزید پیچیدہ ویلیڈیشن لاجک کی ضرورت ہو سکتی ہے۔ ایسی صورت میں، آپ کسٹم ویلیڈیٹرز لکھ سکتے ہیں تاکہ مخصوص کاروباری قواعد کو پورا کر سکیں۔

ایک کسٹم ویلیڈیٹر ایک فنکشن ہوتا ہے جو ایک فیلڈ کی قیمت کو حاصل کرکے ایک error واپس کرتا ہے۔ اگر واپس کردہ error خالی نہیں ہے، تو یہ ویلیڈیشن کی ناکامی ظاہر کرتا ہے۔ ایک کسٹم ویلیڈیٹر کا عام فارمیٹ مندرجہ ذیل ہے:

func (User) Fields() []ent.Field {
    return []ent.Field{
        field.String("phone").
            Validate(func(s string) error {
                // تصدیق کریں کہ فون نمبر متوقع فارمیٹ کو پورا کرتا ہے
                matched, _ := regexp.MatchString(`^\+?[1-9]\d{1,14}$`, s)
                if !matched {
                    return errors.New("غلط فون نمبر فارمیٹ")
                }
                return nil
            }),
    }
}

جیسا کہ مندرجہ بالا دکھایا گیا ہے، ہم نے فون نمبر کے فارمیٹ کی تصدیق کرنے کے لئے ایک کسٹم ویلیڈیٹر بنایا ہے۔

3.3. پابندیاں

پابندیاں وہ قواعد ہیں جو ڈیٹا بیس آبجیکٹ پر مخصوص قواعد عائد کرتی ہیں۔ یہ معلومات کی درستگی اور مستقلیت کو یقینی بنانے یا غلط ڈیٹا کو روکنے کے لئے استعمال کی جاتی ہیں۔

عام ڈیٹا بیس پابندیاں درج ذیل ہیں:

  • پرائمری کی پابندی: یہ یقینی بناتا ہے کہ ہر ریکارڈ انواع میں یونیک ہوں۔
  • یونیک پابندی: یہ یقینی بناتا ہے کہ کسی کالم کی یا کا کمبائنیشن کی قیمت ٹیبل میں یونیک ہے۔
  • فارن کی پابندی: یہ چیزوں کے درمیان تعلقات کی تعیناتی مستقلیت ہے، یقینی بناتا ہے کہ اشارتی انتقالیت یقینی بن جائے۔
  • چیک پابندی: یہ یقینی بناتا ہے کہ کسی فیلڈ کی قیمت کسی مخصوص شرط کو پورا کرتی ہے۔

انٹٹٹی ماڈل میں، آپ پابندیاں منظم کر سکتے ہیں تاکہ ڈیٹا کی مستقلیت کو برقرار رکھا جا سکے، جیسے مندرجہ ذیل:

func (User) Fields() []ent.Field {
    return []ent.Field{
        field.String("username").
            Unique(), // یونیک پابندی جو یقینی بناتی ہے کہ ٹیبل میں یوزر نیم یونیک ہے۔
        field.String("email").
            Unique(), // یونیک پابندی جو یقینی بناتی ہے کہ ای میل یونیک ہے۔
    }
}

func (User) Edges() []ent.Edge {
    return []ent.Edge{
        edge.To("friends", User.Type).
            Unique(), // فارن کی پابندی جو ایک یونیک ایج رشتے کو دوسرے یوزر کے ساتھ بناتی ہے۔
    }
}

خلاصہ، فیلڈ ویلیڈیشن اور پابندیاں درست ڈیٹا کی معیار پسندگی اور غیر متوقع ڈیٹا خرابیوں سے بچانے کیلئے بہت اہم ہیں۔ ent فریم ورک کے فراہم کردہ ٹولز کا استعمال یہ عمل کم سے کم اور معتبر بنا سکتا ہے۔