sqll/lib.rs
1//! [<img alt="github" src="https://img.shields.io/badge/github-udoprog/sqll-8da0cb?style=for-the-badge&logo=github" height="20">](https://github.com/udoprog/sqll)
2//! [<img alt="crates.io" src="https://img.shields.io/crates/v/sqll.svg?style=for-the-badge&color=fc8d62&logo=rust" height="20">](https://crates.io/crates/sqll)
3//! [<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-sqll-66c2a5?style=for-the-badge&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K" height="20">](https://docs.rs/sqll)
4//!
5//! Efficient interface to [SQLite] that doesn't get in your way.
6//!
7//! <br>
8//!
9//! ## Usage
10//!
11//! The two primary methods to interact with an SQLite database through this
12//! crate is through [`execute`] and [`prepare`].
13//!
14//! The [`execute`] function is used for batch statements, and allows for
15//! multiple queries to be specified. [`prepare`] only allows for a single
16//! statement to be specified, but in turn permits [reading rows] and [binding
17//! query parameters].
18//!
19//! Special consideration needs to be taken about the thread safety of
20//! connections. You can read more about that in the [`Connection`]
21//! documentation.
22//!
23//! You can find simple examples of this below.
24//!
25//! <br>
26//!
27//! #### Examples
28//!
29//! * [`examples/persons.rs`] - A simple table with users, a primary key,
30//! inserting and querying.
31//! * [`examples/axum.rs`] - Create an in-memory database connection and serve
32//! it using [`axum`]. This showcases how to properly handle external
33//! synchronization for the best performance in a real-world scenario.
34//! * [`examples/tokio_async.rs`] - Using `sqll` in an asynchronous context with
35//! `tokio`.
36//!
37//! <br>
38//!
39//! #### Connecting and querying
40//!
41//! Here is a simple example of setting up an in-memory connection, creating a
42//! table, inserting and querying back some rows:
43//!
44//! ```
45//! use sqll::{Connection, Result};
46//!
47//! let c = Connection::open_in_memory()?;
48//!
49//! c.execute(r#"
50//! CREATE TABLE users (name TEXT, age INTEGER);
51//!
52//! INSERT INTO users VALUES ('Alice', 42);
53//! INSERT INTO users VALUES ('Bob', 52);
54//! "#)?;
55//!
56//! let results = c.prepare("SELECT name, age FROM users ORDER BY age")?
57//! .iter::<(String, u32)>()
58//! .collect::<Result<Vec<_>>>()?;
59//!
60//! assert_eq!(results, [("Alice".to_string(), 42), ("Bob".to_string(), 52)]);
61//! # Ok::<_, sqll::Error>(())
62//! ```
63//!
64//! <br>
65//!
66//! #### The [`Row`] trait.
67//!
68//! The [`Row`] trait can be used to conveniently read rows from a statement
69//! using [`next`]. It can be conveniently implemented using the [`Row`
70//! derive].
71//!
72//! ```
73//! use sqll::{Connection, Row};
74//!
75//! #[derive(Row)]
76//! struct Person<'stmt> {
77//! name: &'stmt str,
78//! age: u32,
79//! }
80//!
81//! let mut c = Connection::open_in_memory()?;
82//!
83//! c.execute(r#"
84//! CREATE TABLE users (name TEXT, age INTEGER);
85//!
86//! INSERT INTO users VALUES ('Alice', 42);
87//! INSERT INTO users VALUES ('Bob', 52);
88//! "#)?;
89//!
90//! let mut results = c.prepare("SELECT name, age FROM users ORDER BY age")?;
91//!
92//! while let Some(person) = results.next::<Person<'_>>()? {
93//! println!("{} is {} years old", person.name, person.age);
94//! }
95//! # Ok::<_, sqll::Error>(())
96//! ```
97//!
98//! <br>
99//!
100//! #### The [`Bind`] trait.
101//!
102//! The [`Bind`] trait can be used to conveniently [`bind`] parameters to
103//! prepared statements, and it can conveniently be implemented for structs
104//! using the [`Bind` derive].
105//!
106//! ```
107//! use sqll::{Bind, Connection, Row};
108//!
109//! #[derive(Bind, Row, PartialEq, Debug)]
110//! #[sql(named)]
111//! struct Person<'stmt> {
112//! name: &'stmt str,
113//! age: u32,
114//! }
115//!
116//! let c = Connection::open_in_memory()?;
117//!
118//! c.execute(r#"
119//! CREATE TABLE persons (name TEXT, age INTEGER);
120//! "#)?;
121//!
122//! let mut stmt = c.prepare("INSERT INTO persons (name, age) VALUES (:name, :age)")?;
123//!
124//! stmt.execute(Person { name: "Alice", age: 30 })?;
125//! stmt.reset()?;
126//!
127//! stmt.execute(Person { name: "Bob", age: 40 })?;
128//! stmt.reset()?;
129//!
130//! let mut query = c.prepare("SELECT name, age FROM persons ORDER BY age")?;
131//!
132//! let p = query.next::<Person<'_>>()?;
133//! assert_eq!(p, Some(Person { name: "Alice", age: 30 }));
134//!
135//! let p = query.next::<Person<'_>>()?;
136//! assert_eq!(p, Some(Person { name: "Bob", age: 40 }));
137//!
138//! query.reset()?;
139//! # Ok::<_, sqll::Error>(())
140//! ```
141//!
142//! <br>
143//!
144//! #### Efficient use of prepared Statements
145//!
146//! Correct handling of prepared statements are crucial to get good performance
147//! out of sqlite. They contain all the state associated with a query and are
148//! expensive to construct so they should be re-used.
149//!
150//! Using a [`PrepareWith::persistent`] prepared statement to perform multiple
151//! queries:
152//!
153//! ```
154//! use sqll::Connection;
155//!
156//! let c = Connection::open_in_memory()?;
157//!
158//! c.execute(r#"
159//! CREATE TABLE users (name TEXT, age INTEGER);
160//!
161//! INSERT INTO users VALUES ('Alice', 42);
162//! INSERT INTO users VALUES ('Bob', 52);
163//! "#)?;
164//!
165//! let mut stmt = c.prepare_with("SELECT * FROM users WHERE age > ?")
166//! .persistent()
167//! .build()?;
168//!
169//! let mut rows = Vec::new();
170//!
171//! for age in [40, 50] {
172//! stmt.bind(age)?;
173//!
174//! while let Some(row) = stmt.next::<(String, i64)>()? {
175//! rows.push(row);
176//! }
177//!
178//! stmt.reset()?;
179//! }
180//!
181//! let expected = vec![
182//! (String::from("Alice"), 42),
183//! (String::from("Bob"), 52),
184//! (String::from("Bob"), 52),
185//! ];
186//!
187//! assert_eq!(rows, expected);
188//! # Ok::<_, sqll::Error>(())
189//! ```
190//!
191//! <br>
192//!
193//! #### Use in asynchronous contexts
194//!
195//! In order for sqlite to be used in asynchronous contexts, the [`Statement`]
196//! object usually needs to be `Send` and external synchronization necessary.
197//! Since sqlite is a synchronous library we have to defer any work done to a
198//! thread pool such as the one provided by [`tokio::task::spawn_blocking`]. To
199//! make a [`Statement`] `Send` you can use [`Statement::into_send`], but using
200//! it is `unsafe` since correct behavior depends on the build and runtime
201//! configuration of the sqlite library in use.
202//!
203//! See the [`tokio_async` example] for a complete example.
204//!
205//! <br>
206//!
207//! ## Features
208//!
209//! * `std` - Enable usage of the Rust standard library. Enabled by default.
210//! * `alloc` - Enable usage of the Rust alloc library. This is required and is
211//! enabled by default. Disabling this option will currently cause a compile
212//! error.
213//! * `derive` - Add a dependency to and re-export of the [`Row` derive]
214//! macro.
215//! * `bundled` - Use a bundled version of sqlite. The bundle is provided by the
216//! [`sqll-sys`] crate and the sqlite version used is part of the build
217//! metadata of that crate[^sqll-sys].
218//! * `threadsafe` - Enable usage of sqlite with the threadsafe option set. We
219//! assume any system level libraries have this build option enabled. If this
220//! is disabled the `bundled` feature has to be enabled. If `threadsafe` is
221//! disabled, `Connection` and `Statement` does not implement `Send`. But it
222//! is also important to understand that if this option is not set, sqlite
223//! **may not be used by multiple threads at all** even if threads have
224//! distinct connections. To disable mutexes which allows for efficient one
225//! connection per thread the [`OpenOptions::no_mutex`] option should be used
226//! instead[^sqll-sys].
227//! * `strict` - Enable usage of sqlite with the strict compiler options
228//! enabled[^sqll-sys].
229//!
230//! [^sqll-sys]: This is a forwarded sqll-sys option, see <https://docs.rs/sqll-sys>.
231//!
232//! <br>
233//!
234//! ## License
235//!
236//! This is a rewrite of the [`sqlite` crate], and components used from there
237//! have been copied under the MIT license.
238//!
239//! [`axum`]: https://docs.rs/axum
240//! [`Bind` derive]: https://docs.rs/sqll/latest/sqll/derive.Bind.html
241//! [`bind`]: https://docs.rs/sqll/latest/sqll/struct.Statement.html#method.bind
242//! [`Bind`]: https://docs.rs/sqll/latest/sqll/trait.Bind.html
243//! [`Connection`]: https://docs.rs/sqll/latest/sqll/struct.Connection.html#thread-safety
244//! [`examples/axum.rs`]: https://github.com/udoprog/sqll/blob/main/examples/axum.rs
245//! [`examples/persons.rs`]: https://github.com/udoprog/sqll/blob/main/examples/persons.rs
246//! [`examples/tokio_async.rs`]: https://github.com/udoprog/sqll/blob/main/examples/tokio_async.rs
247//! [`execute`]: https://docs.rs/sqll/latest/sqll/struct.Connection.html#method.execute
248//! [`next`]: https://docs.rs/sqll/latest/sqll/struct.Statement.html#method.next
249//! [`OpenOptions::no_mutex`]: https://docs.rs/sqll/latest/sqll/struct.OpenOptions.html#method.no_mutex
250//! [`prepare_with`]: https://docs.rs/sqll/latest/sqll/struct.Connection.html#method.prepare_with
251//! [`prepare`]: https://docs.rs/sqll/latest/sqll/struct.Connection.html#method.prepare
252//! [`PrepareWith::persistent`]: https://docs.rs/sqll/latest/sqll/struct.PrepareWith.html#method.persistent
253//! [`Row` derive]: https://docs.rs/sqll/latest/sqll/derive.Row.html
254//! [`Row`]: https://docs.rs/sqll/latest/sqll/trait.Row.html
255//! [`sqlite` crate]: https://github.com/stainless-steel/sqlite
256//! [`sqll-sys`]: https://crates.io/crates/sqll-sys
257//! [`Statement::into_send`]: https://docs.rs/sqll/latest/sqll/struct.Statement.html#method.into_send
258//! [`Statement`]: https://docs.rs/sqll/latest/sqll/struct.Statement.html
259//! [`tokio_async` example]: https://github.com/udoprog/sqll/blob/main/examples/tokio_async.rs
260//! [`tokio::task::spawn_blocking`]: https://docs.rs/tokio/latest/tokio/task/fn.spawn_blocking.html
261//! [binding query parameters]: https://docs.rs/sqll/latest/sqll/struct.Statement.html#method.bind
262//! [calling `execute`]: https://docs.rs/sqll/latest/sqll/struct.Connection.html#method.execute
263//! [reading rows]: https://docs.rs/sqll/latest/sqll/struct.Statement.html#method.next
264//! [SQLite]: https://www.sqlite.org
265
266#![no_std]
267#![allow(clippy::module_inception)]
268#![allow(clippy::new_without_default)]
269#![allow(clippy::should_implement_trait)]
270#![warn(rustdoc::broken_intra_doc_links)]
271#![cfg_attr(docsrs, feature(doc_cfg))]
272
273#[cfg(feature = "std")]
274extern crate std;
275
276#[cfg(feature = "alloc")]
277extern crate alloc;
278
279#[cfg(test)]
280mod tests;
281
282mod bind;
283mod bind_value;
284mod bytes;
285mod code;
286mod column;
287mod connection;
288mod error;
289mod ffi;
290mod fixed_blob;
291mod fixed_text;
292mod from_column;
293mod from_unsized_column;
294mod index;
295mod open_options;
296#[cfg(feature = "alloc")]
297mod owned;
298#[cfg(feature = "alloc")]
299mod owned_bytes;
300mod row;
301mod statement;
302mod text;
303pub mod ty;
304mod utils;
305mod value;
306mod value_type;
307mod version;
308
309#[doc(inline)]
310pub use self::bind::Bind;
311#[doc(inline)]
312pub use self::bind_value::BindValue;
313#[doc(inline)]
314pub use self::code::Code;
315#[doc(inline)]
316pub use self::column::Column;
317#[doc(inline)]
318pub use self::connection::{Connection, Prepare, PrepareWith, SendConnection};
319#[doc(inline)]
320pub use self::error::{CapacityError, DatabaseNotFound, Error, NotThreadSafe, Result};
321#[doc(inline)]
322pub use self::fixed_blob::FixedBlob;
323#[doc(inline)]
324pub use self::fixed_text::FixedText;
325#[doc(inline)]
326pub use self::from_column::FromColumn;
327#[doc(inline)]
328pub use self::from_unsized_column::FromUnsizedColumn;
329#[doc(inline)]
330pub use self::index::Index;
331#[doc(inline)]
332pub use self::open_options::OpenOptions;
333#[doc(inline)]
334#[cfg(feature = "alloc")]
335#[cfg_attr(docsrs, cfg(feature = "alloc"))]
336pub use self::owned_bytes::OwnedBytes;
337#[doc(inline)]
338pub use self::row::Row;
339#[doc(inline)]
340pub use self::statement::{Null, SendStatement, State, Statement};
341#[doc(inline)]
342pub use self::text::Text;
343#[doc(inline)]
344pub use self::value::Value;
345#[doc(inline)]
346pub use self::value_type::ValueType;
347#[doc(inline)]
348pub use self::version::{lib_version, lib_version_number};
349
350/// Derive macro for [`Bind`].
351///
352/// This can be used to automatically implement [`Bind`] for a struct and allows
353/// the struct to be used for structured binding of multiple parameters into a
354/// [`Statement`] using [`bind`].
355///
356/// This relies on [`BindValue`] being called for each field in the struct. By
357/// default the `#[sql(index)]` used starts at 0 and is incremented for each
358/// field. This behavior can be modified with attributes.
359///
360/// This also derive also supports convenient use of named parameters through
361/// `[sql(named)]` or a per-field `[sql(name = ..)]`.
362///
363/// ```
364/// use sqll::Bind;
365///
366/// #[derive(Bind)]
367/// struct Person<'stmt> {
368/// name: &'stmt str,
369/// age: u32,
370/// }
371/// ```
372///
373/// [`bind`]: Statement::bind
374///
375/// <br>
376///
377/// ## Container attributes
378///
379/// <br>
380///
381/// #### `#[sql(crate = ..)]`
382///
383/// This attributes allows specifying an alternative path to the `sqll` crate.
384///
385/// This is useful when the crate is renamed from the default `::sqll`.
386///
387/// ```
388/// # extern crate sqll as my_sqll;
389/// use my_sqll::Bind;
390///
391/// #[derive(Bind)]
392/// #[sql(crate = ::my_sqll)]
393/// struct Person<'stmt> {
394/// name: &'stmt str,
395/// age: u32,
396/// }
397/// ```
398///
399/// <br>
400///
401/// #### `#[sql(named)]`
402///
403/// This attribute enabled bindings to use field names instead of go by the
404/// default index.
405///
406/// When using `named`, the default binding names are the field names prefixed
407/// with a `:`. So a field named `name` will bind to `:name`.
408///
409/// ```
410/// use sqll::{Bind, Connection};
411///
412/// #[derive(Bind)]
413/// #[sql(named)]
414/// struct Person<'stmt> {
415/// name: &'stmt str,
416/// age: u32,
417/// }
418///
419/// let c = Connection::open_in_memory()?;
420///
421/// c.execute(r#"
422/// CREATE TABLE persons (name TEXT, age INTEGER);
423/// "#)?;
424///
425/// let mut stmt = c.prepare("INSERT INTO persons (name, age) VALUES (:name, :age)")?;
426/// let person = Person { name: "Alice", age: 30 };
427/// stmt.bind(person)?;
428/// # Ok::<_, sqll::Error>(())
429/// ```
430///
431/// <br>
432///
433/// ## Field attributes
434///
435/// <br>
436///
437/// #### `#[sql(index = ..)]`
438///
439/// This allows the index being used for a particular row to be overriden. Note
440/// that the underlying binding indexes are 1-based, so this is translated to
441/// that by adding 1 to the specified index in order to be compatible with other
442/// derives.
443///
444/// ```
445/// use sqll::{Bind, Connection};
446///
447/// #[derive(Bind)]
448/// struct Person<'stmt> {
449/// #[sql(index = 1)]
450/// name: &'stmt str,
451/// #[sql(index = 0)]
452/// age: u32,
453/// }
454///
455/// let c = Connection::open_in_memory()?;
456///
457/// c.execute(r#"
458/// CREATE TABLE persons (name TEXT, age INTEGER);
459/// "#)?;
460///
461/// let mut stmt = c.prepare("INSERT INTO persons (age, name) VALUES (?, ?)")?;
462///
463/// stmt.execute(Person { name: "Alice", age: 30 })?;
464/// stmt.reset()?;
465/// # Ok::<_, sqll::Error>(())
466/// ```
467///
468/// <br>
469///
470/// #### `#[sql(name = c"..")]`
471///
472/// This allows for specifying an explicit binding name to use, instead of the
473/// default which is to bind by index or a field derived name if `#[sql(named)]`
474/// is set.
475///
476/// Note that the name are literal references to what is expected by the SQLite
477/// API, so must be prefixed with `:`. If a string literal is used, it will be
478/// checked so that it doesn't contain any null bytes.
479///
480/// ```
481/// use sqll::{Bind, Connection};
482///
483/// #[derive(Bind)]
484/// struct Person<'stmt> {
485/// #[sql(name = c":notname")]
486/// name: &'stmt str,
487/// #[sql(name = c":notage")]
488/// age: u32,
489/// }
490/// # #[derive(Bind)]
491/// # struct PersonStr<'stmt> {
492/// # #[sql(name = ":notname")]
493/// # name: &'stmt str,
494/// # #[sql(name = ":notage")]
495/// # age: u32,
496/// # }
497///
498/// let c = Connection::open_in_memory()?;
499///
500/// c.execute(r#"
501/// CREATE TABLE persons (name TEXT, age INTEGER);
502/// "#)?;
503///
504/// let mut stmt = c.prepare("INSERT INTO persons (name, age) VALUES (:notname, :notage)")?;
505/// stmt.execute(Person { name: "Alice", age: 30 })?;
506/// stmt.reset()?;
507/// # stmt.execute(PersonStr { name: "Alice", age: 30 })?;
508/// # stmt.reset()?;
509/// # Ok::<_, sqll::Error>(())
510/// ```
511#[cfg(feature = "derive")]
512#[cfg_attr(docsrs, doc(cfg(feature = "derive")))]
513pub use sqll_macros::Bind;
514
515/// Derive macro for [`Row`].
516///
517/// This can be used to automatically implement [`Row`] for a struct and allows
518/// the struct to be constructed from a [`Statement`] using [`next`] or
519/// [`iter`].
520///
521/// This relies on [`FromColumn`] being called to construct each field in the
522/// struct. By default the `#[sql(index)]` used starts at `0` and is incremented
523/// for each field. This behavior can be modified with attributes.
524///
525/// ```
526/// use sqll::{Connection, Row};
527///
528/// #[derive(Row)]
529/// struct Person<'stmt> {
530/// name: &'stmt str,
531/// age: u32,
532/// }
533///
534/// #[derive(Row)]
535/// struct PersonTuple<'stmt>(&'stmt str, u32);
536///
537/// let mut c = Connection::open_in_memory()?;
538///
539/// c.execute(r#"
540/// CREATE TABLE users (name TEXT, age INTEGER);
541///
542/// INSERT INTO users VALUES ('Alice', 42);
543/// INSERT INTO users VALUES ('Bob', 72);
544/// "#)?;
545///
546/// let mut results = c.prepare("SELECT name, age FROM users ORDER BY age")?;
547///
548/// while let Some(person) = results.next::<Person<'_>>()? {
549/// println!("{} is {} years old", person.name, person.age);
550/// }
551/// # Ok::<_, sqll::Error>(())
552/// ```
553///
554/// [`iter`]: Statement::iter
555/// [`next`]: Statement::next
556///
557/// <br>
558///
559/// ## Container attributes
560///
561/// <br>
562///
563/// #### `#[sql(crate = ..)]`
564///
565/// This attributes allows specifying an alternative path to the `sqll` crate.
566///
567/// This is useful when the crate is renamed from the default `::sqll`.
568///
569/// ```
570/// # extern crate sqll as my_sqll;
571/// use my_sqll::Row;
572///
573/// #[derive(Row)]
574/// #[sql(crate = ::my_sqll)]
575/// struct Person<'stmt> {
576/// name: &'stmt str,
577/// age: u32,
578/// }
579/// ```
580///
581/// <br>
582///
583/// ## Field attributes
584///
585/// <br>
586///
587/// #### `#[sql(index = ..)]`
588///
589/// This allows the index being used for a particular row to be overriden.
590///
591/// ```
592/// use sqll::Row;
593///
594/// #[derive(Row)]
595/// struct Person<'stmt> {
596/// #[sql(index = 1)]
597/// name: &'stmt str,
598/// #[sql(index = 0)]
599/// age: u32,
600/// }
601/// ```
602///
603/// <br>
604///
605/// #### Missing `#[sql(name)]`?
606///
607/// Unlike the `Bind` derive, there is no `#[sql(name = ..)]` attribute for the
608/// `Row` derive. This is due to the underlying API not efficiently supporting
609/// this, and implementing it in `sqll` would either require additional
610/// allocations or inefficient per-row lookups.
611///
612/// Note that it's also not uncommon for column names to simply *not* have a
613/// name, such as when computing expressions like `COUNT(*)` or `column + 1`.
614///
615/// # Errors
616///
617/// Trying to use the same index multiple times results in an error. This is to
618/// ensure that the implementation follows the safety requirements of the [`Row`
619/// trait].
620///
621/// ```compile_fail
622/// use sqll::Row;
623///
624/// #[derive(Row)]
625/// struct InvalidRow {
626/// #[sql(index = 0)]
627/// a: u32,
628/// #[sql(index = 0)]
629/// b: u32,
630/// }
631/// ```
632///
633/// [`Row` trait]: crate::Row
634#[cfg(feature = "derive")]
635#[cfg_attr(docsrs, doc(cfg(feature = "derive")))]
636pub use sqll_macros::Row;