Skip to content

Commit

Permalink
feat(typegen): Go Type Gen (#687)
Browse files Browse the repository at this point in the history
* feat(typegen): add route for go

* feat(typegen): cleanup server.ts and set up local typegen for go

* feat(typegen): create go table structs

* feat(typegen): create go view/matview structs

* feat(typegen): create go composite type structs

* feat(typegen): go: handle range types

* feat(typegen): go: test

* feat(typegen): go: format

* feat(typegen): separate go types by operation and add nullable types

* feat(typegen): go: format

* feat(typegen): go: handle empty tables

* chore: update snapshot

---------

Co-authored-by: Bobbie Soedirgo <[email protected]>
  • Loading branch information
isaacharrisholt and soedirgo committed May 24, 2024
1 parent e49ebcd commit 9b6a6af
Show file tree
Hide file tree
Showing 7 changed files with 1,097 additions and 5 deletions.
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,14 @@ To start developing, run `npm run dev`. It will set up the database with Docker

If you are fixing a bug, you should create a new test case. To test your changes, add the `-u` flag to `vitest` on the `test:run` script, run `npm run test`, and then review the git diff of the snapshots. Depending on your change, you may see `id` fields being changed - this is expected and you are free to commit it, as long as it passes the CI. Don't forget to remove the `-u` flag when committing.

To make changes to the TypeScript type generation, run `npm run gen:types:typescript` while you have `npm run dev` running.
To make changes to the type generation, run `npm run gen:types:<lang>` while you have `npm run dev` running,
where `<lang>` is one of:

- `typescript`
- `go`

To use your own database connection string instead of the provided test database, run:
`PG_META_DB_URL=postgresql://postgres:postgres@localhost:5432/postgres npm run gen:types:typescript`
`PG_META_DB_URL=postgresql://postgres:postgres@localhost:5432/postgres npm run gen:types:<lang>`

## Licence

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"build": "tsc -p tsconfig.json && cpy 'src/lib/sql/*.sql' dist/lib/sql",
"docs:export": "PG_META_EXPORT_DOCS=true node --loader ts-node/esm src/server/server.ts > openapi.json",
"gen:types:typescript": "PG_META_GENERATE_TYPES=typescript node --loader ts-node/esm src/server/server.ts",
"gen:types:go": "PG_META_GENERATE_TYPES=go node --loader ts-node/esm src/server/server.ts",
"start": "node dist/server/server.js",
"dev": "trap 'npm run db:clean' INT && run-s db:clean db:run && nodemon --exec node --loader ts-node/esm src/server/server.ts | pino-pretty --colorize",
"test": "run-s db:clean db:run test:run db:clean",
Expand Down
35 changes: 35 additions & 0 deletions src/server/routes/generators/go.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import type { FastifyInstance } from 'fastify'
import { PostgresMeta } from '../../../lib/index.js'
import { DEFAULT_POOL_CONFIG } from '../../constants.js'
import { extractRequestForLogging } from '../../utils.js'
import { apply as applyGoTemplate } from '../../templates/go.js'
import { getGeneratorMetadata } from '../../../lib/generators.js'

export default async (fastify: FastifyInstance) => {
fastify.get<{
Headers: { pg: string }
Querystring: {
excluded_schemas?: string
included_schemas?: string
}
}>('/', async (request, reply) => {
const connectionString = request.headers.pg
const excludedSchemas =
request.query.excluded_schemas?.split(',').map((schema) => schema.trim()) ?? []
const includedSchemas =
request.query.included_schemas?.split(',').map((schema) => schema.trim()) ?? []

const pgMeta: PostgresMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString })
const { data: generatorMeta, error: generatorMetaError } = await getGeneratorMetadata(pgMeta, {
includedSchemas,
excludedSchemas,
})
if (generatorMetaError) {
request.log.error({ error: generatorMetaError, request: extractRequestForLogging(request) })
reply.code(500)
return { error: generatorMetaError.message }
}

return applyGoTemplate(generatorMeta)
})
}
6 changes: 4 additions & 2 deletions src/server/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ import TablesRoute from './tables.js'
import TriggersRoute from './triggers.js'
import TypesRoute from './types.js'
import ViewsRoute from './views.js'
import TypeGenRoute from './generators/typescript.js'
import TypeScriptTypeGenRoute from './generators/typescript.js'
import GoTypeGenRoute from './generators/go.js'
import { PG_CONNECTION, CRYPTO_KEY } from '../constants.js'

export default async (fastify: FastifyInstance) => {
Expand Down Expand Up @@ -62,5 +63,6 @@ export default async (fastify: FastifyInstance) => {
fastify.register(TriggersRoute, { prefix: '/triggers' })
fastify.register(TypesRoute, { prefix: '/types' })
fastify.register(ViewsRoute, { prefix: '/views' })
fastify.register(TypeGenRoute, { prefix: '/generators/typescript' })
fastify.register(TypeScriptTypeGenRoute, { prefix: '/generators/typescript' })
fastify.register(GoTypeGenRoute, { prefix: '/generators/go' })
}
38 changes: 38 additions & 0 deletions src/server/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import {
PG_META_PORT,
} from './constants.js'
import { apply as applyTypescriptTemplate } from './templates/typescript.js'
import { apply as applyGoTemplate } from './templates/go.js'
import { getGeneratorMetadata } from '../lib/generators.js'

const logger = pino({
formatters: {
Expand All @@ -27,6 +29,37 @@ const logger = pino({
const app = buildApp({ logger })
const adminApp = buildAdminApp({ logger })

async function getTypeOutput(): Promise<string | null> {
const pgMeta: PostgresMeta = new PostgresMeta({
...DEFAULT_POOL_CONFIG,
connectionString: PG_CONNECTION,
})
const { data: generatorMetadata, error: generatorMetadataError } = await getGeneratorMetadata(
pgMeta,
{
includedSchemas: GENERATE_TYPES_INCLUDED_SCHEMAS,
}
)
if (generatorMetadataError) {
throw new Error(generatorMetadataError.message)
}

let output: string | null = null
switch (GENERATE_TYPES) {
case 'typescript':
output = await applyTypescriptTemplate({
...generatorMetadata,
detectOneToOneRelationships: GENERATE_TYPES_DETECT_ONE_TO_ONE_RELATIONSHIPS,
})
break
case 'go':
output = applyGoTemplate(generatorMetadata)
break
}

return output
}

if (EXPORT_DOCS) {
// TODO: Move to a separate script.
await app.ready()
Expand Down Expand Up @@ -154,3 +187,8 @@ if (EXPORT_DOCS) {
adminApp.listen({ port: adminPort, host: PG_META_HOST })
})
}

app.listen({ port: PG_META_PORT, host: PG_META_HOST }, () => {
const adminPort = PG_META_PORT + 1
adminApp.listen({ port: adminPort, host: PG_META_HOST })
})
Loading

0 comments on commit 9b6a6af

Please sign in to comment.