Skip to content

Commit 8a215d3

Browse files
committed
finish
1 parent 825a3ad commit 8a215d3

File tree

9 files changed

+198
-103
lines changed

9 files changed

+198
-103
lines changed

Cargo.lock

Lines changed: 4 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/pg_cli/src/execute/traverse.rs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,13 @@ impl TraversalContext for TraversalOptions<'_, '_> {
456456

457457
fn can_handle(&self, pglsp_path: &PgLspPath) -> bool {
458458
let path = pglsp_path.as_path();
459-
if self.fs.path_is_dir(path) || self.fs.path_is_symlink(path) {
459+
460+
let is_valid_file = self.fs.path_is_file(path)
461+
&& path
462+
.extension()
463+
.is_some_and(|ext| ext == "sql" || ext == "pg");
464+
465+
if self.fs.path_is_dir(path) || self.fs.path_is_symlink(path) || is_valid_file {
460466
// handle:
461467
// - directories
462468
// - symlinks
@@ -476,15 +482,7 @@ impl TraversalContext for TraversalOptions<'_, '_> {
476482
}
477483

478484
// bail on fifo and socket files
479-
if !self.fs.path_is_file(path) {
480-
return false;
481-
}
482-
483-
// only allow .sql and .pg files for now
484-
if path
485-
.extension()
486-
.is_none_or(|ext| ext != "sql" && ext != "pg")
487-
{
485+
if !is_valid_file {
488486
return false;
489487
}
490488

crates/pg_cli/src/lib.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ impl<'app> CliSession<'app> {
7474
staged,
7575
changed,
7676
since,
77-
after,
7877
} => run_command(
7978
self,
8079
&cli_options,
@@ -85,7 +84,6 @@ impl<'app> CliSession<'app> {
8584
staged,
8685
changed,
8786
since,
88-
after,
8987
},
9088
),
9189
PgLspCommand::Clean => commands::clean::clean(self),
Lines changed: 5 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
use std::str::FromStr;
2-
31
use biome_deserialize_macros::{Merge, Partial};
42
use bpaf::Bpaf;
53
use serde::{Deserialize, Serialize};
@@ -10,30 +8,10 @@ use serde::{Deserialize, Serialize};
108
#[partial(serde(rename_all = "snake_case", default, deny_unknown_fields))]
119
pub struct MigrationsConfiguration {
1210
/// The directory where the migration files are stored
13-
#[partial(bpaf(hide))]
14-
pub migration_dir: Option<String>,
15-
16-
/// The pattern used to store migration files
17-
#[partial(bpaf(hide))]
18-
pub migration_pattern: Option<MigrationPattern>,
19-
}
20-
21-
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize, Merge)]
22-
pub enum MigrationPattern {
23-
/// The migration files are stored in the root of the migration directory
24-
Root,
25-
/// The migration files are stored in a subdirectory of the migration directory
26-
Subdirectory,
27-
}
28-
29-
impl FromStr for MigrationPattern {
30-
type Err = String;
11+
#[partial(bpaf(long("migrations-dir")))]
12+
pub migrations_dir: String,
3113

32-
fn from_str(s: &str) -> Result<Self, Self::Err> {
33-
match s {
34-
"root" => Ok(Self::Root),
35-
"subdirectory" => Ok(Self::Subdirectory),
36-
_ => Err(format!("Invalid migration pattern: {}", s)),
37-
}
38-
}
14+
/// Ignore any migrations before this timestamp
15+
#[partial(bpaf(long("after")))]
16+
pub after: u64,
3917
}

crates/pg_workspace/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ tree-sitter.workspace = true
3939
tree_sitter_sql.workspace = true
4040

4141
[dev-dependencies]
42+
tempfile = "3.15.0"
4243

4344
[lib]
4445
doctest = false

crates/pg_workspace/src/settings.rs

Lines changed: 33 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,16 @@ use std::{
44
borrow::Cow,
55
num::NonZeroU64,
66
path::{Path, PathBuf},
7+
str::FromStr,
78
sync::{RwLock, RwLockReadGuard, RwLockWriteGuard},
89
};
910

1011
use ignore::gitignore::{Gitignore, GitignoreBuilder};
1112
use pg_configuration::{
1213
database::PartialDatabaseConfiguration,
1314
diagnostics::InvalidIgnorePattern,
14-
files::{FilesConfiguration, MigrationPattern},
15-
migrations::{MigrationsConfiguration, PartialMigrationsConfiguration},
15+
files::FilesConfiguration,
16+
migrations::{self, MigrationsConfiguration, PartialMigrationsConfiguration},
1617
ConfigurationDiagnostic, LinterConfiguration, PartialConfiguration,
1718
};
1819
use pg_fs::FileSystem;
@@ -32,7 +33,7 @@ pub struct Settings {
3233
pub linter: LinterSettings,
3334

3435
/// Migrations settings
35-
pub migrations: Option<Migrations>,
36+
pub migrations: Option<MigrationSettings>,
3637
}
3738

3839
#[derive(Debug)]
@@ -105,7 +106,13 @@ impl Settings {
105106
to_linter_settings(working_directory.clone(), LinterConfiguration::from(linter))?;
106107
}
107108

108-
// TODO migrations
109+
// Migrations settings
110+
if let Some(migrations) = configuration.migrations {
111+
self.migrations = to_migration_settings(
112+
working_directory.clone(),
113+
MigrationsConfiguration::from(migrations),
114+
);
115+
}
109116

110117
Ok(())
111118
}
@@ -313,68 +320,34 @@ pub struct FilesSettings {
313320
}
314321

315322
/// Migration settings
316-
#[derive(Debug)]
317-
pub(crate) struct Migrations {
318-
path: PathBuf,
319-
pattern: MigrationPattern,
320-
}
321-
322-
pub(crate) struct Migration {
323-
timestamp: u64,
324-
name: String,
323+
#[derive(Debug, Default)]
324+
pub struct MigrationSettings {
325+
pub path: Option<PathBuf>,
326+
pub after: Option<u64>,
325327
}
326328

327-
impl Migrations {
328-
fn get_migration(&self, path: &Path) -> Option<Migration> {
329-
// check if path is a child of the migration directory
330-
match path.canonicalize() {
331-
Ok(canonical_child) => match self.path.canonicalize() {
332-
Ok(canonical_dir) => canonical_child.starts_with(&canonical_dir),
333-
Err(_) => return None,
334-
},
335-
Err(_) => return None,
336-
};
337-
338-
match self.pattern {
339-
// supabase style migrations/0001_create_table.sql
340-
MigrationPattern::Root => {
341-
let file_name = path.file_name()?.to_str()?;
342-
let timestamp = file_name.split('_').next()?;
343-
let name = file_name
344-
.split('_')
345-
.skip(1)
346-
.collect::<Vec<&str>>()
347-
.join("_");
348-
let timestamp = timestamp.parse().ok()?;
349-
Some(Migration { timestamp, name })
350-
}
351-
// drizzle / prisma style migrations/0001_create_table/migration.sql
352-
MigrationPattern::Subdirectory => {
353-
let relative_path = path.strip_prefix(&self.path).ok()?;
354-
let components: Vec<_> = relative_path.components().collect();
355-
if components.len() != 2 {
356-
return None;
357-
}
358-
let dir_name = components[0].as_os_str().to_str()?;
359-
let parts: Vec<&str> = dir_name.splitn(2, '_').collect();
360-
if parts.len() != 2 {
361-
return None;
362-
}
363-
let timestamp = parts[0].parse().ok()?;
364-
let name = parts[1].to_string();
365-
Some(Migration { timestamp, name })
366-
}
329+
impl From<PartialMigrationsConfiguration> for MigrationSettings {
330+
fn from(value: PartialMigrationsConfiguration) -> Self {
331+
Self {
332+
path: value.migrations_dir.map(PathBuf::from),
333+
after: value.after,
367334
}
368335
}
369336
}
370337

371-
impl From<MigrationsConfiguration> for Migrations {
372-
fn from(value: MigrationsConfiguration) -> Self {
373-
Self {
374-
path: value.migration_dir,
375-
pattern: value.migration_pattern,
376-
}
377-
}
338+
fn to_migration_settings(
339+
working_directory: Option<PathBuf>,
340+
conf: MigrationsConfiguration,
341+
) -> Option<MigrationSettings> {
342+
tracing::debug!(
343+
"Migrations configuration: {:?}, dir: {:?}",
344+
conf,
345+
working_directory
346+
);
347+
working_directory.map(|working_directory| MigrationSettings {
348+
path: Some(working_directory.join(conf.migrations_dir)),
349+
after: Some(conf.after),
350+
})
378351
}
379352

380353
/// Limit the size of files to 1.0 MiB by default

crates/pg_workspace/src/workspace/server.rs

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
use std::{fs, future::Future, panic::RefUnwindSafe, path::Path, sync::RwLock};
1+
use std::{
2+
fs,
3+
future::Future,
4+
panic::RefUnwindSafe,
5+
path::{Path, PathBuf},
6+
sync::RwLock,
7+
};
28

39
use analyser::AnalyserVisitorBuilder;
410
use change::StatementChange;
@@ -33,6 +39,7 @@ use super::{
3339
mod analyser;
3440
mod change;
3541
mod document;
42+
mod migration;
3643
mod pg_query;
3744
mod tree_sitter;
3845

@@ -150,13 +157,31 @@ impl WorkspaceServer {
150157
Ok(())
151158
}
152159

160+
fn is_ignored_by_migration_config(&self, path: &Path) -> bool {
161+
let set = self.settings();
162+
set.as_ref()
163+
.migrations
164+
.as_ref()
165+
.and_then(|migration_settings| {
166+
tracing::info!("Checking migration settings: {:?}", migration_settings);
167+
let ignore_before = migration_settings.after.as_ref()?;
168+
tracing::info!("Checking migration settings: {:?}", ignore_before);
169+
let migrations_dir = migration_settings.path.as_ref()?;
170+
tracing::info!("Checking migration settings: {:?}", migrations_dir);
171+
let migration = migration::get_migration(path, migrations_dir)?;
172+
173+
Some(&migration.timestamp <= ignore_before)
174+
})
175+
.unwrap_or(false)
176+
}
177+
153178
/// Check whether a file is ignored in the top-level config `files.ignore`/`files.include`
154179
fn is_ignored(&self, path: &Path) -> bool {
155180
let file_name = path.file_name().and_then(|s| s.to_str());
156181
// Never ignore PGLSP's config file regardless `include`/`ignore`
157182
(file_name != Some(ConfigName::pglsp_toml())) &&
158183
// Apply top-level `include`/`ignore
159-
(self.is_ignored_by_top_level_config(path))
184+
(self.is_ignored_by_top_level_config(path) || self.is_ignored_by_migration_config(path))
160185
}
161186

162187
/// Check whether a file is ignored in the top-level config `files.ignore`/`files.include`

0 commit comments

Comments
 (0)