Dieses Tutorial bietet eine umfassende Anleitung zum Verständnis und zur Arbeit mit der Domain Specific Language (NammaDSL) im NammaYatri. Es umfasst die Erstellung von YAML-Dateien, die Codegenerierung und -kompilierung sowie die Syntax zum Definieren von APIs und Speicher.
Speicherort : Erstellen Sie eine YAML-Datei im spec
des Moduls, an dem Sie arbeiten. Wenn Sie beispielsweise an der rider-app
arbeiten, wäre der Pfad:
rider-platform/rider-app/spec
Abhängig von der Art der Spezifikation, die Sie definieren, können Sie die Datei entweder im API
oder Storage
ablegen.
Codegenerierung : Führen Sie nach der Definition der YAML-Dateien den folgenden Befehl aus, um den Code zu generieren:
, run-generator
Dieser Befehl generiert Haskell Beam-, Abfrage- und Domänendateien im src-read-only
-Verzeichnis sowie die SQL-Abfragen.
Wichtiger Hinweis : Dieser Befehl generiert nur die Spezifikationsdateien, die neu oder geändert sind. Dazu wird der aktuelle Hash der Spezifikationsdatei abgerufen und mit dem Datei-Hash des HEAD-Commits verglichen
, run-generator --all
Verwenden Sie die Argumente „--all“, um alle Spezifikationsdateien zu generieren
Kompilierung : Kompilieren Sie den Code mit:
cabal build all
imports
: Wird zum Importieren vordefinierter Typen verwendet.
importPackageOverrides
: Wird zum Überschreiben von Importpaketen verwendet. Weitere Informationen
module
: Gibt den Namen des Moduls an.
Hinweis: Bei Dashboard-APIs haben alle APIs im Modul dasselbe API-Präfix. Standardmäßig wird das module
in die Kamel-Schreibweise konvertiert.
apiPrefix
: Überschreibt das Standard-API-Präfix für die Haupt- und Hilfs-Dashboard-API (optional, spezifisch für das Dashboard).
Hinweis: Für apiPrefix
und helperApiPrefix
ist der leere Wert ""
zulässig. Dies bedeutet, dass kein API-Präfix vorhanden ist.
helperApiPrefix
: API-Präfix für die Helper-Dashboard-API überschreiben (optional, spezifisch für das Dashboard).
types
: Definiert die Anforderungs- und Antworttypen für Ihre APIs. Dieses Feld ist optional. Identisch mit komplexen Typen in Storage DSL. Typen werden im folgenden Format definiert:
{TypeName}:
- {field1}: {field1Type}
- {field2}: {field2Type}
- derive: {Any extra derivation}
Hinweis: Die alte Syntax behält die Reihenfolge der Felder nicht bei und wird nicht mehr unterstützt.
{TypeName}:
{field1}: {field1Type}
{field2}: {field2Type}
derive: {Any extra derivation}
Aufzählungstypen können wie folgt definiert werden:
{TypeName}:
- enum: {enum1},{enum2}
- derive: {Any extra derivation}
Um einen neuen Typ oder Typ anstelle von Daten zu erstellen, verwenden Sie recordType: NewType | Data (Default) | Type
{TypeName}:
- recordType: NewType
- {fieldName}: {fieldType}
- derive: {Any extra derivation}
{TypeName}:
- recordType: Type
- type: {fieldType}
Um eine Standard-HideSecrets-Instanz zu erstellen, verwenden Sie das Schlüsselwort derive
(spezifisch für das Dashboard).
{TypeName}:
- {fieldName}: {fieldType}
- derive: "'HideSecrets"
apis
: Enthält alle APIs im folgenden Format:
{httpMethod}
(HTTP-Methode GET | POST | PUT | DELETE) endpoint
: API-Pfad
/path1/path2/{pathParam1}/path3/{pathParam2}
Hinweis: Pfadparametertypen sollten im Parameterteil unten erwähnt werden.
name
: API-Name. Manchmal haben zwei verschiedene APIs denselben API-Namen, der automatisch aus dem Pfad generiert wird, sodass er überschrieben werden kann (optional).
Hinweis: Seien Sie vorsichtig, wenn Sie apiName
für eine bereits vorhandene API ändern. Wenn sich apName
ändert, wird auch die Endpoint
und UserActonType
Generierung geändert. Alte Daten sollten wie folgt migriert werden:
migrate:
endpoint: <oldEndpoint>
userActionType: <oldUserActionType>
Normalerweise sind <oldEndpoint>
und <oldUserActionType>
die gleichen Werte in diesem Format:
PROVIDER_MANAGEMENT/BOOKING/POST_BOOKING_CANCEL_ALL_STUCK
response
:
type
: Art der Antwort request
:
type
: Art der Anfrage (optional) multipart
:
type
: Art der Anfrage im Falle einer mehrteiligen Anfrage (optional) auth
: Authentifizierungsmethode (Standard: TokenAuth) Weitere Informationen
query
: Liste der Abfrageparameter
- {queryParam1}: {queryParam1Type}
Hinweis: Die alte Syntax behält die Reihenfolge der Parameter nicht bei und wird nicht mehr unterstützt.
{queryParam1}: {queryParam1Type}
mandatoryQuery
: Liste der obligatorischen Abfrageparameter
- {mandatoryQueryParam1}: {mandatoryQueryParam1Type}
Hinweis: Die alte Syntax behält die Reihenfolge der Parameter nicht bei und wird nicht mehr unterstützt.
{mandatoryQueryParam1}: {mandatoryQueryParam1Type}
params
: Liste der Pfadparameter
{pathParam1}: {pathParam1Type}
{pathParam2}: {pathParam2Type}
headers
: Liste der Header
headers:
- {header1}: {headerType1}
- {header2}: {headerType2}
helperApi
: Enthält rekursiv die Dashboard-Hilfs-API im gleichen Format wie die Haupt-API (optional, spezifisch für Dashboard).
validation
: Qualifizierter Name für die Anforderungsvalidierungsfunktion (optional)
Beispiel:
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
: Wird zum Importieren vordefinierter Typen verwendet. Mehr anzeigen{dataTypeName}
: Gibt den Namen des Moduls an. tableName
: Optionaler Name der Tabelle. Er verwendet den Snake_Case des dataTypeName
wenn dieser nicht definiert ist.
fields
: Listet alle Felder der Tabelle vom Typ Haskell auf. Mehr anzeigen
constraints
: PrimaryKey | Sekundärschlüssel | NichtNull | AUTOINKREMENT
importPackageOverrides
: Wird zum Überschreiben von Importpaketen verwendet. Weitere Informationen
types
: Benutzerdefinierte Typen, ähnlich den API-Typen. Mehr anzeigen
derives
: Überschreibt Ableitungen des Hauptdatentyps.
derives : " Show,Eq,Ord "
beamType
: Benutzerdefinierter Strahltyp für einen angegebenen Datentyp. Mehr anzeigen
beamFields
: Benutzerdefinierte Änderung des Strahlfeldnamens oder Verwendung, wenn Sie auf der Strahlseite etwas anderes haben möchten. Mehr anzeigen
beamInstance
: Wir können die benötigte Strahlinstanz angeben, indem wir dieses Feld Mehr anzeigen verwenden
sqlType
: Benutzerdefinierter SQL-Typ für ein Feld. Mehr anzeigen
default
: Standard-SQL-Wert für Felder, falls vorhanden
fields :
scheduleTryTimes : ' [Int] '
tripCategory : Text
default :
tripCategory : " 'All' "
scheduleTryTimes : " '{1800, 900, 300}' "
queries
: Alle Beam-Abfragen für die Tabelle. Mehr anzeigen
cachedQueries:
Zwischengespeicherte Abfragen für die Tabelle. Mehr anzeigen
fromTType
: FromTType der Felder, falls zutreffend. Mehr anzeigen
toTType
: ToTType der Felder, falls zutreffend. Mehr anzeigen
excludedFields
: Es gibt einige allgemeine Felder wie MerchantId, MerchantOperatingCityId, CreatedAt und UpdatedAt, die automatisch zum Datentyp hinzugefügt werden. Um sie zu entfernen, verwenden Sie dies.
excludedFields :
- merchantOperatingCityId
- merchantId
extraIndexes
: Alle zusätzlichen Indizes Weitere Informationen
extraOperations
: Zusätzliche Operationen Mehr anzeigen
Sie müssen den Modulnamen bei Importen angeben
imports :
Merchant : Domain.Types.Merchant
FRFSSearch : Domain.Types.FRFSSearch
Hinweis: Diese gängigen Typen werden automatisch importiert, sodass Sie sie ohne Import direkt verwenden können
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
So ändern Sie das Paket:
importPackageOverrides:
Domain.Types.DataType1: dashboard-api
Generierter Import in Haskell:
import "dashboard-api" Domain.Types.DataType1
Manchmal müssen wir möglicherweise die Paketüberschreibung überspringen, wenn wir im selben Paket generieren. Dann sollten wir die Paketzuordnung in dhall
-Konfigurationen angeben:
, _packageMapping =
[ { _1 = GeneratorType. API_TYPES , _2 = " dashboard-api " }
{ _1 = GeneratorType. SERVANT_API , _2 = " rider-app " }
]
Generierter Import in Haskell für API_TYPES
:
import "this" Domain.Types.DataType1
Generierter Import in Haskell für SERVANT_API
:
import "dashboard-api" Domain.Types.DataType1
Geben Sie im Feldabschnitt den Feldnamen und den entsprechenden Haskell-Typ an
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
Bei einfachen Feldtypen (die gerade importiert werden) wird es auch auf der Balkenseite kopiert, es sei denn, wir erwähnen einen bestimmten Balkentyp
Wenn das Feld ein komplexer Typ ist, wird es auf der Strahlseite rekursiv aufgeteilt, es sei denn, wir erwähnen einen spezifischen Strahltyp
Im Fall von Id, ShortId wird der Balkentyp als Text betrachtet
Wenn wir den Typ „Importierte Daten“ auf der Domänenseite und die entsprechende ID auf der Balkenseite wünschen, verwenden wir die WithId-Erweiterungen mit der Typdefinition.
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: Dies wird verwendet, wenn wir die ID des importierten Datentyps als Beam-Feld verwenden möchten. Dadurch wird der Datentyp in der Abfrage „Beam erstellen“ nicht erstellt.
WithCachedId: Wie WithId, der einzige Unterschied besteht darin, dass die Abfrage „create“ und „findbyId“ aus Storage.CachedQuery importiert wird.*
WithIdCreate , WithCachedIdCreate: Verwenden Sie dies, wenn es erforderlich ist, den Datentyp in der Erstellungsabfrage zu erstellen. Wichtig: Der importierte Datentyp sollte in der entsprechenden Abfragedatei über eine Erstellungsfunktion verfügen. Beispiel:
fields :
fareParams : Maybe FareParameters|WithIdCreate
farePolicy : Maybe FarePolicy|WithCachedId
Generierte Erstellungsabfrage:
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
Generierte ToTType- und FromTType-Konvertierungen:
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
}
Syntax:
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)
Syntax der Where-Klausel:
where:
- {operator1}:
- field1
- {operator2}:
- field2
- field3
- {operator3}:
- field4
- field5
Es gibt drei Arten von Feldern, die in Parametern und der Where-Klausel verwendet werden:
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
Liste der Where-Operatoren:
Beispiel:
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
Generierte Abfrage:
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
]