Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(cli): rewrite to effect-ts #40

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
refactor(cli): rewrite to effect-ts
  • Loading branch information
divyenduz committed Jan 15, 2024
commit 7ab65db239cce4f797045d25e53b6025761d60ac
Binary file modified bun.lockb
Binary file not shown.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"dependencies": {
"arg": "5.0.1",
"dotenv": "16.0.3",
"effect": "2.0.3",
"esbuild": "0.14.18",
"postgres": "3.3.3",
"tasuku": "2.0.1",
Expand All @@ -22,9 +23,9 @@
"@trivago/prettier-plugin-sort-imports": "3.2.0",
"@turf/distance": "6.5.0",
"@turf/helpers": "6.5.0",
"@types/bun": "1.0.1",
"@types/dotenv": "8.2.0",
"@types/node": "18.11.7",
"bun-types": "1.0.1",
"mathjs": "11.6.0",
"object-hash": "3.0.0",
"prettier": "2.5.1",
Expand Down
110 changes: 60 additions & 50 deletions src/commands/generate.ts
Original file line number Diff line number Diff line change
@@ -1,51 +1,61 @@
import fs from 'fs'

import { ParseCLI } from '../helpers/ParseCLI.js'
import { PLV8ifyCLI } from '../impl/PLV8ifyCLI.js'

export async function generateCommand(
CLI: ReturnType<typeof ParseCLI.getCommand>
) {
const {
bundler,
writeBundlerOutput,
inputFilePath,
outputFolderPath,
scopePrefix,
pgFunctionDelimiter,
fallbackReturnType,
mode,
defaultVolatility,
} = CLI.config

fs.mkdirSync(outputFolderPath, { recursive: true })

const plv8ify = new PLV8ifyCLI(bundler)
plv8ify.init(inputFilePath)

const bundledJs = await plv8ify.build({
mode,
inputFile: inputFilePath,
scopePrefix,
})

// Optionally, write ESBuild output file
if (writeBundlerOutput) {
plv8ify.write(`${outputFolderPath}/output.js`, bundledJs)
}

// Emit SQL files for each exported function in the input TS file
const sqlFiles = plv8ify.getPLV8SQLFunctions({
mode,
scopePrefix,
defaultVolatility,
bundledJs,
pgFunctionDelimiter,
fallbackReturnType,
outputFolder: outputFolderPath,
})

sqlFiles.forEach((sqlFile) => {
plv8ify.write(sqlFile.filename, sqlFile.sql)
})
import { Effect } from 'effect'
import { PLV8ify } from 'src/interfaces/PLV8ify.js'

import { Config } from '../helpers/ParseCLI.js'

export function generateCommand() {
const bundledJs = Effect.all([Config, PLV8ify]).pipe(
Effect.tap(([config, plv8ify]) => {
const commandConfig = config.getCommand()
const { inputFilePath } = commandConfig.config
plv8ify.init(inputFilePath)
}),
Effect.flatMap(([config, plv8ify]) => {
const commandConfig = config.getCommand()
const { mode, inputFilePath, scopePrefix } = commandConfig.config
const bundledJs = Effect.promise(() =>
plv8ify.build({
mode,
inputFile: inputFilePath,
scopePrefix,
})
)
return bundledJs
})
)

return bundledJs.pipe(
Effect.flatMap((bundledJs) => {
return Effect.all([Config, PLV8ify]).pipe(
Effect.flatMap(([config, plv8ify]) => {
const commandConfig = config.getCommand()
const {
mode,
scopePrefix,
defaultVolatility,
pgFunctionDelimiter,
fallbackReturnType,
outputFolderPath,
writeBundlerOutput,
} = commandConfig.config
const sqlFiles = plv8ify.getPLV8SQLFunctions({
mode,
scopePrefix,
defaultVolatility,
bundledJs,
pgFunctionDelimiter,
fallbackReturnType,
outputFolder: outputFolderPath,
})

return Effect.succeed({
writeBundlerOutput,
outputFolderPath,
sqlFiles,
bundledJs,
})
})
)
})
)
}
18 changes: 15 additions & 3 deletions src/commands/version.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
import { Effect } from 'effect'
import { createRequire } from 'module'

const require = createRequire(import.meta.url)

class VersionCmdError extends Error {
readonly _tag = 'VersionCmdError'
}

export function versionCommand() {
const pkg = require('../../package.json')
console.log(`Version: ${pkg.version}`)
process.exit(0)
return Effect.try({
try: () => {
// TODO: require can fail, this effect is not pure
const pkg = require('../../package.json')
console.log(`Version: ${pkg.version}`)
},
catch: (e) => {
return new VersionCmdError(`${e}`)
},
})
}
29 changes: 17 additions & 12 deletions src/helpers/ParseCLI.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import arg from 'arg'
import { Context, Layer } from 'effect'
import { Mode, Volatility } from 'src/interfaces/PLV8ify.js'

type Command = 'version' | 'generate' | 'deploy'
export type BundlerType = 'esbuild' | 'bun'

export class ParseCLI {
static getCommand() {
// CLI Args
Expand All @@ -22,11 +20,9 @@ export class ParseCLI {
})

if (args._.length === 0) {
ParseCLI.throwError(`
throw new Error(`
Please specify a command. Available commands: generate, version, deploy
`)
console.error()
process.exit(1)
}

const debug = args['--debug'] || false
Expand Down Expand Up @@ -57,11 +53,20 @@ Please specify a command. Available commands: generate, version, deploy
},
}
}
}

static throwError(message?: string) {
if (message) {
console.error(message)
}
process.exit(1)
}
type Command = 'version' | 'generate' | 'deploy'
export type BundlerType = 'esbuild' | 'bun'

export interface Config {
getCommand: () => ReturnType<typeof ParseCLI.getCommand>
}

export const Config = Context.Tag<Config>()

export const ConfigLive = Layer.succeed(
Config,
Config.of({
getCommand: ParseCLI.getCommand,
})
)
20 changes: 20 additions & 0 deletions src/helpers/Utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import fs from 'fs'

export function writeFile(filePath: string, content: string) {
try {
fs.unlinkSync(filePath)
} catch (e) {}
fs.writeFileSync(filePath, content)
}

type Runtime = 'node' | 'bun'

export function getRuntime(): Runtime {
if (typeof Bun !== 'undefined') {
return 'bun'
}
if (typeof process !== 'undefined') {
return 'node'
}
throw new Error('Unknown runtime')
}
8 changes: 4 additions & 4 deletions src/impl/PLV8ifyCLI.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { describe, expect, it } from 'bun:test'
import { TSFunction } from 'src/interfaces/TSCompiler'

import { PLV8ifyCLI } from './PLV8ifyCLI'
import { PLV8ifyCLIImpl } from './PLV8ifyCLI'

describe('PLV8ifyCLI tests', () => {
it('getSQLFunction with parameters', async () => {
const plv8ify = new PLV8ifyCLI()
const plv8ify = new PLV8ifyCLIImpl()
const sql = plv8ify.getPLV8SQLFunction({
fn: {
name: 'test',
Expand All @@ -23,7 +23,7 @@ describe('PLV8ifyCLI tests', () => {
})

it('getSQLFunction with delimiter', async () => {
const plv8ify = new PLV8ifyCLI()
const plv8ify = new PLV8ifyCLIImpl()
const sql = plv8ify.getPLV8SQLFunction({
fn: {
name: 'test',
Expand All @@ -42,7 +42,7 @@ describe('PLV8ifyCLI tests', () => {
})

it('getSQLFunction with parameters-trigger', async () => {
const plv8ify = new PLV8ifyCLI()
const plv8ify = new PLV8ifyCLIImpl()
const sql = plv8ify.getPLV8SQLFunction({
fn: {
name: 'test',
Expand Down
34 changes: 21 additions & 13 deletions src/impl/PLV8ifyCLI.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import fs, { Mode } from 'fs'
import { Layer } from 'effect'
import { Mode } from 'fs'
import { BundlerType } from 'src/helpers/ParseCLI.js'
import { Bundler } from 'src/interfaces/Bundler.js'
import {
Expand Down Expand Up @@ -35,7 +36,7 @@ interface GetInitSQLFunctionArgs {
volatility: Volatility
}

export class PLV8ifyCLI implements PLV8ify {
export class PLV8ifyCLIImpl implements PLV8ify {
private _bundler: Bundler
private _tsCompiler: TSCompiler

Expand Down Expand Up @@ -82,17 +83,6 @@ export class PLV8ifyCLI implements PLV8ify {
return modeAdjustedBundledJs
}

private writeFile(filePath: string, content: string) {
try {
fs.unlinkSync(filePath)
} catch (e) {}
fs.writeFileSync(filePath, content)
}

write(path: string, string: string) {
this.writeFile(path, string)
}

private getScopedName(fn: TSFunction, scopePrefix: string) {
const scopedName = scopePrefix + '_' + fn.name
return scopedName
Expand Down Expand Up @@ -297,3 +287,21 @@ SET plv8.start_proc = ${scopePrefix}_init;
SELECT plv8_reset();
`
}

// TODO: this should be lazily evaluated
const plv8ify = new PLV8ifyCLIImpl()

export const PLV8ifyCLILive = Layer.succeed(
PLV8ify,
PLV8ify.of({
init: (inputFilePath: string) => {
return plv8ify.init(inputFilePath)
},
build: (args) => {
return plv8ify.build(args)
},
getPLV8SQLFunctions: (args) => {
return plv8ify.getPLV8SQLFunctions(args)
},
})
)
47 changes: 32 additions & 15 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,14 @@
#!/usr/bin/env node
import { Effect, Layer } from 'effect'
import fs from 'fs'
import { match } from 'ts-pattern'

import { deployCommand } from './commands/deploy.js'
import { generateCommand } from './commands/generate.js'
import { versionCommand } from './commands/version.js'
import { ParseCLI } from './helpers/ParseCLI.js'

type Runtime = 'node' | 'bun'

function getRuntime(): Runtime {
if (typeof Bun !== 'undefined') {
return 'bun'
}
if (typeof process !== 'undefined') {
return 'node'
}
throw new Error('Unknown runtime')
}
import { Config, ConfigLive, ParseCLI } from './helpers/ParseCLI.js'
import { getRuntime, writeFile } from './helpers/Utils.js'
import { PLV8ifyCLILive } from './impl/PLV8ifyCLI.js'

async function main() {
const runtime = getRuntime()
Expand All @@ -32,10 +24,35 @@ async function main() {

match(CLI.command)
.with('version', () => {
versionCommand()
const program = versionCommand()
Effect.runSync(program)
})
.with('generate', async () => {
await generateCommand(CLI)
const program = await generateCommand()
const runnable = await Effect.provide(
program,
Layer.merge(ConfigLive, PLV8ifyCLILive)
)
runnable.pipe(
Effect.tap(
({ outputFolderPath, writeBundlerOutput, sqlFiles, bundledJs }) => {
fs.mkdirSync(outputFolderPath, { recursive: true })

if (writeBundlerOutput) {
writeFile(`${outputFolderPath}/output.js`, bundledJs)
}
sqlFiles.forEach((sqlFile) => {
writeFile(sqlFile.filename, sqlFile.sql)
})
process.exit(0)
}
),
Effect.catchAll((e) => {
console.error(e)
process.exit(1)
}),
Effect.runPromise
)
})
.with('deploy', async () => {
await deployCommand(CLI)
Expand Down
Loading
Loading