Skip to content

Commit 7b932e9

Browse files
authored
Split pgroll latest (#861)
Split pgroll latest into - pgroll latest migration - pgroll latest schema ![CleanShot 2025-05-28 at 20 11 54@2x](https://github.com/user-attachments/assets/6cf28af5-0bf5-4af0-8e90-264b1d953f02) Fix #845 Amp: https://ampcode.com/threads/T-51521447-5949-4653-bc50-d7c846a27757
1 parent 21589af commit 7b932e9

File tree

4 files changed

+148
-56
lines changed

4 files changed

+148
-56
lines changed

cli-definition.json

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -96,24 +96,44 @@
9696
},
9797
{
9898
"name": "latest",
99-
"short": "Print the name of the latest schema version, either in the target database or a local directory",
99+
"short": "Print the name of the latest schema version or migration",
100100
"use": "latest",
101-
"example": "latest --local ./migrations",
102-
"flags": [
101+
"example": "",
102+
"flags": [],
103+
"subcommands": [
103104
{
104-
"name": "local",
105-
"shorthand": "l",
106-
"description": "retrieve the latest version from a local migration directory",
107-
"default": ""
105+
"name": "migration",
106+
"short": "Print the latest migration name (without schema prefix)",
107+
"use": "migration",
108+
"example": "latest migration --local ./migrations",
109+
"flags": [
110+
{
111+
"name": "local",
112+
"shorthand": "l",
113+
"description": "retrieve the latest version from a local migration directory",
114+
"default": ""
115+
}
116+
],
117+
"subcommands": [],
118+
"args": []
108119
},
109120
{
110-
"name": "with-schema",
111-
"shorthand": "s",
112-
"description": "prefix the version with the schema name",
113-
"default": "false"
121+
"name": "schema",
122+
"short": "Print the latest schema version (migration name prefixed with schema)",
123+
"use": "schema",
124+
"example": "latest schema --local ./migrations",
125+
"flags": [
126+
{
127+
"name": "local",
128+
"shorthand": "l",
129+
"description": "retrieve the latest version from a local migration directory",
130+
"default": ""
131+
}
132+
],
133+
"subcommands": [],
134+
"args": []
114135
}
115136
],
116-
"subcommands": [],
117137
"args": []
118138
},
119139
{

cmd/latest.go

Lines changed: 60 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,29 +13,33 @@ import (
1313
)
1414

1515
func latestCmd() *cobra.Command {
16-
var withSchema bool
16+
withSchema := true
17+
latestCmd := &cobra.Command{
18+
Use: "latest",
19+
Short: "Print the name of the latest schema version or migration",
20+
Long: "Print the name of the latest schema version or migration, either in the target database or a local directory",
21+
}
22+
23+
latestCmd.AddCommand(latestSchemaCmd(withSchema))
24+
latestCmd.AddCommand(latestMigrationCmd(!withSchema))
25+
26+
return latestCmd
27+
}
28+
29+
func latestSchemaCmd(withSchema bool) *cobra.Command {
1730
var migrationsDir string
1831

19-
latestCmd := &cobra.Command{
20-
Use: "latest",
21-
Short: "Print the name of the latest schema version, either in the target database or a local directory",
22-
Example: "latest --local ./migrations",
32+
schemaCmd := &cobra.Command{
33+
Use: "schema",
34+
Short: "Print the latest schema version (migration name prefixed with schema)",
35+
Example: "latest schema --local ./migrations",
2336
Args: cobra.NoArgs,
2437
RunE: func(cmd *cobra.Command, args []string) error {
2538
ctx := cmd.Context()
2639

27-
var latestVersion string
28-
var err error
29-
if migrationsDir != "" {
30-
latestVersion, err = latestVersionLocal(ctx, migrationsDir, withSchema)
31-
if err != nil {
32-
return fmt.Errorf("failed to get latest version from directory %q: %w", migrationsDir, err)
33-
}
34-
} else {
35-
latestVersion, err = latestVersionRemote(ctx, withSchema)
36-
if err != nil {
37-
return fmt.Errorf("failed to get latest version from database: %w", err)
38-
}
40+
latestVersion, err := getLatestVersion(ctx, migrationsDir, withSchema)
41+
if err != nil {
42+
return fmt.Errorf("failed to get latest version from database: %w", err)
3943
}
4044

4145
fmt.Println(latestVersion)
@@ -44,10 +48,46 @@ func latestCmd() *cobra.Command {
4448
},
4549
}
4650

47-
latestCmd.Flags().BoolVarP(&withSchema, "with-schema", "s", false, "prefix the version with the schema name")
48-
latestCmd.Flags().StringVarP(&migrationsDir, "local", "l", "", "retrieve the latest version from a local migration directory")
51+
schemaCmd.Flags().StringVarP(&migrationsDir, "local", "l", "", "retrieve the latest version from a local migration directory")
4952

50-
return latestCmd
53+
return schemaCmd
54+
}
55+
56+
func latestMigrationCmd(withSchema bool) *cobra.Command {
57+
var migrationsDir string
58+
59+
migrationCmd := &cobra.Command{
60+
Use: "migration",
61+
Short: "Print the latest migration name (without schema prefix)",
62+
Example: "latest migration --local ./migrations",
63+
Args: cobra.NoArgs,
64+
RunE: func(cmd *cobra.Command, args []string) error {
65+
ctx := cmd.Context()
66+
67+
latestVersion, err := getLatestVersion(ctx, migrationsDir, withSchema)
68+
if err != nil {
69+
return fmt.Errorf("failed to get latest version from database: %w", err)
70+
}
71+
72+
fmt.Println(latestVersion)
73+
74+
return nil
75+
},
76+
}
77+
78+
migrationCmd.Flags().StringVarP(&migrationsDir, "local", "l", "", "retrieve the latest version from a local migration directory")
79+
80+
return migrationCmd
81+
}
82+
83+
// getLatestVersion returns the latest migration version from a local
84+
// migrations directory or remote database, optionally prepending the schema
85+
// name to which the migration is applied.
86+
func getLatestVersion(ctx context.Context, migrationsDir string, withSchema bool) (string, error) {
87+
if migrationsDir != "" {
88+
return latestVersionLocal(ctx, migrationsDir, withSchema)
89+
}
90+
return latestVersionRemote(ctx, withSchema)
5191
}
5292

5393
// latestVersionLocal returns the latest migration version from a local

docs/cli/latest.mdx

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,75 @@
11
---
22
title: Latest
3-
description: Prints the latest schema version in either the target database or a local directory of migration files.
3+
description: Prints the latest schema version or migration name in either the target database or a local directory of migration files.
44
---
55

66
## Command
77

8-
By default, `pgroll latest` prints the latest version in the target database. Use the `--local` flag to print the latest version in a local directory of migration files instead.
8+
The `pgroll latest` command has two subcommands:
99

10-
In both cases, the `--with-schema` flag can be used to prefix the latest version with the schema name.
10+
- `pgroll latest schema` - prints the latest schema version (migration name prefixed with schema name)
11+
- `pgroll latest migration` - prints the latest migration name (without schema prefix)
1112

12-
### Database
13+
Both subcommands support the `--local` flag to retrieve the latest version from a local directory of migration files instead of the target database.
14+
15+
### Schema Command
16+
17+
#### Database
1318

1419
Assuming that the [example migrations](https://github.com/xataio/pgroll/tree/main/examples) have been applied to the `public` schema in the target database, running:
1520

1621
```
17-
$ pgroll latest
22+
$ pgroll latest schema
1823
```
1924

20-
will print the latest version in the target database:
25+
will print the latest schema version in the target database:
2126

2227
```
23-
45_add_table_check_constraint
28+
public_55_add_primary_key_constraint_to_table
2429
```
2530

26-
The exact output will vary as the `examples/` directory is updated.
31+
#### Local
32+
33+
Assuming that the [example migrations](https://github.com/xataio/pgroll/tree/main/examples) are on disk in a directory called `examples`, running:
34+
35+
```
36+
$ pgroll latest schema --local examples/
37+
```
38+
39+
will print the latest schema version in the directory:
40+
41+
```
42+
public_55_add_primary_key_constraint_to_table
43+
```
44+
45+
### Migration Command
46+
47+
#### Database
48+
49+
Assuming that the [example migrations](https://github.com/xataio/pgroll/tree/main/examples) have been applied to the `public` schema in the target database, running:
50+
51+
```
52+
$ pgroll latest migration
53+
```
54+
55+
will print the latest migration name in the target database:
56+
57+
```
58+
55_add_primary_key_constraint_to_table
59+
```
2760

28-
### Local
61+
#### Local
2962

3063
Assuming that the [example migrations](https://github.com/xataio/pgroll/tree/main/examples) are on disk in a directory called `examples`, running:
3164

3265
```
33-
$ pgroll latest --local examples/
66+
$ pgroll latest migration --local examples/
3467
```
3568

36-
will print the latest migration in the directory:
69+
will print the latest migration name in the directory:
3770

3871
```
39-
45_add_table_check_constraint
72+
55_add_primary_key_constraint_to_table
4073
```
4174

4275
The exact output will vary as the `examples/` directory is updated.

docs/guides/clientapps.mdx

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ if err != nil {
2525
return nil, fmt.Errorf("failed to set search path: %s", err)
2626
}
2727
```
28+
2829
In practice, the `searchPath` variable would be provided to the application as an environment variable.
2930

3031
Set `search_path` in Python using `psycopg2` with the [`Connection` class](https://www.psycopg.org/psycopg3/docs/api/connections.html#psycopg.Connection):
@@ -39,23 +40,23 @@ with psycopg2.connect('dbname=postgres user=postgres password=postgres options=-
3940
Another example for setting `search_path` in Node.js:
4041

4142
```js
42-
const { Client } = require('pg');
43+
const { Client } = require("pg");
4344

4445
const client = new Client({
45-
user: 'postgres',
46-
host: 'localhost',
47-
database: 'postgres',
48-
password: 'postgres',
46+
user: "postgres",
47+
host: "localhost",
48+
database: "postgres",
49+
password: "postgres",
4950
port: 5432,
5051
});
5152

5253
client.connect();
5354

54-
client.query('SET search_path TO public_02_add_assignee_column', (err, res) => {
55+
client.query("SET search_path TO public_02_add_assignee_column", (err, res) => {
5556
if (err) {
56-
console.error('Error setting search_path', err.stack);
57+
console.error("Error setting search_path", err.stack);
5758
} else {
58-
console.log('search_path set successfully');
59+
console.log("search_path set successfully");
5960
// Perform your database operations here
6061
}
6162

@@ -64,19 +65,17 @@ client.query('SET search_path TO public_02_add_assignee_column', (err, res) => {
6465
});
6566
```
6667

67-
6868
## CI/CD pipelines
6969

70-
`pgroll` can tell you the name of the latest schema version, either in the target database or local directory using the `latest` command.
70+
`pgroll` can tell you the name of the latest schema version, either in the target database or local directory using the `latest schema` command.
7171

7272
```
73-
$ pgroll latest --with-schema
73+
$ pgroll latest schema
7474
public_02_add_assignee_column
7575
```
7676

7777
You can pass the `search_path` value to your application in your CI/CD pipeline, so your application can be tested against the latest database changes.
7878

79-
8079
## What happens if the `search_path` is not set?
8180

8281
If an application doesn't set the `search_path` for the connection, the `search_path` defaults to the `public` schema, meaning that the application will be working with the underlying tables directly rather than accessing them through the versioned views.

0 commit comments

Comments
 (0)