You've already forked seamantic
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
52d549ddb4
|
|||
|
a5454bda71
|
|||
|
800916c111
|
|||
|
b8f25b635d
|
@@ -0,0 +1,4 @@
|
||||
allow-expect-in-tests = true
|
||||
check-private-items = true
|
||||
|
||||
allowed-duplicate-crates = []
|
||||
+22
-6
@@ -1,7 +1,23 @@
|
||||
# OS Files
|
||||
*~
|
||||
._*
|
||||
.DS_Store
|
||||
*
|
||||
!**/
|
||||
|
||||
# Rust
|
||||
/target
|
||||
!.zed/settings.json
|
||||
!.gitignore
|
||||
|
||||
!/CONTRIBUTING.md
|
||||
!/LICENSE.md
|
||||
!/README.md
|
||||
|
||||
!/.clippy.toml
|
||||
!/.rustfmt.toml
|
||||
!/.tombi.toml
|
||||
!/Cargo.toml
|
||||
!/Cargo.lock
|
||||
!/justfile
|
||||
!/rust-toolchain.toml
|
||||
|
||||
!/crates/**/*.rs
|
||||
!/crates/**/Cargo.toml
|
||||
!/crates/**/README.md
|
||||
|
||||
!/lints/*.toml
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
hard_tabs = true
|
||||
wrap_comments = true
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
[format.rules]
|
||||
indent-style = "tab"
|
||||
indent-width = 4
|
||||
line-width = 120
|
||||
|
||||
# Disable TOML 1.1 features from tombi as long as we support rust <1.94
|
||||
[[schemas]]
|
||||
toml-version = "v1.0.0"
|
||||
path = "tombi://www.schemastore.org/cargo.json"
|
||||
include = ["Cargo.toml"]
|
||||
+7
-14
@@ -1,19 +1,12 @@
|
||||
{
|
||||
"project_name": null,
|
||||
|
||||
"auto_install_extensions": {
|
||||
"tombi": true,
|
||||
"cargo-appraiser": true,
|
||||
},
|
||||
|
||||
"languages": {
|
||||
"TOML": {
|
||||
"format_on_save": "on",
|
||||
"formatter": { "language_server": { "name": "tombi" } },
|
||||
},
|
||||
},
|
||||
|
||||
"lsp": {
|
||||
"just-lsp": {
|
||||
"initialization_options": {
|
||||
"formatting": {
|
||||
"indentation": "\t",
|
||||
},
|
||||
},
|
||||
},
|
||||
"rust-analyzer": {
|
||||
"initialization_options": {
|
||||
"imports": {
|
||||
|
||||
+2
-1
@@ -3,4 +3,5 @@ How to Contribute
|
||||
|
||||
We'd love to accept your patches and contributions to this project.
|
||||
We just need you to follow the Contributor License Agreement outlined
|
||||
in the latest v0.0.x of https://github.com/Skrunix/license
|
||||
in the latest v0.0.x of https://git.skrundz.dev/skrunix/license
|
||||
(mirrored to https://github.com/skrunix/license)
|
||||
|
||||
Generated
+517
-824
File diff suppressed because it is too large
Load Diff
+525
-27
@@ -1,41 +1,539 @@
|
||||
[workspace]
|
||||
resolver = "2"
|
||||
members = ["seamantic"]
|
||||
resolver = "3"
|
||||
members = ["crates/*"]
|
||||
|
||||
[workspace.package]
|
||||
license-file = "LICENSE.md"
|
||||
|
||||
edition = "2024"
|
||||
rust-version = "1.88.0"
|
||||
rust-version = "1.94"
|
||||
license-file = "LICENSE.md"
|
||||
publish = false
|
||||
|
||||
[workspace.dependencies]
|
||||
seamantic = { path = "seamantic", version = "=0.0.13", default-features = false }
|
||||
seamantic = { path = "crates/seamantic", version = "=1.0.1", default-features = false }
|
||||
|
||||
sea-orm = { version = "=2.0.0-rc.38", default-features = false }
|
||||
sea-orm-migration = { version = "=2.0.0-rc.38", default-features = false }
|
||||
|
||||
serde = { version = "^1", default-features = false }
|
||||
serde_test = { version = "^1", default-features = false }
|
||||
tokio = { version = "^1", default-features = false }
|
||||
sea-orm = { version = "^2.0.0", default-features = false }
|
||||
sea-orm-migration = { version = "^2.0.0", default-features = false }
|
||||
serde = { version = "^1.0.220", default-features = false }
|
||||
serde_test = { version = "^1.0.0", default-features = false }
|
||||
tokio = { version = "^1.38.2", default-features = false }
|
||||
|
||||
[workspace.lints.clippy]
|
||||
arithmetic_side_effects = "forbid"
|
||||
as_conversions = "forbid"
|
||||
checked_conversions = "forbid"
|
||||
default_union_representation = "forbid"
|
||||
expect_used = "forbid"
|
||||
indexing_slicing = "forbid"
|
||||
integer_division = "forbid"
|
||||
integer_division_remainder_used = "forbid"
|
||||
transmute_undefined_repr = "forbid"
|
||||
unchecked_time_subtraction = "forbid"
|
||||
unwrap_used = "forbid"
|
||||
cargo = { level = "warn", priority = -1 }
|
||||
complexity = { level = "warn", priority = -1 }
|
||||
correctness = { level = "deny", priority = -1 }
|
||||
perf = { level = "warn", priority = -1 }
|
||||
style = { level = "warn", priority = -1 }
|
||||
suspicious = { level = "warn", priority = -1 }
|
||||
|
||||
absolute-paths = "allow"
|
||||
alloc-instead-of-core = "warn"
|
||||
allow-attributes = "warn"
|
||||
allow-attributes-without-reason = "deny"
|
||||
arbitrary-source-item-ordering = "allow"
|
||||
arithmetic-side-effects = "deny"
|
||||
as-conversions = "deny"
|
||||
as-pointer-underscore = "deny"
|
||||
as-ptr-cast-mut = "deny"
|
||||
as-underscore = "deny"
|
||||
assertions-on-result-states = "warn"
|
||||
assigning-clones = "warn"
|
||||
big-endian-bytes = "allow"
|
||||
bool-to-int-with-if = "warn"
|
||||
borrow-as-ptr = "warn"
|
||||
branches-sharing-code = "warn"
|
||||
case-sensitive-file-extension-comparisons = "warn"
|
||||
cast-lossless = "deny"
|
||||
cast-possible-truncation = "deny"
|
||||
cast-possible-wrap = "deny"
|
||||
cast-precision-loss = "deny"
|
||||
cast-ptr-alignment = "deny"
|
||||
cast-sign-loss = "deny"
|
||||
cfg-not-test = "deny"
|
||||
checked-conversions = "deny"
|
||||
clear-with-drain = "warn"
|
||||
clone-on-ref-ptr = "warn"
|
||||
cloned-instead-of-copied = "warn"
|
||||
coerce-container-to-any = "warn"
|
||||
cognitive-complexity = "allow"
|
||||
collapsible-else-if = "warn"
|
||||
collection-is-never-read = "warn"
|
||||
comparison-chain = "warn"
|
||||
copy-iterator = "warn"
|
||||
create-dir = "warn"
|
||||
dbg-macro = "warn"
|
||||
debug-assert-with-mut-call = "deny"
|
||||
decimal-bitwise-operands = "warn"
|
||||
decimal-literal-representation = "warn"
|
||||
default-numeric-fallback = "warn"
|
||||
default-trait-access = "warn"
|
||||
default-union-representation = "allow"
|
||||
deref-by-slicing = "warn"
|
||||
derive-partial-eq-without-eq = "warn"
|
||||
disallowed-script-idents = "deny"
|
||||
doc-broken-link = "warn"
|
||||
doc-comment-double-space-linebreaks = "warn"
|
||||
doc-include-without-cfg = "warn"
|
||||
doc-link-code = "warn"
|
||||
doc-link-with-quotes = "warn"
|
||||
doc-markdown = "warn"
|
||||
doc-paragraphs-missing-punctuation = "warn"
|
||||
duration-suboptimal-units = "warn"
|
||||
elidable-lifetime-names = "warn"
|
||||
else-if-without-else = "warn"
|
||||
empty-drop = "warn"
|
||||
empty-enum-variants-with-brackets = "warn"
|
||||
empty-enums = "warn"
|
||||
empty-structs-with-brackets = "warn"
|
||||
enum-glob-use = "warn"
|
||||
equatable-if-let = "warn"
|
||||
error-impl-error = "warn"
|
||||
exhaustive-enums = "warn"
|
||||
exhaustive-structs = "warn"
|
||||
exit = "warn"
|
||||
expect-used = "warn"
|
||||
expl-impl-clone-on-copy = "warn"
|
||||
explicit-deref-methods = "warn"
|
||||
explicit-into-iter-loop = "warn"
|
||||
explicit-iter-loop = "warn"
|
||||
fallible-impl-from = "warn"
|
||||
field-scoped-visibility-modifiers = "warn"
|
||||
filetype-is-file = "warn"
|
||||
filter-map-next = "warn"
|
||||
flat-map-option = "warn"
|
||||
float-arithmetic = "warn"
|
||||
float-cmp = "warn"
|
||||
float-cmp-const = "warn"
|
||||
fn-params-excessive-bools = "allow"
|
||||
fn-to-numeric-cast-any = "warn"
|
||||
format-collect = "warn"
|
||||
format-push-string = "warn"
|
||||
future-not-send = "warn"
|
||||
get-unwrap = "warn"
|
||||
host-endian-bytes = "allow"
|
||||
if-not-else = "warn"
|
||||
if-then-some-else-none = "warn"
|
||||
ignore-without-reason = "warn"
|
||||
ignored-unit-patterns = "warn"
|
||||
impl-trait-in-params = "warn"
|
||||
implicit-clone = "warn"
|
||||
implicit-hasher = "warn"
|
||||
implicit-return = "allow"
|
||||
imprecise-flops = "warn"
|
||||
inconsistent-struct-constructor = "warn"
|
||||
index-refutable-slice = "deny"
|
||||
indexing-slicing = "deny"
|
||||
inefficient-to-string = "warn"
|
||||
infinite-loop = "warn"
|
||||
inline-always = "warn"
|
||||
inline-asm-x86-att-syntax = "warn"
|
||||
inline-asm-x86-intel-syntax = "warn"
|
||||
inline-modules = "allow"
|
||||
inline-trait-bounds = "allow"
|
||||
integer-division = "deny"
|
||||
integer-division-remainder-used = "deny"
|
||||
into-iter-without-iter = "warn"
|
||||
invalid-upcast-comparisons = "warn"
|
||||
ip-constant = "warn"
|
||||
items-after-statements = "warn"
|
||||
iter-filter-is-ok = "warn"
|
||||
iter-filter-is-some = "warn"
|
||||
iter-not-returning-iterator = "warn"
|
||||
iter-on-empty-collections = "warn"
|
||||
iter-on-single-items = "warn"
|
||||
iter-over-hash-type = "warn"
|
||||
iter-with-drain = "warn"
|
||||
iter-without-into-iter = "warn"
|
||||
large-digit-groups = "warn"
|
||||
large-futures = "warn"
|
||||
large-include-file = "warn"
|
||||
large-stack-arrays = "warn"
|
||||
large-stack-frames = "warn"
|
||||
large-types-passed-by-value = "warn"
|
||||
let-underscore-must-use = "warn"
|
||||
let-underscore-untyped = "warn"
|
||||
linkedlist = "warn"
|
||||
literal-string-with-formatting-args = "warn"
|
||||
little-endian-bytes = "allow"
|
||||
lossy-float-literal = "warn"
|
||||
macro-use-imports = "warn"
|
||||
manual-assert = "warn"
|
||||
manual-assert-eq = "warn"
|
||||
manual-ilog2 = "warn"
|
||||
manual-instant-elapsed = "warn"
|
||||
manual-is-power-of-two = "warn"
|
||||
manual-is-variant-and = "warn"
|
||||
manual-let-else = "warn"
|
||||
manual-midpoint = "warn"
|
||||
manual-string-new = "warn"
|
||||
many-single-char-names = "warn"
|
||||
map-err-ignore = "warn"
|
||||
map-unwrap-or = "warn"
|
||||
map-with-unused-argument-over-ranges = "warn"
|
||||
match-bool = "warn"
|
||||
match-same-arms = "warn"
|
||||
match-wild-err-arm = "warn"
|
||||
match-wildcard-for-single-variants = "warn"
|
||||
maybe-infinite-iter = "warn"
|
||||
mem-forget = "warn"
|
||||
min-ident-chars = "allow"
|
||||
mismatching-type-param-order = "warn"
|
||||
missing-assert-message = "warn"
|
||||
missing-asserts-for-indexing = "warn"
|
||||
missing-const-for-fn = "warn"
|
||||
missing-docs-in-private-items = "warn"
|
||||
missing-errors-doc = "warn"
|
||||
missing-fields-in-debug = "warn"
|
||||
missing-inline-in-public-items = "warn"
|
||||
missing-panics-doc = "warn"
|
||||
missing-trait-methods = "warn"
|
||||
mixed-read-write-in-expression = "warn"
|
||||
mod-module-files = "allow"
|
||||
module-name-repetitions = "warn"
|
||||
modulo-arithmetic = "warn"
|
||||
multiple-crate-versions = "allow"
|
||||
multiple-inherent-impl = "warn"
|
||||
multiple-unsafe-ops-per-block = "warn"
|
||||
must-use-candidate = "warn"
|
||||
mut-mut = "warn"
|
||||
mutex-atomic = "warn"
|
||||
mutex-integer = "warn"
|
||||
naive-bytecount = "warn"
|
||||
needless-bitwise-bool = "warn"
|
||||
needless-collect = "warn"
|
||||
needless-continue = "warn"
|
||||
needless-for-each = "warn"
|
||||
needless-pass-by-ref-mut = "warn"
|
||||
needless-pass-by-value = "warn"
|
||||
needless-raw-string-hashes = "warn"
|
||||
needless-raw-strings = "warn"
|
||||
needless-type-cast = "warn"
|
||||
no-effect-underscore-binding = "warn"
|
||||
no-mangle-with-rust-abi = "warn"
|
||||
non-ascii-literal = "allow"
|
||||
non-send-fields-in-send-ty = "warn"
|
||||
non-std-lazy-statics = "warn"
|
||||
non-zero-suggestions = "warn"
|
||||
nonminimal-bool = "warn"
|
||||
nonstandard-macro-braces = "warn"
|
||||
option-as-ref-cloned = "warn"
|
||||
option-if-let-else = "warn"
|
||||
option-option = "warn"
|
||||
or-fun-call = "warn"
|
||||
overly-complex-bool-expr = "allow"
|
||||
panic = "warn"
|
||||
panic-in-result-fn = "warn"
|
||||
partial-pub-fields = "warn"
|
||||
path-buf-push-overwrite = "warn"
|
||||
pathbuf-init-then-push = "warn"
|
||||
pattern-type-mismatch = "allow"
|
||||
pointer-format = "warn"
|
||||
precedence-bits = "warn"
|
||||
print-stderr = "warn"
|
||||
print-stdout = "warn"
|
||||
ptr-as-ptr = "warn"
|
||||
ptr-cast-constness = "warn"
|
||||
ptr-offset-by-literal = "warn"
|
||||
pub-underscore-fields = "warn"
|
||||
pub-use = "allow"
|
||||
pub-with-shorthand = "allow"
|
||||
pub-without-shorthand = "warn"
|
||||
question-mark-used = "allow"
|
||||
range-minus-one = "warn"
|
||||
range-plus-one = "warn"
|
||||
rc-buffer = "warn"
|
||||
rc-mutex = "warn"
|
||||
read-zero-byte-vec = "warn"
|
||||
redundant-clone = "warn"
|
||||
redundant-closure-for-method-calls = "warn"
|
||||
redundant-else = "warn"
|
||||
redundant-pub-crate = "allow"
|
||||
redundant-test-prefix = "warn"
|
||||
redundant-type-annotations = "warn"
|
||||
ref-as-ptr = "warn"
|
||||
ref-binding-to-reference = "warn"
|
||||
ref-option = "warn"
|
||||
ref-option-ref = "warn"
|
||||
ref-patterns = "warn"
|
||||
renamed-function-params = "warn"
|
||||
rest-pat-in-fully-bound-structs = "warn"
|
||||
return-and-then = "warn"
|
||||
return-self-not-must-use = "warn"
|
||||
same-functions-in-if-condition = "warn"
|
||||
same-length-and-capacity = "warn"
|
||||
same-name-method = "warn"
|
||||
search-is-some = "warn"
|
||||
self-named-module-files = "warn"
|
||||
self-only-used-in-recursion = "warn"
|
||||
semicolon-if-nothing-returned = "warn"
|
||||
semicolon-inside-block = "warn"
|
||||
semicolon-outside-block = "allow"
|
||||
separated-literal-suffix = "allow"
|
||||
set-contains-or-insert = "warn"
|
||||
shadow-reuse = "allow"
|
||||
shadow-same = "allow"
|
||||
shadow-unrelated = "allow"
|
||||
should-panic-without-expect = "warn"
|
||||
significant-drop-in-scrutinee = "warn"
|
||||
significant-drop-tightening = "warn"
|
||||
similar-names = "allow"
|
||||
single-call-fn = "allow"
|
||||
single-char-lifetime-names = "allow"
|
||||
single-char-pattern = "allow"
|
||||
single-match-else = "warn"
|
||||
single-option-map = "warn"
|
||||
stable-sort-primitive = "warn"
|
||||
std-instead-of-alloc = "warn"
|
||||
std-instead-of-core = "warn"
|
||||
str-split-at-newline = "warn"
|
||||
str-to-string = "warn"
|
||||
string-add = "warn"
|
||||
string-add-assign = "warn"
|
||||
string-lit-as-bytes = "warn"
|
||||
string-lit-chars-any = "warn"
|
||||
string-slice = "warn"
|
||||
struct-excessive-bools = "allow"
|
||||
struct-field-names = "warn"
|
||||
suboptimal-flops = "warn"
|
||||
suspicious-operation-groupings = "warn"
|
||||
suspicious-xor-used-as-pow = "warn"
|
||||
tests-outside-test-module = "warn"
|
||||
todo = "warn"
|
||||
too-long-first-doc-paragraph = "allow"
|
||||
too-many-lines = "allow"
|
||||
trailing-empty-array = "warn"
|
||||
trait-duplication-in-bounds = "warn"
|
||||
transmute-ptr-to-ptr = "warn"
|
||||
transmute-undefined-repr = "warn"
|
||||
trivial-regex = "warn"
|
||||
trivially-copy-pass-by-ref = "warn"
|
||||
try-err = "warn"
|
||||
tuple-array-conversions = "warn"
|
||||
type-repetition-in-bounds = "warn"
|
||||
unchecked-time-subtraction = "deny"
|
||||
undocumented-unsafe-blocks = "deny"
|
||||
unicode-not-nfc = "warn"
|
||||
unimplemented = "warn"
|
||||
uninhabited-references = "warn"
|
||||
uninlined-format-args = "warn"
|
||||
unnecessary-box-returns = "warn"
|
||||
unnecessary-debug-formatting = "warn"
|
||||
unnecessary-join = "warn"
|
||||
unnecessary-literal-bound = "warn"
|
||||
unnecessary-safety-comment = "warn"
|
||||
unnecessary-safety-doc = "warn"
|
||||
unnecessary-self-imports = "warn"
|
||||
unnecessary-semicolon = "warn"
|
||||
unnecessary-struct-initialization = "warn"
|
||||
unnecessary-trailing-comma = "warn"
|
||||
unnecessary-wraps = "warn"
|
||||
unneeded-field-pattern = "warn"
|
||||
unnested-or-patterns = "warn"
|
||||
unreachable = "warn"
|
||||
unreadable-literal = "warn"
|
||||
unsafe-derive-deserialize = "warn"
|
||||
unseparated-literal-suffix = "warn"
|
||||
unused-async = "warn"
|
||||
unused-async-trait-impl = "warn"
|
||||
unused-peekable = "warn"
|
||||
unused-result-ok = "warn"
|
||||
unused-rounding = "warn"
|
||||
unused-self = "warn"
|
||||
unused-trait-names = "warn"
|
||||
unwrap-in-result = "warn"
|
||||
unwrap-used = "warn"
|
||||
use-debug = "warn"
|
||||
use-self = "warn"
|
||||
used-underscore-binding = "warn"
|
||||
used-underscore-items = "warn"
|
||||
useless-let-if-seq = "warn"
|
||||
verbose-bit-mask = "warn"
|
||||
verbose-file-reads = "warn"
|
||||
volatile-composites = "warn"
|
||||
while-float = "warn"
|
||||
wildcard-enum-match-arm = "warn"
|
||||
wildcard-imports = "warn"
|
||||
with-capacity-zero = "warn"
|
||||
zero-sized-map-values = "warn"
|
||||
|
||||
[workspace.lints.rust]
|
||||
arithmetic_overflow = "forbid"
|
||||
missing_docs = "forbid"
|
||||
unsafe_code = "forbid"
|
||||
unused_doc_comments = "forbid"
|
||||
deprecated-safe = "forbid"
|
||||
future-incompatible = "deny"
|
||||
keyword-idents = "deny"
|
||||
let-underscore = "warn"
|
||||
nonstandard-style = "warn"
|
||||
refining-impl-trait = "warn"
|
||||
rust-2018-compatibility = "deny"
|
||||
rust-2018-idioms = "deny"
|
||||
rust-2021-compatibility = "deny"
|
||||
rust-2024-compatibility = "deny"
|
||||
unknown-or-malformed-diagnostic-attributes = "deny"
|
||||
unused = { level = "warn", priority = -1 }
|
||||
|
||||
ambiguous-glob-reexports = "warn"
|
||||
ambiguous-negative-literals = "deny"
|
||||
ambiguous-wide-pointer-comparisons = "warn"
|
||||
arithmetic-overflow = "deny"
|
||||
asm-sub-register = "warn"
|
||||
async-fn-in-trait = "warn"
|
||||
bad-asm-style = "warn"
|
||||
binary-asm-labels = "deny"
|
||||
bindings-with-variant-name = "deny"
|
||||
break-with-label-and-loop = "warn"
|
||||
c-void-returns = "warn"
|
||||
clashing-extern-declarations = "warn"
|
||||
closure-returning-async-block = "warn"
|
||||
confusable-idents = "warn"
|
||||
const-item-interior-mutations = "warn"
|
||||
const-item-mutation = "warn"
|
||||
dangerous-implicit-autorefs = "deny"
|
||||
dangling-pointers-from-locals = "warn"
|
||||
dangling-pointers-from-temporaries = "warn"
|
||||
dead-code-pub-in-binary = "warn"
|
||||
deprecated = "warn"
|
||||
deprecated-in-future = "allow"
|
||||
deprecated-where-clause-location = "warn"
|
||||
deref-into-dyn-supertrait = "warn"
|
||||
deref-nullptr = "deny"
|
||||
double-negations = "warn"
|
||||
drop-bounds = "warn"
|
||||
dropping-copy-types = "warn"
|
||||
dropping-references = "warn"
|
||||
duplicate-features = "deny"
|
||||
duplicate-macro-attributes = "warn"
|
||||
dyn-drop = "warn"
|
||||
enum-intrinsics-non-enums = "deny"
|
||||
explicit-builtin-cfgs-in-flags = "deny"
|
||||
exported-private-dependencies = "warn"
|
||||
ffi-unwind-calls = "warn"
|
||||
for-loops-over-fallibles = "warn"
|
||||
forgetting-copy-types = "warn"
|
||||
forgetting-references = "warn"
|
||||
function-casts-as-integer = "warn"
|
||||
function-item-references = "warn"
|
||||
hidden-glob-reexports = "warn"
|
||||
impl-trait-redundant-captures = "warn"
|
||||
improper-ctypes = "warn"
|
||||
improper-ctypes-definitions = "warn"
|
||||
improper-gpu-kernel-arg = "warn"
|
||||
incomplete-features = "warn"
|
||||
incomplete-include = "deny"
|
||||
ineffective-unstable-trait-impl = "deny"
|
||||
inline-no-sanitize = "warn"
|
||||
integer-to-ptr-transmutes = "warn"
|
||||
internal-features = "warn"
|
||||
invalid-atomic-ordering = "deny"
|
||||
invalid-doc-attributes = "warn"
|
||||
invalid-from-utf8 = "warn"
|
||||
invalid-from-utf8-unchecked = "deny"
|
||||
invalid-nan-comparisons = "warn"
|
||||
invalid-null-arguments = "deny"
|
||||
invalid-reference-casting = "deny"
|
||||
invalid-runtime-symbol-definitions = "deny"
|
||||
invalid-value = "warn"
|
||||
irrefutable-let-patterns = "warn"
|
||||
large-assignments = "warn"
|
||||
linker-info = "allow"
|
||||
linker-messages = "warn"
|
||||
long-running-const-eval = "deny"
|
||||
macro-use-extern-crate = "warn"
|
||||
meta-variable-misuse = "warn"
|
||||
mismatched-lifetime-syntaxes = "warn"
|
||||
missing-abi = "warn"
|
||||
missing-copy-implementations = "warn"
|
||||
missing-debug-implementations = "warn"
|
||||
missing-docs = "warn"
|
||||
missing-gpu-kernel-export-name = "warn"
|
||||
mixed-script-confusables = "warn"
|
||||
mutable-transmutes = "deny"
|
||||
named-arguments-used-positionally = "warn"
|
||||
named-asm-labels = "deny"
|
||||
no-mangle-const-items = "deny"
|
||||
no-mangle-generic-items = "warn"
|
||||
non-ascii-idents = "deny"
|
||||
non-contiguous-range-endpoints = "warn"
|
||||
non-local-definitions = "warn"
|
||||
non-shorthand-field-patterns = "warn"
|
||||
noop-method-call = "warn"
|
||||
opaque-hidden-inferred-bound = "warn"
|
||||
overflowing-literals = "deny"
|
||||
overlapping-range-endpoints = "warn"
|
||||
private-bounds = "warn"
|
||||
private-interfaces = "warn"
|
||||
ptr-to-integer-transmute-in-consts = "warn"
|
||||
redundant-imports = "warn"
|
||||
redundant-lifetimes = "warn"
|
||||
renamed-and-removed-lints = "warn"
|
||||
rtsan-nonblocking-async = "warn"
|
||||
single-use-lifetimes = "warn"
|
||||
special-module-name = "warn"
|
||||
stable-features = "warn"
|
||||
suspicious-double-ref-op = "warn"
|
||||
suspicious-runtime-symbol-definitions = "warn"
|
||||
text-direction-codepoint-in-comment = "deny"
|
||||
text-direction-codepoint-in-literal = "deny"
|
||||
trivial-bounds = "warn"
|
||||
trivial-casts = "warn"
|
||||
trivial-numeric-casts = "warn"
|
||||
type-alias-bounds = "warn"
|
||||
uncommon-codepoints = "warn"
|
||||
unconditional-panic = "deny"
|
||||
unconditional-recursion = "warn"
|
||||
undropped-manually-drops = "deny"
|
||||
unexpected-cfgs = "warn"
|
||||
unfulfilled-lint-expectations = "warn"
|
||||
ungated-async-fn-track-caller = "warn"
|
||||
unit-bindings = "warn"
|
||||
unknown-crate-types = "deny"
|
||||
unknown-lints = "warn"
|
||||
unnameable-test-items = "warn"
|
||||
unnameable-types = "warn"
|
||||
unnecessary-transmutes = "warn"
|
||||
unpredictable-function-pointer-comparisons = "warn"
|
||||
unreachable-cfg-select-predicates = "warn"
|
||||
unreachable-pub = "warn"
|
||||
unsafe-code = "forbid"
|
||||
unstable-features = "forbid"
|
||||
unused-associated-type-bounds = "warn"
|
||||
unused-comparisons = "warn"
|
||||
unused-crate-dependencies = "warn"
|
||||
unused-import-braces = "warn"
|
||||
unused-lifetimes = "warn"
|
||||
unused-qualifications = "warn"
|
||||
unused-results = "warn"
|
||||
useless-deprecated = "deny"
|
||||
useless-ptr-null-checks = "warn"
|
||||
uses-power-alignment = "warn"
|
||||
variant-size-differences = "warn"
|
||||
warnings = "warn"
|
||||
while-true = "warn"
|
||||
|
||||
# unstable lints
|
||||
# default-overrides-default-fields = "deny"
|
||||
# deprecated-llvm-intrinsic = "warn"
|
||||
# implicit-provenance-casts = "deny"
|
||||
# multiple-supertrait-upcastable = "warn"
|
||||
# must-not-suspend = "warn"
|
||||
# non-exhaustive-omitted-patterns = "warn"
|
||||
# resolving-to-items-shadowing-supertrait-items = "warn"
|
||||
# shadowing-supertrait-items = "warn"
|
||||
# tail-call-track-caller = "warn"
|
||||
# test-unstable-lint = "deny"
|
||||
# unqualified-local-imports = "deny"
|
||||
|
||||
[workspace.lints.rustdoc]
|
||||
bare-urls = "warn"
|
||||
broken-intra-doc-links = "warn"
|
||||
invalid-codeblock-attributes = "warn"
|
||||
invalid-html-tags = "warn"
|
||||
invalid-rust-codeblocks = "warn"
|
||||
missing-crate-level-docs = "warn"
|
||||
private-doc-tests = "warn"
|
||||
private-intra-doc-links = "warn"
|
||||
redundant-explicit-links = "warn"
|
||||
unescaped-backticks = "warn"
|
||||
|
||||
# unstable lints
|
||||
# missing-doc-code-examples = "warn"
|
||||
|
||||
[profile.release]
|
||||
opt-level = 3
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
# Seamantic
|
||||
|
||||
[](https://crates.io/crates/seamantic)
|
||||
## Development
|
||||
|
||||
A library to enhance SeaORM
|
||||
Run the full validation suite before committing:
|
||||
|
||||
## Various builds
|
||||
```sh
|
||||
just all
|
||||
just install
|
||||
```
|
||||
|
||||
- build: `cargo hack --feature-powerset build`
|
||||
- clippy: `cargo hack --feature-powerset clippy -- -D warnings`
|
||||
- test: `cargo hack --feature-powerset test`
|
||||
- test old: `cargo +1.88 hack --feature-powerset test`
|
||||
- example: `cargo run --example=migrations --features=sqlite`
|
||||
- fmt: `cargo fmt --check`
|
||||
- docs: `RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features`
|
||||
- semver: `cargo semver-checks --all-features`
|
||||
- publish: `cargo publish --dry-run -p seamantic`
|
||||
##### Publish
|
||||
|
||||
- `cargo semver-checks --all-features`
|
||||
- `cargo publish --dry-run -p <crate>`
|
||||
- `cargo publish --dry-run --workspace`
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
[package]
|
||||
name = "seamantic"
|
||||
version = "0.0.13"
|
||||
license-file.workspace = true
|
||||
|
||||
version = "1.0.1"
|
||||
description = "A library to enhance SeaORM"
|
||||
repository = "https://github.com/QuantumShade/seamantic"
|
||||
categories = []
|
||||
repository = "https://git.skrundz.dev/quantumshade/seamantic"
|
||||
keywords = ["SeaORM"]
|
||||
categories = ["database"]
|
||||
include = ["/src"]
|
||||
publish = true
|
||||
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
license-file.workspace = true
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
@@ -31,7 +33,7 @@ serde_test = { workspace = true }
|
||||
tokio = { workspace = true, features = ["macros", "rt"] }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
default = ["sqlite"]
|
||||
serde = ["dep:serde"]
|
||||
sqlite = ["sea-orm-migration/sqlx-sqlite"]
|
||||
|
||||
@@ -14,6 +14,10 @@ pub(super) struct Migration;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigrationTrait for Migration {
|
||||
#[expect(
|
||||
elided_lifetimes_in_paths,
|
||||
reason = "async_trait causes lifetimes to be strange"
|
||||
)]
|
||||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.create_table(
|
||||
@@ -28,6 +32,10 @@ impl MigrationTrait for Migration {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[expect(
|
||||
elided_lifetimes_in_paths,
|
||||
reason = "async_trait causes lifetimes to be strange"
|
||||
)]
|
||||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.drop_table(Table::drop().table(Objects::Table).to_owned())
|
||||
@@ -15,3 +15,6 @@ async fn main() {
|
||||
let database = Database::connect(options).await.expect("Database::connect");
|
||||
Migrator::up(&database, None).await.expect("Migrator::up");
|
||||
}
|
||||
|
||||
// dev-dependencies cannot be optional and `serde_test` is not used
|
||||
use {serde_test as _, tokio as _};
|
||||
@@ -1,4 +1,4 @@
|
||||
//! A library for enhacing SeaORM
|
||||
//! A library for enhacing `SeaORM`.
|
||||
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
|
||||
@@ -31,6 +31,7 @@ macro_rules! migrations {
|
||||
|
||||
/// Auto-generated migration manager
|
||||
#[automatically_derived]
|
||||
#[non_exhaustive]
|
||||
pub struct Migrator;
|
||||
|
||||
#[automatically_derived]
|
||||
@@ -46,3 +47,8 @@ macro_rules! migrations {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// dev-dependencies cannot be optional and `tokio` and `serde_test` are only used
|
||||
// when the `sqlite` feature is active
|
||||
#[cfg(test)]
|
||||
use {serde_test as _, tokio as _};
|
||||
@@ -1,37 +1,45 @@
|
||||
//! [Duration] utilities
|
||||
//! [Duration] utilities.
|
||||
|
||||
use core::time::Duration;
|
||||
|
||||
use sea_orm::sea_query::{ArrayType, Nullable, ValueType, ValueTypeErr};
|
||||
use sea_orm::{ColIdx, ColumnType, DbErr, QueryResult, TryFromU64, TryGetError, TryGetable, Value};
|
||||
|
||||
// "u64 unsupported by sqlx-sqlite", so use i64 as the bit representation
|
||||
/// The internal representation that `SeaORM` uses for durations.
|
||||
///
|
||||
/// "u64 unsupported by sqlx-sqlite", so use i64 as the bit representation.
|
||||
type SeaOrmRepr = i64;
|
||||
/// The internal represenation that [Duration] uses.
|
||||
type DurationRepr = u64;
|
||||
|
||||
/// Wrapper around [Duration] to store a number of seconds
|
||||
/// Wrapper around [Duration] to store a number of seconds.
|
||||
///
|
||||
/// ### Warning:
|
||||
/// Sub-second precision will be lost
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
||||
/// # Warning:
|
||||
/// Sub-second precision will be lost.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[cfg_attr(feature = "serde", serde(transparent))]
|
||||
#[repr(transparent)]
|
||||
#[expect(clippy::exhaustive_structs, reason = "unlikely to change")]
|
||||
pub struct Seconds(pub Duration);
|
||||
|
||||
impl From<Duration> for Seconds {
|
||||
#[inline]
|
||||
fn from(value: Duration) -> Self {
|
||||
Self(Duration::from_secs(value.as_secs()))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Seconds> for Duration {
|
||||
#[inline]
|
||||
fn from(value: Seconds) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
#[expect(clippy::missing_trait_methods, reason = "accept default methods")]
|
||||
impl ValueType for Seconds {
|
||||
#[inline]
|
||||
fn try_from(v: Value) -> Result<Self, ValueTypeErr> {
|
||||
<SeaOrmRepr as ValueType>::try_from(v)
|
||||
.map(|i| DurationRepr::from_ne_bytes(i.to_ne_bytes()))
|
||||
@@ -39,26 +47,32 @@ impl ValueType for Seconds {
|
||||
.map(Self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn type_name() -> String {
|
||||
core::any::type_name::<Self>().to_string()
|
||||
core::any::type_name::<Self>().to_owned()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn array_type() -> ArrayType {
|
||||
SeaOrmRepr::array_type()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn column_type() -> ColumnType {
|
||||
SeaOrmRepr::column_type()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Seconds> for Value {
|
||||
#[inline]
|
||||
fn from(value: Seconds) -> Self {
|
||||
value.0.as_secs().into()
|
||||
}
|
||||
}
|
||||
|
||||
#[expect(clippy::missing_trait_methods, reason = "accept default methods")]
|
||||
impl TryGetable for Seconds {
|
||||
#[inline]
|
||||
fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Self, TryGetError> {
|
||||
SeaOrmRepr::try_get_by(res, index)
|
||||
.map(|i| DurationRepr::from_ne_bytes(i.to_ne_bytes()))
|
||||
@@ -68,6 +82,7 @@ impl TryGetable for Seconds {
|
||||
}
|
||||
|
||||
impl TryFromU64 for Seconds {
|
||||
#[inline]
|
||||
fn try_from_u64(n: u64) -> Result<Self, DbErr> {
|
||||
SeaOrmRepr::try_from_u64(n)
|
||||
.map(|i| DurationRepr::from_ne_bytes(i.to_ne_bytes()))
|
||||
@@ -77,6 +92,7 @@ impl TryFromU64 for Seconds {
|
||||
}
|
||||
|
||||
impl Nullable for Seconds {
|
||||
#[inline]
|
||||
fn null() -> Value {
|
||||
SeaOrmRepr::null()
|
||||
}
|
||||
@@ -91,10 +107,9 @@ mod tests {
|
||||
|
||||
use super::Seconds;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, DeriveEntityModel)]
|
||||
#[sea_orm(table_name = "seconds")]
|
||||
pub struct Model {
|
||||
struct Model {
|
||||
#[sea_orm(primary_key, auto_increment = false)]
|
||||
id: u8,
|
||||
#[sea_orm(primary_key, auto_increment = false)]
|
||||
@@ -102,9 +117,9 @@ mod tests {
|
||||
nullable: Option<Seconds>,
|
||||
}
|
||||
|
||||
#[expect(clippy::missing_trait_methods, reason = "accept default methods")]
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {}
|
||||
enum Relation {}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
//! Typed IDs for use as primary keys
|
||||
//! Typed IDs for use as primary keys.
|
||||
|
||||
use core::cmp::Ordering;
|
||||
use core::fmt;
|
||||
@@ -8,57 +8,70 @@ use core::marker::PhantomData;
|
||||
use sea_orm::sea_query::{ArrayType, Nullable, ValueType, ValueTypeErr};
|
||||
use sea_orm::{ColIdx, ColumnType, DbErr, QueryResult, TryFromU64, TryGetError, TryGetable, Value};
|
||||
|
||||
/// The internal representation used by the database
|
||||
/// The internal representation used by the database.
|
||||
pub type SeaOrmRepr = i64;
|
||||
|
||||
/// An opaque type representing a row ID
|
||||
/// An opaque type representing a row ID.
|
||||
///
|
||||
/// IDs should be tagged with `#[sea_orm(primary_key, auto_increment = false)]`
|
||||
/// IDs should be tagged with `#[sea_orm(primary_key, auto_increment = false)]`.
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[cfg_attr(feature = "serde", serde(transparent))]
|
||||
#[repr(transparent)]
|
||||
pub struct Id<T> {
|
||||
/// The ID.
|
||||
id: SeaOrmRepr,
|
||||
/// `PhantomData` for `T`.
|
||||
#[cfg_attr(feature = "serde", serde(skip_serializing, default))]
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
// Manual implementation since `T: Clone` is not required
|
||||
// Manual implementation since `T: Clone` is not required.
|
||||
#[expect(clippy::missing_trait_methods, reason = "accept default methods")]
|
||||
impl<T> Clone for Id<T> {
|
||||
#[inline]
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
// Manual implementation since `T: Copy` is not required
|
||||
// Manual implementation since `T: Copy` is not required.
|
||||
impl<T> Copy for Id<T> {}
|
||||
|
||||
// Manual implementation since `T: PartialEq` is not required
|
||||
// Manual implementation since `T: PartialEq` is not required.
|
||||
#[expect(clippy::missing_trait_methods, reason = "accept default methods")]
|
||||
impl<T> PartialEq for Id<T> {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.id == other.id
|
||||
self.id.eq(&other.id)
|
||||
}
|
||||
}
|
||||
|
||||
// Manual implementation since `T: Eq` is not required
|
||||
// Manual implementation since `T: Eq` is not required.
|
||||
#[expect(clippy::missing_trait_methods, reason = "accept default methods")]
|
||||
impl<T> Eq for Id<T> {}
|
||||
|
||||
// Manual implementation since `T: PartialOrd` is not required
|
||||
// Manual implementation since `T: PartialOrd` is not required.
|
||||
#[expect(clippy::missing_trait_methods, reason = "accept default methods")]
|
||||
impl<T> PartialOrd for Id<T> {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
// Manual implementation since `T: Ord` is not required
|
||||
#[expect(clippy::missing_trait_methods, reason = "accept default methods")]
|
||||
impl<T> Ord for Id<T> {
|
||||
#[inline]
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.id.cmp(&other.id)
|
||||
}
|
||||
}
|
||||
|
||||
// Manual implementation since `T: Hash` is not required
|
||||
#[expect(clippy::missing_trait_methods, reason = "accept default methods")]
|
||||
impl<T> Hash for Id<T> {
|
||||
#[inline]
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.id.hash(state);
|
||||
}
|
||||
@@ -66,7 +79,9 @@ impl<T> Hash for Id<T> {
|
||||
|
||||
impl<T> Id<T> {
|
||||
/// Allows the conversion from a raw value to [Id], though the use is discouraged.
|
||||
pub fn from_raw(raw: SeaOrmRepr) -> Self {
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub const fn from_raw(raw: SeaOrmRepr) -> Self {
|
||||
Self {
|
||||
id: raw,
|
||||
_phantom: PhantomData,
|
||||
@@ -74,13 +89,16 @@ impl<T> Id<T> {
|
||||
}
|
||||
|
||||
/// Allows extracting the raw value, though the use is discouraged.
|
||||
pub fn into_raw(self) -> SeaOrmRepr {
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub const fn into_raw(self) -> SeaOrmRepr {
|
||||
self.id
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> fmt::Debug for Id<T> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("Id")
|
||||
.field("T", &core::any::type_name::<T>())
|
||||
.field("id", &self.id)
|
||||
@@ -88,7 +106,9 @@ impl<T> fmt::Debug for Id<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[expect(clippy::missing_trait_methods, reason = "accept default methods")]
|
||||
impl<T> ValueType for Id<T> {
|
||||
#[inline]
|
||||
fn try_from(v: Value) -> Result<Self, ValueTypeErr> {
|
||||
<SeaOrmRepr as ValueType>::try_from(v).map(|id| Self {
|
||||
id,
|
||||
@@ -96,26 +116,32 @@ impl<T> ValueType for Id<T> {
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn type_name() -> String {
|
||||
format!("Id<{}>", &core::any::type_name::<T>())
|
||||
format!("Id<{}>", core::any::type_name::<T>())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn array_type() -> ArrayType {
|
||||
SeaOrmRepr::array_type()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn column_type() -> ColumnType {
|
||||
SeaOrmRepr::column_type()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Id<T>> for Value {
|
||||
#[inline]
|
||||
fn from(value: Id<T>) -> Self {
|
||||
value.id.into()
|
||||
}
|
||||
}
|
||||
|
||||
#[expect(clippy::missing_trait_methods, reason = "accept default methods")]
|
||||
impl<T> TryGetable for Id<T> {
|
||||
#[inline]
|
||||
fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Self, TryGetError> {
|
||||
SeaOrmRepr::try_get_by(res, index).map(|id| Self {
|
||||
id,
|
||||
@@ -125,6 +151,7 @@ impl<T> TryGetable for Id<T> {
|
||||
}
|
||||
|
||||
impl<T> TryFromU64 for Id<T> {
|
||||
#[inline]
|
||||
fn try_from_u64(n: u64) -> Result<Self, DbErr> {
|
||||
SeaOrmRepr::try_from_u64(n).map(|id| Self {
|
||||
id,
|
||||
@@ -134,6 +161,7 @@ impl<T> TryFromU64 for Id<T> {
|
||||
}
|
||||
|
||||
impl<T> Nullable for Id<T> {
|
||||
#[inline]
|
||||
fn null() -> Value {
|
||||
SeaOrmRepr::null()
|
||||
}
|
||||
@@ -148,24 +176,32 @@ mod tests {
|
||||
|
||||
use super::Id;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, DeriveEntityModel)]
|
||||
#[sea_orm(table_name = "ids")]
|
||||
pub struct Model {
|
||||
#[expect(clippy::use_self, reason = "derive macros cause Self to be invalid")]
|
||||
struct Model {
|
||||
#[sea_orm(primary_key, auto_increment = false)]
|
||||
id: Id<Model>,
|
||||
nullable: Option<Id<Model>>,
|
||||
}
|
||||
|
||||
#[expect(clippy::missing_trait_methods, reason = "accept default methods")]
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {}
|
||||
enum Relation {}
|
||||
|
||||
#[test]
|
||||
#[expect(clippy::missing_panics_doc, reason = "unit test")]
|
||||
fn round_trip() {
|
||||
let raw = 1234;
|
||||
let id = Id::<()>::from_raw(raw);
|
||||
assert_eq!(raw, id.into_raw());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "serde")]
|
||||
fn test_serde() {
|
||||
fn ser_de() {
|
||||
let id: Id<()> = Id::from_raw(1234);
|
||||
serde_test::assert_tokens(&id, &[serde_test::Token::I64(1234)]);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
//! `SeaORM` column types for enforcing data consistency.
|
||||
|
||||
pub mod duration;
|
||||
pub mod id;
|
||||
pub mod net;
|
||||
pub mod path;
|
||||
@@ -1,74 +1,89 @@
|
||||
//! [IpAddr], [Ipv4Addr], and [Ipv6Addr] utilities
|
||||
//! [`IpAddr`], [`Ipv4Addr`], and [`Ipv6Addr`] utilities.
|
||||
|
||||
use core::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
||||
|
||||
use sea_orm::sea_query::{ArrayType, Nullable, ValueType, ValueTypeErr};
|
||||
use sea_orm::{ColIdx, ColumnType, DbErr, QueryResult, TryFromU64, TryGetError, TryGetable, Value};
|
||||
|
||||
/// The internal representation used by the database.
|
||||
type SeaOrmRepr = String;
|
||||
|
||||
/// Wrapper around [IpAddr]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
/// Wrapper around [`IpAddr`].
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[cfg_attr(feature = "serde", serde(transparent))]
|
||||
#[repr(transparent)]
|
||||
#[expect(clippy::exhaustive_structs, reason = "unlikely to change")]
|
||||
pub struct IpAddress(pub IpAddr);
|
||||
|
||||
/// Wrapper around [IpAddr]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
/// Wrapper around [`Ipv4Addr`].
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[cfg_attr(feature = "serde", serde(transparent))]
|
||||
#[repr(transparent)]
|
||||
#[expect(clippy::exhaustive_structs, reason = "unlikely to change")]
|
||||
pub struct Ipv4Address(pub Ipv4Addr);
|
||||
|
||||
/// Wrapper around [IpAddr]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
/// Wrapper around [`Ipv6Addr`].
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[cfg_attr(feature = "serde", serde(transparent))]
|
||||
#[repr(transparent)]
|
||||
#[expect(clippy::exhaustive_structs, reason = "unlikely to change")]
|
||||
pub struct Ipv6Address(pub Ipv6Addr);
|
||||
|
||||
/// Implements `SeaORM` traits for `IP` types.
|
||||
macro_rules! impl_addr {
|
||||
($t:ty, $inner:ty, $repr:ty) => {
|
||||
impl From<$inner> for $t {
|
||||
#[inline]
|
||||
fn from(value: $inner) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$t> for $inner {
|
||||
#[inline]
|
||||
fn from(value: $t) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
#[expect(clippy::missing_trait_methods, reason = "accept default methods")]
|
||||
impl ValueType for $t {
|
||||
#[inline]
|
||||
fn try_from(v: Value) -> Result<Self, ValueTypeErr> {
|
||||
<SeaOrmRepr as ValueType>::try_from(v)
|
||||
.and_then(|s| s.parse().map_err(|_| ValueTypeErr))
|
||||
.map(Self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn type_name() -> String {
|
||||
core::any::type_name::<Self>().to_string()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn array_type() -> ArrayType {
|
||||
SeaOrmRepr::array_type()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn column_type() -> ColumnType {
|
||||
SeaOrmRepr::column_type()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$t> for Value {
|
||||
#[inline]
|
||||
fn from(value: $t) -> Self {
|
||||
value.0.to_string().into()
|
||||
}
|
||||
}
|
||||
|
||||
#[expect(clippy::missing_trait_methods, reason = "accept default methods")]
|
||||
impl TryGetable for $t {
|
||||
#[inline]
|
||||
fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Self, TryGetError> {
|
||||
SeaOrmRepr::try_get_by(res, index)
|
||||
.and_then(|s| s.parse().map_err(|_| TryGetError::Null(Self::type_name())))
|
||||
@@ -77,6 +92,7 @@ macro_rules! impl_addr {
|
||||
}
|
||||
|
||||
impl TryFromU64 for $t {
|
||||
#[inline]
|
||||
fn try_from_u64(n: u64) -> Result<Self, DbErr> {
|
||||
SeaOrmRepr::try_from_u64(n)
|
||||
.and_then(|s| {
|
||||
@@ -88,6 +104,7 @@ macro_rules! impl_addr {
|
||||
}
|
||||
|
||||
impl Nullable for $t {
|
||||
#[inline]
|
||||
fn null() -> Value {
|
||||
SeaOrmRepr::null()
|
||||
}
|
||||
@@ -109,10 +126,9 @@ mod tests {
|
||||
|
||||
use super::super::IpAddress;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, DeriveEntityModel)]
|
||||
#[sea_orm(table_name = "ipaddress")]
|
||||
pub struct Model {
|
||||
struct Model {
|
||||
#[sea_orm(primary_key, auto_increment = false)]
|
||||
id: u8,
|
||||
#[sea_orm(primary_key, auto_increment = false)]
|
||||
@@ -120,11 +136,11 @@ mod tests {
|
||||
nullable: Option<IpAddress>,
|
||||
}
|
||||
|
||||
#[expect(clippy::missing_trait_methods, reason = "accept default methods")]
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {}
|
||||
enum Relation {}
|
||||
}
|
||||
mod ipv4address {
|
||||
use sea_orm::{
|
||||
@@ -134,10 +150,9 @@ mod tests {
|
||||
|
||||
use super::super::Ipv4Address;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, DeriveEntityModel)]
|
||||
#[sea_orm(table_name = "ipv4address")]
|
||||
pub struct Model {
|
||||
struct Model {
|
||||
#[sea_orm(primary_key, auto_increment = false)]
|
||||
id: u8,
|
||||
#[sea_orm(primary_key, auto_increment = false)]
|
||||
@@ -145,11 +160,11 @@ mod tests {
|
||||
nullable: Option<Ipv4Address>,
|
||||
}
|
||||
|
||||
#[expect(clippy::missing_trait_methods, reason = "accept default methods")]
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {}
|
||||
enum Relation {}
|
||||
}
|
||||
mod ipv6address {
|
||||
use sea_orm::{
|
||||
@@ -159,10 +174,9 @@ mod tests {
|
||||
|
||||
use super::super::Ipv6Address;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, DeriveEntityModel)]
|
||||
#[sea_orm(table_name = "ipv6address")]
|
||||
pub struct Model {
|
||||
struct Model {
|
||||
#[sea_orm(primary_key, auto_increment = false)]
|
||||
id: u8,
|
||||
#[sea_orm(primary_key, auto_increment = false)]
|
||||
@@ -170,10 +184,10 @@ mod tests {
|
||||
nullable: Option<Ipv6Address>,
|
||||
}
|
||||
|
||||
#[expect(clippy::missing_trait_methods, reason = "accept default methods")]
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {}
|
||||
enum Relation {}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
//! [Path] and [PathBuf] utilities
|
||||
//! [Path] and [`PathBuf`] utilities.
|
||||
|
||||
use std::ffi::OsString;
|
||||
use std::path::{Path, PathBuf};
|
||||
@@ -11,34 +11,42 @@ compile_error!("PathBytes is not supported on Windows");
|
||||
use sea_orm::sea_query::{ArrayType, Nullable, ValueType, ValueTypeErr};
|
||||
use sea_orm::{ColIdx, ColumnType, DbErr, QueryResult, TryFromU64, TryGetError, TryGetable, Value};
|
||||
|
||||
/// The internal representation used by the database.
|
||||
type SeaOrmRepr = Vec<u8>;
|
||||
|
||||
/// Wrapper around [PathBuf] to store paths as bytes in SeaORM
|
||||
/// Wrapper around [`PathBuf`] to store paths as bytes in `SeaORM`.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[cfg_attr(feature = "serde", serde(transparent))]
|
||||
#[repr(transparent)]
|
||||
#[expect(clippy::exhaustive_structs, reason = "unlikely to change")]
|
||||
#[expect(clippy::module_name_repetitions, reason = "Bytes wouldn't make sense")]
|
||||
pub struct PathBytes(pub PathBuf);
|
||||
|
||||
impl From<PathBuf> for PathBytes {
|
||||
#[inline]
|
||||
fn from(value: PathBuf) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PathBytes> for PathBuf {
|
||||
#[inline]
|
||||
fn from(value: PathBytes) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<Path> for PathBytes {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &Path {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[expect(clippy::missing_trait_methods, reason = "accept default methods")]
|
||||
impl ValueType for PathBytes {
|
||||
#[inline]
|
||||
fn try_from(v: Value) -> Result<Self, ValueTypeErr> {
|
||||
<SeaOrmRepr as ValueType>::try_from(v)
|
||||
.map(OsString::from_vec)
|
||||
@@ -46,26 +54,32 @@ impl ValueType for PathBytes {
|
||||
.map(Self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn type_name() -> String {
|
||||
core::any::type_name::<Self>().to_string()
|
||||
core::any::type_name::<Self>().to_owned()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn array_type() -> ArrayType {
|
||||
SeaOrmRepr::array_type()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn column_type() -> ColumnType {
|
||||
SeaOrmRepr::column_type()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PathBytes> for Value {
|
||||
#[inline]
|
||||
fn from(value: PathBytes) -> Self {
|
||||
value.0.into_os_string().into_vec().into()
|
||||
}
|
||||
}
|
||||
|
||||
#[expect(clippy::missing_trait_methods, reason = "accept default methods")]
|
||||
impl TryGetable for PathBytes {
|
||||
#[inline]
|
||||
fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Self, TryGetError> {
|
||||
SeaOrmRepr::try_get_by(res, index)
|
||||
.map(OsString::from_vec)
|
||||
@@ -75,6 +89,7 @@ impl TryGetable for PathBytes {
|
||||
}
|
||||
|
||||
impl TryFromU64 for PathBytes {
|
||||
#[inline]
|
||||
fn try_from_u64(n: u64) -> Result<Self, DbErr> {
|
||||
SeaOrmRepr::try_from_u64(n)
|
||||
.map(OsString::from_vec)
|
||||
@@ -84,6 +99,7 @@ impl TryFromU64 for PathBytes {
|
||||
}
|
||||
|
||||
impl Nullable for PathBytes {
|
||||
#[inline]
|
||||
fn null() -> Value {
|
||||
SeaOrmRepr::null()
|
||||
}
|
||||
@@ -98,10 +114,9 @@ mod tests {
|
||||
|
||||
use super::PathBytes;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, DeriveEntityModel)]
|
||||
#[sea_orm(table_name = "paths")]
|
||||
pub struct Model {
|
||||
struct Model {
|
||||
#[sea_orm(primary_key, auto_increment = false)]
|
||||
id: u8,
|
||||
#[sea_orm(primary_key, auto_increment = false)]
|
||||
@@ -109,9 +124,9 @@ mod tests {
|
||||
nullable: Option<PathBytes>,
|
||||
}
|
||||
|
||||
#[expect(clippy::missing_trait_methods, reason = "accept default methods")]
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {}
|
||||
enum Relation {}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
//! Helpers for working with SeaORM
|
||||
//! Helpers for working with `SeaORM`.
|
||||
|
||||
mod upsert;
|
||||
pub use upsert::UpsertTrait;
|
||||
@@ -0,0 +1,66 @@
|
||||
//! Provides [`UpsertTrait`] for performing an upsert into a database.
|
||||
|
||||
use sea_orm::sea_query::{IntoColumnRef as _, OnConflict};
|
||||
use sea_orm::{ActiveModelTrait, EntityTrait, Insert, Iterable as _};
|
||||
|
||||
/// This trait add a method on [Insert] to allow for upsert behavior.
|
||||
pub trait UpsertTrait: private::Sealed {
|
||||
/// Set ON CONFLICT on primary key to update all other columns.
|
||||
#[must_use]
|
||||
fn on_conflict_upsert(self) -> Self;
|
||||
}
|
||||
|
||||
/// Returns an [Iterator] over the `PrimaryKey` columns of an [`ActiveModelTrait`].
|
||||
fn primary_key_iter<A: ActiveModelTrait>()
|
||||
-> impl Iterator<Item = <A::Entity as EntityTrait>::PrimaryKey> {
|
||||
<A::Entity as EntityTrait>::PrimaryKey::iter()
|
||||
}
|
||||
|
||||
/// Returns an [Iterator] over the [`EntityTrait`] columns of an [`ActiveModelTrait`].
|
||||
fn column_iter<A: ActiveModelTrait>() -> impl Iterator<Item = <A::Entity as EntityTrait>::Column> {
|
||||
<<A as ActiveModelTrait>::Entity as EntityTrait>::Column::iter()
|
||||
}
|
||||
|
||||
impl<A: ActiveModelTrait> private::Sealed for Insert<A> {}
|
||||
impl<A: ActiveModelTrait> UpsertTrait for Insert<A> {
|
||||
#[inline]
|
||||
fn on_conflict_upsert(self) -> Self {
|
||||
self.on_conflict(
|
||||
OnConflict::columns(primary_key_iter::<A>())
|
||||
.update_columns(column_iter::<A>().filter(|col| {
|
||||
!primary_key_iter::<A>().any(|pk| pk.into_column_ref() == col.into_column_ref())
|
||||
}))
|
||||
.to_owned(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Private module.
|
||||
mod private {
|
||||
/// Sealed trait to prevent implementations of `UpsertTrait`.
|
||||
#[expect(unnameable_types, reason = "sealed trait")]
|
||||
pub trait Sealed {}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{UpsertTrait, private::Sealed};
|
||||
|
||||
#[test]
|
||||
fn seal() {
|
||||
struct S;
|
||||
|
||||
impl Sealed for S {}
|
||||
impl UpsertTrait for S {
|
||||
fn on_conflict_upsert(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
fn is_sealed<T: Sealed>() {}
|
||||
fn is_upsert<T: UpsertTrait>() {}
|
||||
|
||||
is_sealed::<S>();
|
||||
is_upsert::<S>();
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
//! Helpers for defining SeaORM schemas
|
||||
//! Helpers for defining `SeaORM` schemas.
|
||||
|
||||
#[cfg(feature = "sqlite")]
|
||||
mod sqlite;
|
||||
@@ -1,16 +1,18 @@
|
||||
//! Helper functions for declaring `SQLite` schemas.
|
||||
|
||||
use sea_orm_migration::schema::{integer_null, string};
|
||||
use sea_orm_migration::sea_query::{ColumnDef, IntoIden};
|
||||
|
||||
/// Sets the column to be an alias for SQLite's rowid.
|
||||
///
|
||||
/// Required conditions:
|
||||
/// - This column must *not* be auto_increment
|
||||
/// - There cannot be other primary_key columns in the table
|
||||
/// - This column must *not* be `auto_increment`
|
||||
/// - There cannot be other `primary_key` columns in the table
|
||||
///
|
||||
/// When using `DeriveEntityModel`, the type must be `i64` (or equivalent)
|
||||
/// and should be tagged with:
|
||||
///
|
||||
/// `#[sea_orm(primary_key, auto_increment = false)]`
|
||||
/// > `#[sea_orm(primary_key, auto_increment = false)]`.
|
||||
///
|
||||
/// When using the new entity format:
|
||||
///
|
||||
@@ -25,11 +27,12 @@ use sea_orm_migration::sea_query::{ColumnDef, IntoIden};
|
||||
/// id: Id<Model>,
|
||||
/// }
|
||||
/// impl ActiveModelBehavior for ActiveModel {}
|
||||
#[inline]
|
||||
pub fn sqlite_rowid_alias<T: IntoIden>(name: T) -> ColumnDef {
|
||||
integer_null(name).primary_key().take()
|
||||
}
|
||||
|
||||
/// Set the column to be a case insensitive string
|
||||
/// Set the column to be a case insensitive string.
|
||||
///
|
||||
/// When using the new entity format:
|
||||
///
|
||||
@@ -46,6 +49,7 @@ pub fn sqlite_rowid_alias<T: IntoIden>(name: T) -> ColumnDef {
|
||||
/// nocase: String,
|
||||
/// }
|
||||
/// impl ActiveModelBehavior for ActiveModel {}
|
||||
#[inline]
|
||||
pub fn sqlite_case_insensitive_string<T: IntoIden>(name: T) -> ColumnDef {
|
||||
string(name).extra("COLLATE NOCASE").take()
|
||||
}
|
||||
@@ -54,7 +58,12 @@ pub fn sqlite_case_insensitive_string<T: IntoIden>(name: T) -> ColumnDef {
|
||||
mod entity_tests {
|
||||
use sea_orm::{ConnectOptions, Database, DatabaseConnection};
|
||||
|
||||
pub async fn new_initialized_memory_db() -> DatabaseConnection {
|
||||
/// Create and initialize a new in-memory SQLite database.
|
||||
///
|
||||
/// # Panics
|
||||
/// If the database driver fails to connect, or if the schema registry fails
|
||||
/// to sync the database schema.
|
||||
async fn new_initialized_memory_db() -> DatabaseConnection {
|
||||
let options = ConnectOptions::new("sqlite::memory:");
|
||||
|
||||
let db = Database::connect(options)
|
||||
@@ -67,6 +76,22 @@ mod entity_tests {
|
||||
db
|
||||
}
|
||||
|
||||
#[expect(
|
||||
clippy::unused_async_trait_impl,
|
||||
reason = "sea_orm::model generates unpolled futures"
|
||||
)]
|
||||
#[expect(
|
||||
clippy::same_name_method,
|
||||
reason = "sea_orm::model generates the same method names"
|
||||
)]
|
||||
#[expect(
|
||||
clippy::allow_attributes,
|
||||
reason = "under different conditions sea_orm::model generates different code"
|
||||
)]
|
||||
#[allow(
|
||||
clippy::future_not_send,
|
||||
reason = "sea_orm::model generates un-send futures"
|
||||
)]
|
||||
mod rowid_test {
|
||||
use sea_orm::ActiveValue::{NotSet, Set};
|
||||
use sea_orm::entity::prelude::*;
|
||||
@@ -76,14 +101,18 @@ mod entity_tests {
|
||||
#[sea_orm::model]
|
||||
#[derive(Debug, Clone, DeriveEntityModel)]
|
||||
#[sea_orm(table_name = "rowid_test")]
|
||||
pub struct Model {
|
||||
struct Model {
|
||||
#[sea_orm(primary_key, auto_increment = false)]
|
||||
id: Id<Model>,
|
||||
}
|
||||
#[expect(clippy::missing_trait_methods, reason = "accept default methods")]
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
#[cfg(not(miri))]
|
||||
#[tokio::test]
|
||||
async fn test_sqlite_rowid_alias() {
|
||||
#[expect(clippy::missing_panics_doc, reason = "unit test")]
|
||||
#[expect(clippy::default_numeric_fallback, reason = "numbers are not ambiguous")]
|
||||
async fn sqlite_rowid_alias() {
|
||||
let db = super::new_initialized_memory_db().await;
|
||||
|
||||
// Starts at 1 and increments
|
||||
@@ -98,7 +127,7 @@ mod entity_tests {
|
||||
let model = ActiveModel {
|
||||
id: Set(Id::from_raw(i)),
|
||||
};
|
||||
model.delete(&db).await.expect("delete");
|
||||
_ = model.delete(&db).await.expect("delete");
|
||||
let model = ActiveModel { id: NotSet };
|
||||
let model = model.insert(&db).await.expect("insert");
|
||||
assert_eq!(model.id.into_raw(), i);
|
||||
@@ -156,6 +185,22 @@ mod entity_tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[expect(
|
||||
clippy::unused_async_trait_impl,
|
||||
reason = "sea_orm::model generates unpolled futures"
|
||||
)]
|
||||
#[expect(
|
||||
clippy::same_name_method,
|
||||
reason = "sea_orm::model generates the same method names"
|
||||
)]
|
||||
#[expect(
|
||||
clippy::allow_attributes,
|
||||
reason = "under different conditions sea_orm::model generates different code"
|
||||
)]
|
||||
#[allow(
|
||||
clippy::future_not_send,
|
||||
reason = "sea_orm::model generates un-send futures"
|
||||
)]
|
||||
mod nocase_test {
|
||||
use sea_orm::ActiveValue::Set;
|
||||
use sea_orm::entity::prelude::*;
|
||||
@@ -163,17 +208,20 @@ mod entity_tests {
|
||||
#[sea_orm::model]
|
||||
#[derive(Debug, Clone, DeriveEntityModel)]
|
||||
#[sea_orm(table_name = "nocase_test")]
|
||||
pub struct Model {
|
||||
struct Model {
|
||||
#[sea_orm(primary_key, auto_increment = false)]
|
||||
id: i64,
|
||||
case: String,
|
||||
#[sea_orm(extra = "COLLATE NOCASE")]
|
||||
nocase: String,
|
||||
}
|
||||
#[expect(clippy::missing_trait_methods, reason = "accept default methods")]
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
#[cfg(not(miri))]
|
||||
#[tokio::test]
|
||||
async fn test_sqlite_case_insensitive_string() {
|
||||
#[expect(clippy::missing_panics_doc, reason = "unit test")]
|
||||
async fn sqlite_case_insensitive_string() {
|
||||
let db = super::new_initialized_memory_db().await;
|
||||
|
||||
let i = 50;
|
||||
@@ -185,7 +233,7 @@ mod entity_tests {
|
||||
case: Set("abcd".to_owned()),
|
||||
nocase: Set("abcd".to_owned()),
|
||||
};
|
||||
model.insert(&db).await.expect("insert");
|
||||
drop(model.insert(&db).await.expect("insert"));
|
||||
}
|
||||
|
||||
// Query by uppercase string
|
||||
@@ -216,7 +264,7 @@ mod entity_tests {
|
||||
mod tests {
|
||||
use sea_orm::ActiveValue::{NotSet, Set};
|
||||
use sea_orm::entity::prelude::*;
|
||||
use sea_orm::{ConnectOptions, Database, DatabaseConnection};
|
||||
use sea_orm::{ConnectOptions, Database};
|
||||
use sea_orm_migration::async_trait::async_trait;
|
||||
use sea_orm_migration::prelude::*;
|
||||
|
||||
@@ -224,14 +272,21 @@ mod tests {
|
||||
|
||||
use super::{sqlite_case_insensitive_string, sqlite_rowid_alias};
|
||||
|
||||
#[expect(clippy::missing_panics_doc, reason = "unit test")]
|
||||
async fn new_memory_db() -> DatabaseConnection {
|
||||
let options = ConnectOptions::new("sqlite::memory:");
|
||||
Database::connect(options).await.expect("Database::connect")
|
||||
}
|
||||
|
||||
#[cfg(not(miri))]
|
||||
#[tokio::test]
|
||||
#[expect(unused_qualifications, reason = "derive macro qualifies everything")]
|
||||
#[expect(clippy::missing_panics_doc, reason = "unit test")]
|
||||
#[expect(clippy::default_numeric_fallback, reason = "numbers are not ambiguous")]
|
||||
#[expect(clippy::redundant_test_prefix, reason = "name collision")]
|
||||
async fn test_sqlite_rowid_alias() {
|
||||
struct Migrator;
|
||||
#[expect(clippy::missing_trait_methods, reason = "accept default methods")]
|
||||
impl MigratorTrait for Migrator {
|
||||
fn migrations() -> Vec<Box<dyn MigrationTrait>> {
|
||||
vec![Box::new(Migration)]
|
||||
@@ -246,7 +301,12 @@ mod tests {
|
||||
#[derive(DeriveMigrationName)]
|
||||
struct Migration;
|
||||
#[async_trait]
|
||||
#[expect(clippy::missing_trait_methods, reason = "accept default methods")]
|
||||
impl MigrationTrait for Migration {
|
||||
#[expect(
|
||||
elided_lifetimes_in_paths,
|
||||
reason = "async_trait causes lifetimes to be strange"
|
||||
)]
|
||||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.create_table(
|
||||
@@ -263,17 +323,21 @@ mod tests {
|
||||
|
||||
#[derive(Debug, Clone, DeriveEntityModel)]
|
||||
#[sea_orm(table_name = "test_table")]
|
||||
pub struct Model {
|
||||
#[expect(clippy::use_self, reason = "derive macros cause Self to be invalid")]
|
||||
struct Model {
|
||||
#[sea_orm(primary_key, auto_increment = false)]
|
||||
id: Id<Model>,
|
||||
}
|
||||
#[derive(Debug, EnumIter)]
|
||||
pub enum Relation {}
|
||||
enum Relation {}
|
||||
#[expect(clippy::missing_trait_methods, reason = "accept default methods")]
|
||||
impl RelationTrait for Relation {
|
||||
#[expect(clippy::panic, reason = "no relation")]
|
||||
fn def(&self) -> RelationDef {
|
||||
panic!("No RelationDef")
|
||||
}
|
||||
}
|
||||
#[expect(clippy::missing_trait_methods, reason = "accept default methods")]
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
let db = new_memory_db().await;
|
||||
@@ -291,7 +355,7 @@ mod tests {
|
||||
let model = ActiveModel {
|
||||
id: Set(Id::from_raw(i)),
|
||||
};
|
||||
model.delete(&db).await.expect("delete");
|
||||
_ = model.delete(&db).await.expect("delete");
|
||||
let model = ActiveModel { id: NotSet };
|
||||
let model = model.insert(&db).await.expect("insert");
|
||||
assert_eq!(model.id.into_raw(), i);
|
||||
@@ -348,9 +412,14 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(miri))]
|
||||
#[tokio::test]
|
||||
#[expect(unused_qualifications, reason = "derive macro qualifies everything")]
|
||||
#[expect(clippy::missing_panics_doc, reason = "unit test")]
|
||||
#[expect(clippy::redundant_test_prefix, reason = "name collision")]
|
||||
async fn test_sqlite_case_insensitive_string() {
|
||||
struct Migrator;
|
||||
#[expect(clippy::missing_trait_methods, reason = "accept default methods")]
|
||||
impl MigratorTrait for Migrator {
|
||||
fn migrations() -> Vec<Box<dyn MigrationTrait>> {
|
||||
vec![Box::new(Migration)]
|
||||
@@ -366,7 +435,12 @@ mod tests {
|
||||
#[derive(DeriveMigrationName)]
|
||||
struct Migration;
|
||||
#[async_trait]
|
||||
#[expect(clippy::missing_trait_methods, reason = "accept default methods")]
|
||||
impl MigrationTrait for Migration {
|
||||
#[expect(
|
||||
elided_lifetimes_in_paths,
|
||||
reason = "async_trait causes lifetimes to be strange"
|
||||
)]
|
||||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.create_table(
|
||||
@@ -384,18 +458,21 @@ mod tests {
|
||||
|
||||
#[derive(Debug, Clone, DeriveEntityModel)]
|
||||
#[sea_orm(table_name = "test_table")]
|
||||
pub struct Model {
|
||||
struct Model {
|
||||
#[sea_orm(primary_key, auto_increment = false)]
|
||||
id: i64,
|
||||
ci_str: String,
|
||||
}
|
||||
#[derive(Debug, EnumIter)]
|
||||
pub enum Relation {}
|
||||
enum Relation {}
|
||||
#[expect(clippy::missing_trait_methods, reason = "accept default methods")]
|
||||
impl RelationTrait for Relation {
|
||||
#[expect(clippy::panic, reason = "no relation")]
|
||||
fn def(&self) -> RelationDef {
|
||||
panic!("No RelationDef")
|
||||
}
|
||||
}
|
||||
#[expect(clippy::missing_trait_methods, reason = "accept default methods")]
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
let db = new_memory_db().await;
|
||||
@@ -409,7 +486,7 @@ mod tests {
|
||||
id: Set(i),
|
||||
ci_str: Set("abcd".to_owned()),
|
||||
};
|
||||
model.insert(&db).await.expect("insert");
|
||||
drop(model.insert(&db).await.expect("insert"));
|
||||
}
|
||||
|
||||
// Query by uppercase string
|
||||
@@ -0,0 +1,43 @@
|
||||
set minimum-version := '1.55.0'
|
||||
set default-list
|
||||
|
||||
alias update := update-min
|
||||
|
||||
all:
|
||||
just all-min
|
||||
just all-max
|
||||
all-min: update-min build lint test example doc format
|
||||
all-max: update-max build lint test example doc format
|
||||
|
||||
update-min:
|
||||
cargo +nightly update -Z direct-minimal-versions
|
||||
|
||||
update-max:
|
||||
cargo update
|
||||
|
||||
build:
|
||||
cargo hack --feature-powerset build
|
||||
|
||||
lint:
|
||||
cargo hack --feature-powerset clippy -- -D warnings
|
||||
cargo hack --feature-powerset clippy --tests -- -D warnings
|
||||
|
||||
test:
|
||||
cargo hack --feature-powerset test
|
||||
cargo +1.94 hack --feature-powerset test
|
||||
cargo +nightly hack --feature-powerset miri test
|
||||
|
||||
example:
|
||||
cargo run --example=migrations --features=sqlite
|
||||
|
||||
doc *args:
|
||||
RUSTDOCFLAGS="--cfg docsrs -D warnings" cargo +nightly doc \
|
||||
--workspace --all-features --document-private-items \
|
||||
--lib --bins --no-deps --locked \
|
||||
{{ args }}
|
||||
|
||||
format:
|
||||
cargo fmt --check
|
||||
|
||||
install:
|
||||
cargo install --path crates/lint-policy-cli
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "stable"
|
||||
channel = "1.98"
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
//! SeaORM column types for enforcing data consistency
|
||||
|
||||
pub mod duration;
|
||||
pub mod id;
|
||||
pub mod ip;
|
||||
pub mod path;
|
||||
@@ -1,34 +0,0 @@
|
||||
use sea_orm::sea_query::{IntoColumnRef, OnConflict};
|
||||
use sea_orm::{ActiveModelTrait, EntityTrait, Insert, Iterable};
|
||||
|
||||
/// This trait add a method on [Insert] to allow for upsert behavior
|
||||
pub trait UpsertTrait: private::Sealed {
|
||||
/// Set ON CONFLICT on primary key to update all other columns
|
||||
fn on_conflict_upsert(self) -> Self;
|
||||
}
|
||||
|
||||
fn primary_key_iter<A: ActiveModelTrait>()
|
||||
-> impl Iterator<Item = <A::Entity as EntityTrait>::PrimaryKey> {
|
||||
<A::Entity as EntityTrait>::PrimaryKey::iter()
|
||||
}
|
||||
|
||||
fn column_iter<A: ActiveModelTrait>() -> impl Iterator<Item = <A::Entity as EntityTrait>::Column> {
|
||||
<<A as ActiveModelTrait>::Entity as EntityTrait>::Column::iter()
|
||||
}
|
||||
|
||||
impl<A: ActiveModelTrait> UpsertTrait for Insert<A> {
|
||||
fn on_conflict_upsert(self) -> Self {
|
||||
self.on_conflict(
|
||||
OnConflict::columns(primary_key_iter::<A>())
|
||||
.update_columns(column_iter::<A>().filter(|col| {
|
||||
!primary_key_iter::<A>().any(|pk| pk.into_column_ref() == col.into_column_ref())
|
||||
}))
|
||||
.to_owned(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
mod private {
|
||||
pub trait Sealed {}
|
||||
impl<A: ::sea_orm::ActiveModelTrait> Sealed for ::sea_orm::Insert<A> {}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
toml-version = "v1.0.0"
|
||||
|
||||
[format.rules]
|
||||
indent-style = "tab"
|
||||
indent-width = 4
|
||||
Reference in New Issue
Block a user