Skip to content

Commit

Permalink
Optimized multisort
Browse files Browse the repository at this point in the history
  • Loading branch information
justinwilaby committed Apr 16, 2024
1 parent ee17240 commit 6271fee
Show file tree
Hide file tree
Showing 6 changed files with 36 additions and 34 deletions.
4 changes: 2 additions & 2 deletions packages/cli/src/commands/pg/reset.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import color from '@heroku-cli/color'
import {Command, flags} from '@heroku-cli/command'
import {Args, ux} from '@oclif/core'
import confirmCommand from '../../lib/confirmCommand'
import pgHost from '../../lib/pg/host'
import {getAddon} from '../../lib/pg/fetcher'
import confirmApp from '../../lib/apps/confirm-app'
import heredoc from 'tsheredoc'

export default class Reset extends Command {
Expand Down Expand Up @@ -32,7 +32,7 @@ export default class Reset extends Command {
.sort()
}

await confirmApp(app, confirm, heredoc(`
await confirmCommand(app, confirm, heredoc(`
Destructive action
${color.addon(db.name)} will lose all of its data
`))
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/src/commands/spaces/destroy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import color from '@heroku-cli/color'
import {Command, flags} from '@heroku-cli/command'
import * as Heroku from '@heroku-cli/schema'
import heredoc from 'tsheredoc'
import confirmApp from '../../lib/apps/confirm-app'
import confirmCommand from '../../lib/confirmCommand'
import {displayNat} from '../../lib/spaces/spaces'

type RequiredSpaceWithNat = Required<Heroku.Space> & {outbound_ips?: Required<Heroku.SpaceNetworkAddressTranslation>}
Expand Down Expand Up @@ -47,7 +47,7 @@ export default class Destroy extends Command {
}
}

await confirmApp(
await confirmCommand(
spaceName as string,
confirm,
`Destructive Action\nThis command will destroy the space ${color.bold.red(spaceName as string)}\n${natWarning}\n`,
Expand Down
8 changes: 4 additions & 4 deletions packages/cli/src/lib/pg/bastion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,16 @@ export const env = (db: ReturnType<typeof getConnectionDetails>) => {
return baseEnv
}

export function tunnelConfig(db: ReturnType<typeof getConnectionDetails>) {
export function tunnelConfig(db: ReturnType<typeof getConnectionDetails>): createTunnel.Config {
const localHost = '127.0.0.1'
// eslint-disable-next-line no-mixed-operators
const localPort = Math.floor(Math.random() * (65535 - 49152) + 49152)
return {
username: 'bastion',
host: db.bastionHost,
privateKey: db.bastionKey,
dstHost: db.host,
dstPort: Number.parseInt(db.port, 10),
dstHost: db.host || undefined,
dstPort: (db.port && Number.parseInt(db.port as string, 10)) || undefined,
localHost: localHost,
localPort: localPort,
}
Expand Down Expand Up @@ -102,7 +102,7 @@ class Timeout {
}
}

export async function sshTunnel(db: ReturnType<typeof getConnectionDetails>, dbTunnelConfig: ReturnType<typeof tunnelConfig>, timeout = 10000) {
export async function sshTunnel(db: ReturnType<typeof getConnectionDetails>, dbTunnelConfig: createTunnel.Config, timeout = 10000) {
if (!db.bastionKey) {
return null
}
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/lib/pg/fetcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ export async function getAddon(heroku: APIClient, app: string, db = 'DATABASE_UR
}

export async function database(heroku: APIClient, app: string, db?: string, namespace?: string) {
const attached = await attachment(heroku, app, db, namespace)
const attached = await getAttachment(heroku, app, db, namespace)

// would inline this as well but in some cases attachment pulls down config
// as well, and we would request twice at the same time but I did not want
Expand Down
40 changes: 19 additions & 21 deletions packages/cli/src/lib/pg/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import color from '@heroku-cli/color'
import type {AddOnAttachment} from '@heroku-cli/schema'
import {ux} from '@oclif/core'
import debug from 'debug'
import {parse} from 'url'
import {renderAttachment} from '../../commands/addons'
import {multiSortCompareFn} from '../utils/multisort'
import {getBastion} from './bastion'
import type {AddOnAttachmentWithConfigVarsAndPlan} from './types'
import type {AddOnAttachmentWithConfigVarsAndPlan, CredentialsInfo} from './types'
import {env} from 'process'

export function getConfigVarName(configVars: string[]): string {
Expand Down Expand Up @@ -114,7 +115,7 @@ export const getConnectionDetails = (attachment: Required<AddOnAttachment & {
const conn = parsePostgresConnectionString(config[connstringVar])

const payload = {
user: conn.username,
user: conn.user,
password: conn.password,
database: conn.database,
host: conn.hostname,
Expand Down Expand Up @@ -173,27 +174,24 @@ export const databaseNameFromUrl = (uri: string, config: Record<string, string>)
return color.configVar(name.replace(/_URL$/, ''))
}

const conn = exports.parsePostgresConnectionString(uri)
const conn = parsePostgresConnectionString(uri)
return `${conn.host}:${conn.port}${conn.pathname}`
}

export const parsePostgresConnectionString = (db: string): Omit<URL, 'toString' | 'toJSON' | 'searchParams' | 'hash' | 'search'> & {database: string | null} => {
const dbUrl = new URL(db.match(/:\/\//) ? db : `postgres:///${db}`)
const databaseName = dbUrl.pathname || null
let database: string | null
if (databaseName && databaseName.charAt(0) === '/') {
database = databaseName.slice(1) || null
} else {
database = databaseName
export const parsePostgresConnectionString = (db: string) => {
const dbPath = db.match(/:\/\//) ? db : `postgres:///${db}`
const parsedURL = parse(dbPath)
const {auth, hostname, pathname, port} = parsedURL
const [user, password] = auth ? auth.split(':') : []
const databaseName = pathname && pathname.charAt(0) === '/' ?
pathname.slice(1) || null :
pathname
return {
...parsedURL,
user,
password,
database: databaseName,
host: hostname,
port: hostname ? port || env.PGPORT || 5432 : port || env.PGPORT,
}

dbUrl.port = dbUrl.port || env.PGPORT
if (dbUrl.hostname) {
dbUrl.port = dbUrl.port || '5432'
}

// Strange behavior in that we cannot spread the
// props of a URL. i.e. {...dbUrl, database} does not work
const {pathname, host, port, password, username, hostname, href, origin, protocol} = dbUrl
return {pathname, host, port, password, username, hostname, href, origin, protocol, database}
}
12 changes: 8 additions & 4 deletions packages/cli/src/lib/utils/multisort.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,8 @@ export function multiSortCompareFn(comparators: Comparator[]): Comparator {
const bitLen = comparators.length - 1
let bitA = 0
let bitB = 0

comparators.forEach((comparator, index) => {
const priority = 1 << (bitLen - index)
for (const [i, comparator] of comparators.entries()) {
const priority = 1 << (bitLen - i)
const score = comparator?.(a, b)
if (score === -1) {
bitA |= priority
Expand All @@ -56,7 +55,12 @@ export function multiSortCompareFn(comparators: Comparator[]): Comparator {
if (score === 1) {
bitB |= priority
}
})

if (bitA !== bitB) {
break
}
}

return bitA > bitB ? -1 : (bitA < bitB ? 1 : 0)
}
}
Expand Down

0 comments on commit 6271fee

Please sign in to comment.