บทช่วยสอนนี้ให้คำแนะนำที่ครอบคลุมเพื่อทำความเข้าใจและการทำงานกับ Domain specific Language (NammaDSL) ใน NammaYatri โดยครอบคลุมถึงการสร้างไฟล์ YAML การสร้างโค้ด และการคอมไพล์ รวมถึงไวยากรณ์สำหรับการกำหนด API และพื้นที่เก็บข้อมูล
ตำแหน่ง : สร้างไฟล์ YAML ภายในโฟลเดอร์ spec
ของโมดูลที่คุณกำลังทำงานอยู่ ตัวอย่างเช่น หากคุณกำลังทำงานกับ rider-app
เส้นทางจะเป็น:
rider-platform/rider-app/spec
ขึ้นอยู่กับประเภทของข้อกำหนดที่คุณกำหนด คุณอาจวางไฟล์ไว้ในโฟลเดอร์ API
หรือ Storage
การสร้างโค้ด : หลังจากกำหนดไฟล์ YAML แล้ว ให้ดำเนินการคำสั่งต่อไปนี้เพื่อสร้างโค้ด:
, run-generator
คำสั่งนี้สร้างไฟล์ Haskell Beam, การสืบค้น และโดเมนในไดเร็กทอรี src-read-only
เช่นเดียวกับการสืบค้น SQL
หมายเหตุสำคัญ : คำสั่งนี้จะสร้างเฉพาะไฟล์ข้อมูลจำเพาะที่เป็นไฟล์ใหม่หรือมีการเปลี่ยนแปลงเท่านั้น สิ่งนี้ทำได้โดยการรับแฮชปัจจุบันของไฟล์ spec และเปรียบเทียบกับแฮชของไฟล์ของการคอมมิต HEAD
, run-generator --all
ใช้ args "--all" เพื่อสร้างไฟล์ spec ทั้งหมด
การคอมไพล์ : คอมไพล์โค้ดโดยใช้:
cabal build all
imports
: ใช้สำหรับการนำเข้าประเภทที่กำหนดไว้ล่วงหน้า
importPackageOverrides
: ใช้เพื่อแทนที่แพ็คเกจการนำเข้า ดูเพิ่มเติม
module
: ระบุชื่อของโมดูล
หมายเหตุ: ในกรณีของ API แดชบอร์ด API ทั้งหมดในโมดูลจะมีคำนำหน้า API เหมือนกัน โดยค่าเริ่มต้น module
จะถูกแปลงเป็นรูปแบบ Camel
apiPrefix
: เขียนทับคำนำหน้า API เริ่มต้นสำหรับ API แดชบอร์ดหลักและตัวช่วย (ตัวเลือก เฉพาะสำหรับแดชบอร์ด)
หมายเหตุ: อนุญาตให้ใช้ค่าว่าง ""
สำหรับ apiPrefix
และ helperApiPrefix
หมายความว่าไม่มีคำนำหน้า API
helperApiPrefix
: เขียนทับคำนำหน้า API สำหรับ API แดชบอร์ดตัวช่วย (เป็นทางเลือก เฉพาะสำหรับแดชบอร์ด)
types
: กำหนดประเภทคำขอและการตอบสนองสำหรับ API ของคุณ ฟิลด์นี้เป็นทางเลือก เช่นเดียวกับประเภทที่ซับซ้อนใน Storage DSL ประเภทถูกกำหนดในรูปแบบต่อไปนี้:
{TypeName}:
- {field1}: {field1Type}
- {field2}: {field2Type}
- derive: {Any extra derivation}
หมายเหตุ: ไวยากรณ์เก่าไม่รักษาลำดับของฟิลด์และจะเลิกใช้แล้ว
{TypeName}:
{field1}: {field1Type}
{field2}: {field2Type}
derive: {Any extra derivation}
ประเภท Enum สามารถกำหนดได้ดังนี้:
{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
: ประกอบด้วย API ทั้งหมดในรูปแบบต่อไปนี้:
{httpMethod}
(วิธี HTTP GET | POST | PUT | DELETE) endpoint
: เส้นทาง API
/path1/path2/{pathParam1}/path3/{pathParam2}
หมายเหตุ: ควรกล่าวถึงประเภทพารามิเตอร์เส้นทางในส่วน พารามิเตอร์ ด้านล่าง
name
: ชื่อ API บางครั้ง API ที่แตกต่างกันสองตัวจะมีชื่อ API เดียวกันที่สร้างขึ้นโดยอัตโนมัติจากเส้นทาง ดังนั้นจึงสามารถเขียนทับได้ (ไม่บังคับ)
หมายเหตุ: โปรดใช้ความระมัดระวังเมื่อคุณเปลี่ยน apiName
สำหรับ API ที่มีอยู่แล้ว เมื่อ 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
: มี API ตัวช่วยแดชบอร์ดแบบเรียกซ้ำในรูปแบบเดียวกับ API หลัก (เป็นทางเลือก เฉพาะสำหรับแดชบอร์ด)
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
: แสดงรายการฟิลด์ทั้งหมดของตารางด้วยประเภท Haskell ดูเพิ่มเติม
constraints
: PrimaryKey | รองคีย์ | ไม่เป็นค่าว่าง | เพิ่มอัตโนมัติ
importPackageOverrides
: ใช้เพื่อแทนที่แพ็คเกจการนำเข้า ดูเพิ่มเติม
types
: ประเภทที่ผู้ใช้กำหนด คล้ายกับประเภท API ดูเพิ่มเติม
derives
: แทนที่มาจากประเภทข้อมูลหลัก
derives : " Show,Eq,Ord "
beamType
: ประเภทลำแสงที่ผู้ใช้กำหนดสำหรับประเภทข้อมูลที่ระบุ ดูเพิ่มเติม
beamFields
: เปลี่ยนชื่อฟิลด์บีมที่ผู้ใช้กำหนดหรือใช้มันหากคุณต้องการให้มีบางสิ่งที่แตกต่างบนบีมไซด์ ดูเพิ่มเติม
beamInstance
: เราสามารถพูดถึง beam instance ที่เราต้องใช้ในช่องนี้ได้ ดูเพิ่มเติม
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, MerchantOperatingCityId, createAt และ updatedAt ซึ่งจะถูกเพิ่มอัตโนมัติในประเภทข้อมูล หากต้องการลบออกให้ใช้สิ่งนี้
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
สร้างการนำเข้าใน haskell:
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
สำหรับประเภทฟิลด์แบบธรรมดา (ซึ่งเพิ่งนำเข้ามา) มันจะถูกคัดลอกในด้านลำแสงเช่นกัน เว้นแต่เราจะกล่าวถึงประเภทลำแสงเฉพาะเจาะจง
หากฟิลด์เป็นประเภทที่ซับซ้อน มันจะถูกแบ่งแบบวนซ้ำในด้านลำแสง เว้นแต่เราจะพูดถึงประเภทลำแสงเฉพาะ
ในกรณีของ Id ShortId ประเภทลำแสงจะถือเป็นข้อความ
หากเราต้องการประเภทข้อมูลที่นำเข้าบนฝั่งโดเมนและ Id ที่สอดคล้องกันบนฝั่งลำแสง เราจะใช้ส่วนขยาย 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: ใช้เมื่อเราต้องการ Id ประเภทข้อมูลที่นำเข้าเป็น Beam Field สิ่งนี้ไม่ได้สร้างชนิดข้อมูลในคิวรีสร้างบีม
WithCachedId: เช่นเดียวกับ WithId ความแตกต่างเพียงอย่างเดียวคือคิวรี create และ 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
]