All notable changes to this project are documented here.
- New library: all CSV operations are now exposed as Go functions under
github.com/maherelgamil/csvops/pkg/csvops— importable by other Go programs (including the upcoming desktop app). Each operation takes a typedOptionsstruct and returns a typedResult. - Every operation supports
context.Contextcancellation and an optionalProgresscallback. merge(library only): newInputFilesoption for explicit-order merging, plusSkipErrors+OnWarnfor per-file non-fatal errors.to-sqlite(library only): typedIfExistsActionenum (Replace,Skip,Append,Fail);ToSQLiteResult.Skippedreflects honoredSkipmode.- Test suite extended to ~35 tests in
pkg/csvops/, including regression coverage for deterministic dedupe output order and the adversarial-table-name SQL-injection fix.
- CLI commands in
cmd/are now thin wrappers over the library. io.Writer-based output inFilterandMergeso callers can stream results to memory.
- CLI flags and behavior unchanged. No breaking changes for end users.
to-sqlite: SQL identifiers (--tableand CSV header column names) are now properly quoted, preventing SQL injection via crafted table names or headers.
filter: new--allflag to require ALL conditions to match (AND) instead of the default ANY (OR).stats: new--max-uniqueflag (default100000) to cap per-column unique tracking and bound memory on high-cardinality columns.split,to-sqlite:--delimiternow accepts\tas a tab shortcut.to-sqlite:--if-existsnow actually implementsskip,append, andfailmodes (previously onlyreplaceworked despite the docs).
dedupe: output rows are now emitted in original file order (previous map iteration produced non-deterministic output between runs).dedupe: in-place overwrite (--input==--output) now closes the output before renaming, fixing Windows behavior.dedupe: fixed nil-pointer panic when the row-count pre-scan failed to open the file.split,to-sqlite: validate--delimiteris exactly one character (previously panicked on empty string).filter:--eq=""now correctly matches empty string values (usesFlags().Changed()instead of zero-value comparison).to-sqlite: transaction is rolled back on row-insert errors instead of leaking.- All commands: converted to
RunEso failures exit with non-zero status (previously printed errors but exited 0). - Build:
-ldflags "-X main.version=..."injection now actually takes effect (previously a no-op becausemain.versiondidn't exist).
merge: streams rows row-by-row instead ofReadAll'ing each input file into memory.dedupe:keep-firstmode now streams output instead of buffering all kept rows.
filter: removed--enable-gtand--enable-ltflags. The--gtand--ltflags now activate automatically when set.
- Added
to-sqlitecommand to convert CSV files to SQLite databases - Auto-generate valid table names from filenames
- Added progress bar while inserting rows
- Cleaned up table naming logic
- Docs added for all commands