Skip to content

Commit

Permalink
feat: add ignore http method support
Browse files Browse the repository at this point in the history
  • Loading branch information
ivan-tymoshenko committed Mar 6, 2023
1 parent 9ba1ea4 commit 7f43d73
Show file tree
Hide file tree
Showing 6 changed files with 434 additions and 243 deletions.
3 changes: 2 additions & 1 deletion packages/sql-openapi/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ async function setupOpenAPI (app, opts) {
})

for (const entity of Object.values(app.platformatic.entities)) {
const entitySchema = mapSQLEntityToJSONSchema(entity, ignore[entity.pluralName])
const ignoredFields = ignore[entity.pluralName]?.fields
const entitySchema = mapSQLEntityToJSONSchema(entity, ignoredFields)
// TODO remove reverseRelationships from the entity
/* istanbul ignore next */
entity.reverseRelationships = entity.reverseRelationships || []
Expand Down
143 changes: 77 additions & 66 deletions packages/sql-openapi/lib/entity-to-routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,66 +41,71 @@ const getEntityLinksForEntity = (app, entity) => {

async function entityPlugin (app, opts) {
const entity = opts.entity
const ignore = opts.ignore
const ignoredFields = opts.ignore.fields || []
const ignoredMethods = opts.ignore.methods || []

const entitySchema = {
$ref: entity.name + '#'
}
const primaryKey = entity.primaryKeys.values().next().value
const primaryKeyParams = getPrimaryKeyParams(entity, ignore)
const primaryKeyParams = getPrimaryKeyParams(entity, ignoredFields)
const primaryKeyCamelcase = camelcase(primaryKey)
const entityLinks = getEntityLinksForEntity(app, entity)

const { whereArgs, orderByArgs } = generateArgs(entity, ignore)
const { whereArgs, orderByArgs } = generateArgs(entity, ignoredFields)

app.addHook('preValidation', async (req) => {
if (typeof req.query.fields === 'string') {
req.query.fields = req.query.fields.split(',')
}
})

const fields = getFieldsForEntity(entity, ignore)
const fields = getFieldsForEntity(entity, ignoredFields)

rootEntityRoutes(app, entity, whereArgs, orderByArgs, entityLinks, entitySchema, fields)
rootEntityRoutes(app, entity, whereArgs, orderByArgs, entityLinks, entitySchema, fields, ignoredMethods)

app.get(`/:${primaryKeyCamelcase}`, {
schema: {
operationId: `get${entity.name}By${capitalize(primaryKeyCamelcase)}`,
params: primaryKeyParams,
querystring: {
type: 'object',
properties: {
fields
if (!ignoredMethods.includes('GET')) {
app.get(`/:${primaryKeyCamelcase}`, {
schema: {
operationId: `get${entity.name}By${capitalize(primaryKeyCamelcase)}`,
params: primaryKeyParams,
querystring: {
type: 'object',
properties: {
fields
}
},
response: {
200: entitySchema
}
},
response: {
200: entitySchema
links: {
200: entityLinks
}
},
links: {
200: entityLinks
}
}, async function (request, reply) {
const ctx = { app: this, reply }
const res = await entity.find({
ctx,
where: {
[primaryKeyCamelcase]: {
eq: request.params[primaryKeyCamelcase]
}
},
fields: request.query.fields
}, async function (request, reply) {
const ctx = { app: this, reply }
const res = await entity.find({
ctx,
where: {
[primaryKeyCamelcase]: {
eq: request.params[primaryKeyCamelcase]
}
},
fields: request.query.fields
})
if (res.length === 0) {
return reply.callNotFound()
}
return res[0]
})
if (res.length === 0) {
return reply.callNotFound()
}
return res[0]
})
}

const mapRoutePathNamesReverseRelations = new Map()
let idxRoutePathNamesReverseRelations = 1
// For every reverse relationship we create: entity/:entity_Id/target_entity
for (const reverseRelationship of entity.reverseRelationships) {
if (ignoredMethods.includes('GET')) continue

const targetEntityName = reverseRelationship.relation.entityName
const targetEntity = app.platformatic.entities[targetEntityName]
const targetForeignKeyCamelcase = camelcase(reverseRelationship.relation.column_name)
Expand All @@ -126,11 +131,11 @@ async function entityPlugin (app, opts) {
app.get(`/:${camelcase(primaryKey)}/${routePathName}`, {
schema: {
operationId,
params: getPrimaryKeyParams(entity, ignore),
params: getPrimaryKeyParams(entity, ignoredFields),
querystring: {
type: 'object',
properties: {
fields: getFieldsForEntity(targetEntity, ignore)
fields: getFieldsForEntity(targetEntity, ignoredFields)
}
},
response: {
Expand Down Expand Up @@ -190,6 +195,8 @@ async function entityPlugin (app, opts) {
let idxRoutePathNamesRelations = 1
// For every relationship we create: entity/:entity_Id/target_entity
for (const relation of entity.relations) {
if (ignoredMethods.includes('GET')) continue

const targetEntityName = relation.foreignEntityName
const targetEntity = app.platformatic.entities[targetEntityName]
const targetForeignKeyCamelcase = camelcase(relation.foreign_column_name)
Expand All @@ -215,11 +222,11 @@ async function entityPlugin (app, opts) {
app.get(`/:${camelcase(primaryKey)}/${targetRelation}`, {
schema: {
operationId,
params: getPrimaryKeyParams(entity, ignore),
params: getPrimaryKeyParams(entity, ignoredFields),
querystring: {
type: 'object',
properties: {
fields: getFieldsForEntity(targetEntity, ignore)
fields: getFieldsForEntity(targetEntity, ignoredFields)
}
},
response: {
Expand Down Expand Up @@ -269,6 +276,8 @@ async function entityPlugin (app, opts) {
}

for (const method of ['POST', 'PUT']) {
if (ignoredMethods.includes(method)) continue

app.route({
url: `/:${primaryKeyCamelcase}`,
method,
Expand Down Expand Up @@ -310,43 +319,45 @@ async function entityPlugin (app, opts) {
})
}

app.delete(`/:${primaryKeyCamelcase}`, {
schema: {
params: primaryKeyParams,
querystring: {
type: 'object',
properties: {
fields
if (!ignoredMethods.includes('DELETE')) {
app.delete(`/:${primaryKeyCamelcase}`, {
schema: {
params: primaryKeyParams,
querystring: {
type: 'object',
properties: {
fields
}
},
response: {
200: entitySchema
}
},
response: {
200: entitySchema
}
}
}, async function (request, reply) {
const ctx = { app: this, reply }
const res = await entity.delete({
ctx,
where: {
[primaryKeyCamelcase]: {
eq: request.params[primaryKeyCamelcase]
}
},
fields: request.query.fields
}, async function (request, reply) {
const ctx = { app: this, reply }
const res = await entity.delete({
ctx,
where: {
[primaryKeyCamelcase]: {
eq: request.params[primaryKeyCamelcase]
}
},
fields: request.query.fields
})
if (res.length === 0) {
return reply.callNotFound()
}
return res[0]
})
if (res.length === 0) {
return reply.callNotFound()
}
return res[0]
})
}
}

function getPrimaryKeyParams (entity, ignore) {
function getPrimaryKeyParams (entity, ignoredFields) {
const primaryKey = entity.primaryKeys.values().next().value
const fields = entity.fields
const field = fields[primaryKey]
const properties = {
[field.camelcase]: { type: mapSQLTypeToOpenAPIType(field.sqlType, ignore) }
[field.camelcase]: { type: mapSQLTypeToOpenAPIType(field.sqlType, ignoredFields) }
}
const required = [field.camelcase]

Expand Down
119 changes: 63 additions & 56 deletions packages/sql-openapi/lib/many-to-many.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,20 @@ const { generateArgs, capitalize, getFieldsForEntity, rootEntityRoutes } = requi

async function entityPlugin (app, opts) {
const entity = opts.entity
const ignore = opts.ignore
const ignoredFields = opts.ignore.fields || []
const ignoredMethods = opts.ignore.methods || []

const entitySchema = {
$ref: entity.name + '#'
}
const primaryKeysParams = getPrimaryKeysParams(entity)
const primaryKeysCamelcase = Array.from(entity.primaryKeys).map((key) => camelcase(key))

const { whereArgs, orderByArgs } = generateArgs(entity, ignore)
const { whereArgs, orderByArgs } = generateArgs(entity, ignoredFields)

const fields = getFieldsForEntity(entity, ignore)
const fields = getFieldsForEntity(entity, ignoredFields)

rootEntityRoutes(app, entity, whereArgs, orderByArgs, undefined, entitySchema, fields)
rootEntityRoutes(app, entity, whereArgs, orderByArgs, undefined, entitySchema, fields, ignoredMethods)

let pathWithParams = ''

Expand All @@ -39,37 +40,41 @@ async function entityPlugin (app, opts) {
return acc + capitalize(key)
}, '')

app.get(pathWithParams, {
schema: {
operationId: `get${entity.name}By${operationName}`,
params: primaryKeysParams,
querystring: {
type: 'object',
properties: {
fields
if (!ignoredMethods.includes('GET')) {
app.get(pathWithParams, {
schema: {
operationId: `get${entity.name}By${operationName}`,
params: primaryKeysParams,
querystring: {
type: 'object',
properties: {
fields
}
},
response: {
200: entitySchema
}
},
response: {
200: entitySchema
}
}
}, async function (request, reply) {
const ctx = { app: this, reply }
const res = await entity.find({
ctx,
where: primaryKeysCamelcase.reduce((acc, key) => {
acc[key] = { eq: request.params[key] }
return acc
}, {}),
fields: request.query.fields
}, async function (request, reply) {
const ctx = { app: this, reply }
const res = await entity.find({
ctx,
where: primaryKeysCamelcase.reduce((acc, key) => {
acc[key] = { eq: request.params[key] }
return acc
}, {}),
fields: request.query.fields
})
if (res.length === 0) {
return reply.callNotFound()
}
return res[0]
})
if (res.length === 0) {
return reply.callNotFound()
}
return res[0]
})
}

for (const method of ['POST', 'PUT']) {
if (ignoredMethods.includes(method)) continue

app.route({
url: pathWithParams,
method,
Expand Down Expand Up @@ -114,35 +119,37 @@ async function entityPlugin (app, opts) {
})
}

app.delete(pathWithParams, {
schema: {
params: primaryKeysParams,
querystring: {
type: 'object',
properties: {
fields
if (!ignoredMethods.includes('DELETE')) {
app.delete(pathWithParams, {
schema: {
params: primaryKeysParams,
querystring: {
type: 'object',
properties: {
fields
}
},
response: {
200: entitySchema
}
},
response: {
200: entitySchema
}
}
}, async function (request, reply) {
const ids = primaryKeysCamelcase.map((key) => { return { key, value: request.params[key] } })
const ctx = { app: this, reply }
const res = await entity.delete({
ctx,
where: ids.reduce((acc, { key, value }) => {
acc[key] = { eq: value }
return acc
}, {}),
fields: request.query.fields
}, async function (request, reply) {
const ids = primaryKeysCamelcase.map((key) => { return { key, value: request.params[key] } })
const ctx = { app: this, reply }
const res = await entity.delete({
ctx,
where: ids.reduce((acc, { key, value }) => {
acc[key] = { eq: value }
return acc
}, {}),
fields: request.query.fields
})
if (res.length === 0) {
return reply.callNotFound()
}
return res[0]
})
if (res.length === 0) {
return reply.callNotFound()
}
return res[0]
})
}
}

function getPrimaryKeysParams (entity) {
Expand Down
Loading

0 comments on commit 7f43d73

Please sign in to comment.