يوفر هذا البرنامج التعليمي دليلاً شاملاً لفهم لغة المجال المحددة (NammaDSL) والعمل معها في NammaYatri. ويغطي إنشاء ملفات YAML، وتوليد التعليمات البرمجية، وتجميعها، بالإضافة إلى بناء الجملة لتحديد واجهات برمجة التطبيقات والتخزين.
الموقع : قم بإنشاء ملف YAML داخل مجلد spec
الخاص بالوحدة التي تعمل عليها. على سبيل المثال، إذا كنت تعمل على rider-app
، فسيكون المسار:
rider-platform/rider-app/spec
اعتمادًا على نوع المواصفات التي تحددها، يمكنك وضع الملف داخل مجلد API
أو مجلد Storage
.
إنشاء الكود : بعد تحديد ملفات YAML، قم بتنفيذ الأمر التالي لإنشاء الكود:
, run-generator
يقوم هذا الأمر بإنشاء ملفات Haskell Beam والاستعلام والمجال في دليل src-read-only
، بالإضافة إلى استعلامات SQL.
ملاحظة هامة : سيقوم هذا الأمر بإنشاء ملفات المواصفات الجديدة أو المتغيرة فقط. يتم ذلك عن طريق الحصول على التجزئة الحالية لملف المواصفات ومقارنتها بتجزئة الملف الخاصة بالتزام HEAD
, run-generator --all
استخدم وسيطات "-all" لإنشاء كافة ملفات المواصفات
التجميع : قم بتجميع الكود باستخدام:
cabal build all
imports
: تستخدم لاستيراد الأنواع المحددة مسبقًا.
importPackageOverrides
: يستخدم لتجاوز حزم الاستيراد شاهد المزيد
module
: تحدد اسم الوحدة النمطية.
ملاحظة: في حالة واجهات برمجة التطبيقات للوحة المعلومات، فإن جميع واجهات برمجة التطبيقات في الوحدة لها نفس بادئة واجهة برمجة التطبيقات، وبشكل افتراضي يتم تحويل module
إلى حالة الجمل.
apiPrefix
: استبدال بادئة واجهة برمجة التطبيقات الافتراضية لواجهة برمجة تطبيقات لوحة المعلومات الرئيسية والمساعد (اختياري، خاص بلوحة المعلومات).
ملاحظة: القيمة الفارغة ""
مسموح بها لـ apiPrefix
و helperApiPrefix
، وهذا يعني عدم وجود بادئة API.
helperApiPrefix
: استبدال بادئة API لواجهة برمجة تطبيقات لوحة المعلومات المساعدة (اختياري، خاص بلوحة المعلومات).
types
: يحدد أنواع الطلب والاستجابة لواجهات برمجة التطبيقات الخاصة بك. هذا الحقل اختياري. نفس الأنواع المعقدة في تخزين DSL. يتم تعريف الأنواع بالتنسيق التالي:
{TypeName}:
- {field1}: {field1Type}
- {field2}: {field2Type}
- derive: {Any extra derivation}
ملاحظة: بناء الجملة القديم لا يحافظ على ترتيب الحقول وسيتم إهماله.
{TypeName}:
{field1}: {field1Type}
{field2}: {field2Type}
derive: {Any extra derivation}
يمكن تعريف أنواع التعداد على النحو التالي:
{TypeName}:
- enum: {enum1},{enum2}
- derive: {Any extra derivation}
لإنشاء نوع جديد أو كتابة بدلاً من البيانات، استخدم recordType: NewType | Data (Default) | Type
{TypeName}:
- recordType: NewType
- {fieldName}: {fieldType}
- derive: {Any extra derivation}
{TypeName}:
- recordType: Type
- type: {fieldType}
لإنشاء مثيل HideSecrets الافتراضي، استخدم الكلمة الأساسية derive
(خاصة بلوحة المعلومات)
{TypeName}:
- {fieldName}: {fieldType}
- derive: "'HideSecrets"
apis
: يحتوي على كافة واجهات برمجة التطبيقات بالتنسيق التالي:
{httpMethod}
(طريقة HTTP GET | POST | PUT | DELETE) endpoint
: مسار API
/path1/path2/{pathParam1}/path3/{pathParam2}
ملحوظة: يجب ذكر أنواع معلمات المسار في جزء المعلمات أدناه.
name
: اسم واجهة برمجة التطبيقات. في بعض الأحيان يكون لواجهتي برمجة تطبيقات مختلفتين نفس اسم واجهة برمجة التطبيقات الذي تم إنشاؤه تلقائيًا من المسار، لذلك يمكن الكتابة فوقه (اختياري)
ملاحظة: كن حذرًا عند تغيير apiName
لواجهة برمجة التطبيقات الموجودة بالفعل. عند تغيير apName
، سيتم أيضًا تغيير إنشاء Endpoint
و UserActonType
، ويجب ترحيل البيانات القديمة على النحو التالي:
migrate:
endpoint: <oldEndpoint>
userActionType: <oldUserActionType>
عادةً ما تكون <oldEndpoint>
و <oldUserActionType>
هي نفس القيم بهذا التنسيق:
PROVIDER_MANAGEMENT/BOOKING/POST_BOOKING_CANCEL_ALL_STUCK
response
:
type
: نوع الاستجابة request
:
type
: نوع الطلب (اختياري) multipart
:
type
: نوع الطلب في حالة الطلب متعدد الأجزاء (اختياري) auth
: طريقة المصادقة (الافتراضية: TokenAuth) شاهد المزيد
query
: قائمة معلمات الاستعلام
- {queryParam1}: {queryParam1Type}
ملاحظة: بناء الجملة القديم لا يحافظ على ترتيب المعلمات وسيتم إهماله.
{queryParam1}: {queryParam1Type}
mandatoryQuery
: قائمة معلمات الاستعلام الإلزامية
- {mandatoryQueryParam1}: {mandatoryQueryParam1Type}
ملاحظة: بناء الجملة القديم لا يحافظ على ترتيب المعلمات وسيتم إهماله.
{mandatoryQueryParam1}: {mandatoryQueryParam1Type}
params
: قائمة معلمات المسار
{pathParam1}: {pathParam1Type}
{pathParam2}: {pathParam2Type}
headers
: قائمة الرؤوس
headers:
- {header1}: {headerType1}
- {header2}: {headerType2}
helperApi
: يحتوي بشكل متكرر على واجهة برمجة تطبيقات مساعد لوحة المعلومات بنفس تنسيق واجهة برمجة التطبيقات الرئيسية (اختياري، خاص بلوحة المعلومات)
validation
: اسم مؤهل لوظيفة التحقق من صحة الطلب (اختياري)
مثال:
imports : {}
module : Sos
types :
SosRes :
- sosId : Id Sos
SosDetailsRes :
- sos : Maybe Sos
SosReq :
- flow : SosType
- rideId : Id Ride
SosUpdateReq :
- status : SosStatus
- comment : Maybe Text
apis :
# GET /sos/getDetails
- GET :
endpoint : /sos/getDetails/{rideId}
auth : TokenAuth
params :
rideId : Id Ride
response :
type : API.Types.UI.Sos.SosDetailsRes
# # POST /sos/{sosId}/status
- POST :
endpoint : /sos/{sosId}/status
auth : TokenAuth RIDER_TYPE
params :
sosId : Id Sos
request :
type : API.Types.UI.Sos.SosUpdateReq
response :
type : Kernel.Types.APISuccess.APISuccess
auth: ApiAuth DRIVER_OFFER_BPP_MANAGEMENT DRIVERS LIST
imports
: تستخدم لاستيراد الأنواع المحددة مسبقًا. شاهد المزيد{dataTypeName}
: يحدد اسم الوحدة. tableName
: اسم اختياري للجدول، ويأخذ حالة الثعبان لـ dataTypeName
إذا لم يتم تعريفه.
fields
: يسرد كافة حقول الجدول بنوع هاسكل. شاهد المزيد
constraints
: المفتاح الأساسي | المفتاح الثانوي | ليس فارغًا | زيادة تلقائية
importPackageOverrides
: يستخدم لتجاوز حزم الاستيراد شاهد المزيد
types
: أنواع محددة من قبل المستخدم، تشبه أنواع واجهة برمجة التطبيقات (API). شاهد المزيد
derives
: تجاوز مشتقات نوع البيانات الرئيسي.
derives : " Show,Eq,Ord "
beamType
: نوع الشعاع المحدد من قبل المستخدم لنوع بيانات محدد. شاهد المزيد
beamFields
: تغيير اسم حقل الشعاع المحدد من قبل المستخدم أو استخدامه إذا كنت تريد الحصول على شيء مختلف على جانب الشعاع. شاهد المزيد
beamInstance
: يمكننا أن نذكر مثيل الشعاع الذي نحتاجه باستخدام هذا الحقل شاهد المزيد
sqlType
: نوع SQL محدد من قبل المستخدم للحقل. شاهد المزيد
default
: قيمة SQL الافتراضية للحقول، إن وجدت
fields :
scheduleTryTimes : ' [Int] '
tripCategory : Text
default :
tripCategory : " 'All' "
scheduleTryTimes : " '{1800, 900, 300}' "
queries
: جميع استعلامات Beam للجدول. شاهد المزيد
cachedQueries:
استعلامات مخزنة مؤقتًا للجدول. شاهد المزيد
fromTType
: FromTType من الحقول، إن أمكن. شاهد المزيد
toTType
: ToTType من الحقول، إن أمكن. شاهد المزيد
excludedFields
: هناك بعض الحقول الشائعة مثل MerchantId وcommerceOperatingCityId وcreateAt وupdateAt والتي تتم إضافتها تلقائيًا في نوع البيانات. لإزالتها استخدم هذا.
excludedFields :
- merchantOperatingCityId
- merchantId
extraIndexes
: أي فهارس إضافية شاهد المزيد
extraOperations
: العمليات الإضافية شاهد المزيد
يجب عليك تقديم اسم الوحدة في الواردات
imports :
Merchant : Domain.Types.Merchant
FRFSSearch : Domain.Types.FRFSSearch
ملاحظة: يتم استيراد هذه الأنواع الشائعة تلقائيًا، لذا يمكنك استخدامها مباشرة دون استيراد
Text -> Kernel.Prelude
Maybe -> Kernel.Prelude
Double -> Kernel.Prelude
TimeOfDay -> Kernel.Prelude
Day -> Data.Time.Calendar
Int -> Kernel.Prelude
Bool -> Kernel.Prelude
Id -> Kernel.Types.Id
ShortId -> Kernel.Types.Id
UTCTime -> Kernel.Prelude
Meters -> Kernel.Types.Common
HighPrecMeters -> Kernel.Types.Common
Kilometers -> Kernel.Types.Common
HighPrecMoney -> Kernel.Types.Common
Seconds -> Kernel.Types.Common
imports:
DataType1: Domain.Types.DataType1
لتغيير الحزمة:
importPackageOverrides:
Domain.Types.DataType1: dashboard-api
الاستيراد الذي تم إنشاؤه في هاسكل:
import "dashboard-api" Domain.Types.DataType1
في بعض الأحيان قد نحتاج إلى تخطي تجاوز الحزمة عندما نقوم بالإنشاء في نفس الحزمة. ثم يجب علينا تحديد تعيين الحزمة في تكوينات dhall
:
, _packageMapping =
[ { _1 = GeneratorType. API_TYPES , _2 = " dashboard-api " }
{ _1 = GeneratorType. SERVANT_API , _2 = " rider-app " }
]
تم إنشاء الاستيراد في haskell لـ API_TYPES
:
import "this" Domain.Types.DataType1
استيراد تم إنشاؤه في haskell لـ SERVANT_API
:
import "dashboard-api" Domain.Types.DataType1
في قسم الحقل، اذكر اسم الحقل ونوع Haskell المقابل
imports : {}
LmsModule :
tableName : lms_module
fields :
id : Id LmsModule
merchantOperatingCityId : Id MerchantOperatingCity
category : LmsCategory
createdAt : UTCTime
updatedAt : UTCTime
duration : Int
noOfVideos : Int
rank : Int
variant : Maybe Variant
moduleCompletionCriteria : ModuleCompletionCriteria
بالنسبة لأنواع الحقول البسيطة (التي تم استيرادها للتو) سيتم نسخها في جانب الشعاع أيضًا ما لم نذكر نوع شعاع محدد
إذا كان الحقل من النوع المعقد، فسيتم تقسيمه بشكل متكرر في جانب الشعاع ما لم نذكر نوع شعاع محدد
في حالة المعرف، سيتم اعتبار ShortId نوع الشعاع كنص
إذا أردنا نوع البيانات المستوردة على جانب المجال والمعرف المقابل على جانب الشعاع، فإننا نستخدم امتدادات WithId مع تعريف النوع.
fields :
field1 : Int
beamType :
field1 : Text
fields :
a : Int
b : Text
beamFields :
a : " aa "
b : " bb "
# SomeType = SomeType {
# integerValueInText :: Text,
# version :: Int
# }
import :
SomeType : Domain.Types.SomeType
Some :
fields :
id : Id Some
val : SomeType # See this is an imported type
beamFields :
val :
intValue : Int
intValueInText : Text
# We have to right the toTType and fromTType functions
toTType :
intValue : (Kernel.Prelude.read . Domain.Types.SomeType.integerValueInText)
intValueInText : Domain.Types.SomeType.integerValueInText
fromTType :
val : mkVal
data Some = Some
{ id :: Kernel.Types.Id. Id Domain.Types.Some. Some ,
val :: Domain.Types.SomeType. SomeType ,
merchantId :: Kernel.Prelude. Maybe ( Kernel.Types.Id. Id Domain.Types.Merchant. Merchant ),
merchantOperatingCityId :: Kernel.Prelude. Maybe ( Kernel.Types.Id. Id Domain.Types.MerchantOperatingCity. MerchantOperatingCity ),
createdAt :: Kernel.Prelude. UTCTime ,
updatedAt :: Kernel.Prelude. UTCTime
}
deriving ( Generic , Show , ToJSON , FromJSON , ToSchema )
data SomeT f = SomeT
{ id :: B. C f Kernel.Prelude. Text ,
intValue :: B. C f Kernel.Prelude. Int ,
intValueInText :: B. C f Kernel.Prelude. Text ,
merchantId :: B. C f ( Kernel.Prelude. Maybe ( Kernel.Prelude. Text )),
merchantOperatingCityId :: B. C f ( Kernel.Prelude. Maybe ( Kernel.Prelude. Text )),
createdAt :: B. C f Kernel.Prelude. UTCTime ,
updatedAt :: B. C f Kernel.Prelude. UTCTime
}
deriving ( Generic , B.Beamable )
beamInstance : MakeTableInstances
$ (mkTableInstances ''PersonT " person " )
beamInstance : MakeTableInstancesGenericSchema
$ (mkTableInstancesGenericSchema ''PersonT " person " )
beamInstance : MakeTableInstancesWithTModifier [("deviceOS", "device_o_s")]
$ (mkTableInstancesWithTModifier ''MetaDataT " meta_data " [( " deviceOS " , " device_o_s " )])
beamInstance : Custom mkCacParseInstace [[Table2],[Table3]]
$ (mkCacParseInstace ''MetaDataT [[ Table2 ], [ Table3 ]])
beamInstance : Custom mkCacParseInstace "table_name" [Table2] [Table3] [(a,b,c)]
beamInstance :
- MakeTableInstances
- Custom mkCacParseInstace [[Table2],[Table3]]
- Custom Tool.Something.mkSomething "abc" [(a,b,c)] [[a],[b],[c]]
$ (mkTableInstances ''PersonT " person " )
$ (mkCacParseInstace ''MetaDataT [[ Table2 ], [ Table3 ]])
$ ( Tool.Something. mkSomething ''MetaDataT " abc " [(a,b,c)] [[a],[b],[c]])
fields :
field1 : " [Int] "
sqlType :
field1 : " text[] "
toTType :
subscriberUrl : Kernel.Prelude.func1|I
gatewayUrl : showBaseUrlSimple # This function will be created in seperated file as it's not imported
registryUrl : showBaseUrl|M # This function will be created in seperated file as it's not imported
fromTType :
updatedAt : Kernel.Prelude.fromMaybe createdAt|I
isScheduled : makeSchelude
tripCategory : Kernel.Prelude.fromMaybe (Domain.Types.Common.OneWay Domain.Types.Common.OneWayOnDemandDynamicOffer)|I
fields :
isVerified : Bool
verificationUrl : Text
aadharId : Text
toTType :
isVerified : (K.B.verify aadharId verificationUrl)|E
toTType :
isVerified : K.B.verify isVerified aadharId verificationUrl)|EM
toTType :
isVerified : K.B.verify isVerified (K.B.C.isCorrectAadhar aadharId) verificationUrl)|EM
WithId: يتم استخدام هذا عندما نريد معرف نوع البيانات المستوردة كحقل الشعاع. لا يؤدي هذا إلى إنشاء نوع البيانات في استعلام إنشاء الحزمة.
WithCachedId: مثل WithId، والفرق الوحيد هو أن إنشاء واستعلام findbyId يتم استيراده من Storage.CachedQuery.*
WithIdCreate ، WithCachedIdCreate: استخدم هذا عندما يكون ذلك مطلوبًا لإنشاء نوع البيانات في إنشاء استعلام. هام: يجب أن يحتوي نوع البيانات المستوردة على وظيفة إنشاء في ملف الاستعلام المقابل له مثال:
fields :
fareParams : Maybe FareParameters|WithIdCreate
farePolicy : Maybe FarePolicy|WithCachedId
استعلام الإنشاء الذي تم إنشاؤه:
create :: ( EsqDBFlow m r , MonadFlow m , CacheFlow m r ) => Domain.Types.Estimate. Estimate -> m ()
create tbl = do
Kernel.Prelude. whenJust tbl . fareParams Storage.Queries.FareParameters. create
createWithKV tbl
تحويلات ToTType وFromTType التي تم إنشاؤها:
instance FromTType' Beam. Estimate Domain.Types.Estimate. Estimate where
fromTType' Beam. EstimateT { .. } = do
fareParams' <- maybe ( pure Nothing ) ( Storage.Queries.FareParameters. findById . Kernel.Types.Id. Id ) fareParamsId
farePolicy' <- maybe ( pure Nothing ) ( Storage.CachedQueries.FarePolicy. findById . Kernel.Types.Id. Id ) farePolicyId
pure $
Just
Domain.Types.Estimate. Estimate
{
fareParams = fareParams',
farePolicy = farePolicy'
}
instance ToTType' Beam. Estimate Domain.Types.Estimate. Estimate where
toTType' Domain.Types.Estimate. Estimate { .. } = do
Beam. EstimateT
{ Beam. fareParamsId = ( Kernel.Types.Id. getId . ( . id ) <$> ) fareParams,
Beam. farePolicyId = ( Kernel.Types.Id. getId . ( . id ) <$> ) farePolicy
}
بناء الجملة:
queries:
{query function name}:
kvFunction: {kv function name}
params: [field1, field2 .. ] Array of field to be updated in update queries
where:
{where clause}
orderby: {field name} (optional)
حيث بناء الجملة:
where:
- {operator1}:
- field1
- {operator2}:
- field2
- field3
- {operator3}:
- field4
- field5
الحقول المستخدمة في المعلمات وحيث يمكن أن تكون الجملة من 3 أنواع:
where:
not_eq
where:
not_eq:
- id: id2|B
myname|CS -> "myname"
123|CI -> 123
123|CS -> "123"
0.23|CD -> 0.23
"0.34"|CS -> "0.23"
true|CB -> True
Domain.Something.defaultValue|CIM -> Domain.Something.defaultValue (and Domain.Something is added to imports)
kvFunction: updateWithKV
params:
- status: newStatus
where:
eq:
- status: NEW|CIM
kvFunction: updateWithKV
params:
- status: Domain.Types.DataType.CONFIRMED|CIM
where:
eq:
- status: NEW|CIM
where:
and:
- eq:
- status: NEW|CIM
- id|B
قائمة حيث المشغلين:
مثال:
LmsModule :
fields :
id : Id LmsModule
category : LmsCategory
question : Question
field1 : Text
field2 : Text
field3 : Text
types :
LmsCategory :
enum : " Safety, Financial, Training "
QuestionType :
enum : " Maths, Physics, Chemistry "
derive : " Show "
Question :
question : Text
tp : QuestionType
derive : " Show,Eq "
queries :
findByComplexCondition :
kvFunction : findAllWithOptionsKV
where :
and :
- field1
- or :
- field2
- field3
- category
- question
orderBy : createdAt
updateQuestionById :
kvFunction : updateWithKV
params :
- question
where :
id
الاستعلام الذي تم إنشاؤه:
findAllWithKV
[ Se. And
[ Se. Is Beam. field1 $ Se. Eq field1,
Se. Or
[ Se. Is Beam. field2 $ Se. Eq field2,
Se. Is Beam. field3 $ Se. Eq field3
],
Se. Is Beam. category $ Se. Eq category,
Se. Is Beam. questionQuestion $ Se. Eq $ Domain.Types.LmsModule. question question,
Se. Is Beam. questionTp $ Se. Eq $ Domain.Types.LmsModule. tp question
]
]
updateQuestionById question ( Kernel.Types.Id. Id id ) = do
_now <- getCurrentTime
updateWithKV
[ Se. Set Beam. questionQuestion $ Domain.Types.LmsModule. question question,
Se. Set Beam. questionTp $ Domain.Types.LmsModule. tp question,
Se. Set Beam. updatedAt _now
]
[ Se. Is Beam. id $ Se. Eq id
]