sebastiansulinski/laravel-bits
Laravel Bits is a lightweight collection of small, reusable utilities and helpers for Laravel applications. It provides handy building blocks for common development tasks, helping you keep code concise and organized without adding heavy dependencies.
This package adds query-builder macros (notably updateMany) and model casts (notably AsBoolean) to a standard Laravel app. As of v1.5.4 it is safe to use on PostgreSQL, MySQL and SQLite; earlier releases only really worked on MySQL.
updateMany implementation. That file tells you the exact argument shape (matched column, list of sets, updated columns) faster than any README.AsBoolean cast class next — it is the other public surface and the one that affects your models.Model::find($id)->update([...]) or build a CASE WHEN by hand, updateMany collapses that into one statement:DB::table('products')->updateMany($sets, 'id'); // one UPDATE instead of N
Start by porting one loop in a sync/import job and diffing the results against the old code before touching anything critical.
Per-row bulk updates. updateMany accepts several sets — each set is a group of rows that share the same column values. You can send one set covering all rows, or several sets covering disjoint rows (e.g. one set for price changes, one for stock changes). Since 1.5.4 each CASE carries an ELSE branch that keeps the existing column value, so a row absent from a given set is left alone rather than nulled out. Build sets from your diff, not from your full dataset.
Sync-from-external-source jobs. Map the incoming payload into sets keyed by your natural key, wrap the call in a transaction, and compare affected rows with the size of the input as a cheap sanity check. Chunk large payloads (a few hundred to a few thousand rows per statement) — a single CASE per column per row grows the statement fast and can hit parameter limits.
Reserved-word and prefixed schemas. Table, matched column and every updated column are now quoted through the connection's grammar. You can target columns named order, group, key or default without hand-quoting, and the connection's table prefix is applied automatically — do not pass a prefixed table name yourself.
Boolean columns. Pair AsBoolean on the model with updates that write real booleans (true/false) rather than 1/0. The cast normalises reads across engines; updateMany normalises the write path. Keep both consistent or you will see 1 vs true mismatches in JSON responses between MySQL and PostgreSQL environments.
CI matrix. Mirror the package's own approach: run your suite against PostgreSQL and MySQL by pointing LARAVEL_BITS_TEST_PGSQL_URL and LARAVEL_BITS_TEST_MYSQL_URL at service containers. Additionally, add a cheap grammar-only test that compiles an updateMany statement per connection and asserts on the SQL string — that catches quoting regressions without needing a live server, and it is exactly how the 1.5.4 bugs would have been caught.
Testing your own calls. Assert on ->toSql() for shape and on database state for behaviour. Do not assert on raw SQL in tests that run across engines; the quoting differs by design.
updateMany emitted MySQL backticks around updated_at and left other identifiers unquoted, which PostgreSQL rejects outright. If you are on PG and on an older version, this macro has never worked for you.ELSE branch preserves the current value. If you genuinely need to set a column to NULL, include it explicitly in a set; you cannot achieve it by leaving the column out.`order` or "order" as a column name will now be double-quoted by the grammar and break. Pass plain names.ELSE branch fixes the untyped-binding problem that made PostgreSQL refuse text bindings against integer and timestamp columns, but passing a string where an integer is expected in your own values can still surprise you. Cast values before building sets.ELSE branch. On any version below 1.5.4, this pattern silently wrote NULL into columns for rows missing from a set, or failed on NOT NULL columns. Audit any existing multi-set call sites after upgrading.->toSql() and inspect the bindings separately. A malformed CASE usually shows up as a column that silently keeps its old value rather than an exception.How can I help you explore Laravel packages today?