Skip to content

Commit d5959d7

Browse files
committed
MAINTENANCE.md: scylla-cql API considerations
Confusion would arise multiple times already around `scylla-cql` versioning requirements. In particular, it's not always clear to all that (and why) we **must not** release `scylla` with just minor bump if it bumps `scylla-cql`'s major. I decided it deserves comprehensive explanation in `MAINTENANCE.md`.
1 parent 597d088 commit d5959d7

File tree

1 file changed

+24
-0
lines changed

1 file changed

+24
-0
lines changed

Diff for: MAINTENANCE.md

+24
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,30 @@ What needs to be considered for releasing:
2828
- Versions of `scylla-cql` and `scylla-macros` MUST always be the same. `scylla-cql` MUST depend on EXACT version of `scylla-macros` (e.g. `version = "=1.0.0"` in `Cargo.toml`). This ensures that we can change the `_macro_internal` module in minor releases, and generally simplifies reasoning about those 2 crates. If Rust allowed it, they would be one crate.
2929
- For simplicity of maintenance, and to avoid potential problems with mixed versioning, we decided to always release all 3 crates together, with the same version numbers. Important: it does not allow us to make breaking changes in `scylla-cql`! Older versions of `scylla` will pick up newer versions of `scylla-cql`, e.g. after we release `scylla-cql 1.2`, `scylla 1.0` may start using it.
3030

31+
### `scylla-cql` API considerations
32+
33+
`scylla-cql` is purposefully available on [crates.io](https://crates.io/). This is mainly because some other crates, including ours (e.g., https://github.com/scylladb/scylla-rust-udf), use `scylla-cql` only and we don't want force them to pay in needless overhead introduced by depending on the whole `scylla` crate.
34+
As `scylla-cql` is publicly available, it must comply to semver.
35+
36+
`scylla-cql` has some `pub` APIs that are not `pub`-re-exported in `scylla`. One might think this allows us bumping `scylla-cql` major number while bumping only minor number of `scylla` **if only** the breaking changes introduced in `scylla-cql` aren't visible in `scylla` API. **This is, unfortunately, not true!** The following bad scenario is a possible result of such action:
37+
38+
Imagine if some crate `X` has both `scylla = "1.x"` and `scylla-cql = "1.x"` in dependencies, which is legal. It's even more likely if we take into account dependency transitivity, so the whole dependency tree must be considered. `X` can then use `scylla_cql` paths to operate on items that come from it, instead of using `scylla` re-exports. This is also legal.
39+
If we now update `scylla` to `1.(x+1)`, and use `scylla-cql = 2.0` there (in `scylla 1.(x+1)`), then the user will suddenly get errors about incompatible types (because they come from different major versions of the crate).
40+
41+
To illustrate on a specific case, consider the following definition present in `X`:
42+
`impl scylla_cql::serialize::row::SerializeRow for SomeStructDefinedInX { ... }`
43+
Now, even if we introduced no breaking changes to `SerializeRow` between `scylla-cql` 1.0 and 2.0, we end up with two different trait named `SerializeRow`, so the compiler refuses to accept (pseudonotation) `scylla-cql<1.x>::SerializeRow` as `scylla-cql<2.0>::SerializeRow`.
44+
45+
Does this mean that we are stuck with the current (sadly, still far from perfect) `scylla-cql` API for the whole `scylla = 1.x`? **Fortunately, no!** Imagine we are dissatisfied with the API of a struct `A` defined in `scylla-cql`:
46+
```rust
47+
pub struct A {
48+
pub field: Typ,
49+
}
50+
```
51+
Assuming `A` is **not** part of `scylla`'s public API (it does not matter if it's re-exported there or not), we can:
52+
1. introduce `A2` in `scylla-cql`, which has a better new API compared to `A` - this is a non-breaking change, because it's adding something new to the API;
53+
2. alter `scylla` code to use `A2` instead of `A` - this is non-breaking, because we've assumed `A` is not present in any `scylla` public API;
54+
3. keep `A` in `scylla-cql`, as well as possible `A` re-exports in `scylla`. Even though it's now legacy, it doesn't hurt. If suitable, we can mark `A` as `#[deprecated]` and remove it in the next major release.
3155

3256
## Documentation
3357

0 commit comments

Comments
 (0)