Это руководство представляет собой подробное руководство по пониманию и работе с предметно-ориентированным языком (NammaDSL) в Намма-Ятри. Он охватывает создание файлов YAML, генерацию и компиляцию кода, а также синтаксис для определения API и хранилища.
Расположение : создайте файл 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
: указывает имя модуля.
Примечание. В случае API панели мониторинга все API в модуле имеют один и тот же префикс API, по умолчанию module
преобразуется в верблюжий регистр.
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}
Типы перечислений могут быть определены как:
{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
: мы можем указать экземпляр луча, который нам нужен, используя это поле.
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 тип луча будет считаться текстовым.
Если нам нужен тип импортируемых данных на стороне домена и соответствующий идентификатор на стороне луча, мы используем расширения 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, с той лишь разницей, что запросы 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
Поля, которые используются в параметрах и предложении, могут быть трех типов:
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
]