๐Ÿšจ NEWS: SQL Injection in Laravel e MySQL: prevenzione con Query Builder, Eloquent e Raw SQL Sicuro

Ecco i punti chiave in breve:
๐Ÿ’ก Hai mai visto un form contatti che invia dati in chiaro a una query SQL scritta a mano? Noi sรฌ. E ogni volta che un client ci affida un sito costruito con query raw senza...

๐Ÿš€ LINK: https://meteoraweb.com/analisi-dei-dati-e-metriche/sql-injection-in-laravel-e-mysql-prevenzione-con-query-builder-eloquent-e-raw-sql-sicuro

#laravel #sicurezzaWeb #sQLInjection #mySQL #queryBuilder

ะฏ ะปัŽะฑะปัŽ SQL, ะฝะพ ัƒัั‚ะฐะป ัะพะฑะธั€ะฐั‚ัŒ WHERE ั‡ะตั€ะตะท fmt.Sprintf: ะทะฐั‡ะตะผ ั ัะดะตะปะฐะป qrafter

ะœะฝะต ะฝั€ะฐะฒะธั‚ัั ั‡ะธัั‚ั‹ะน SQL. ะะต ยซะฝั€ะฐะฒะธั‚ัั, ะฟะพั‚ะพะผัƒ ั‡ั‚ะพ ะฟั€ะธัˆะปะพััŒยป, ะฐ ะฟั€ะฐะฒะดะฐ ะฝั€ะฐะฒะธั‚ัั. ะ’ ั…ะพั€ะพัˆะตะผ SQLโ€‘ะทะฐะฟั€ะพัะต ะฒะธะดะฝะพ, ั‡ั‚ะพ ะฟั€ะพะธัั…ะพะดะธั‚ ั ะดะฐะฝะฝั‹ะผะธ: ะพั‚ะบัƒะดะฐ ะฑะตั€ั‘ะผ, ะบะฐะบ ั„ะธะปัŒั‚ั€ัƒะตะผ, ะณะดะต ัะพะตะดะธะฝัะตะผ, ั‡ั‚ะพ ะฐะณั€ะตะณะธั€ัƒะตะผ ะธ ะฒ ะบะฐะบะพะผ ะฟะพั€ัะดะบะต ะพั‚ะดะฐั‘ะผ ะฝะฐั€ัƒะถัƒ. ะะพ ะบะฐะบ ั‚ะพะปัŒะบะพ ะฒ API ะฟะพัะฒะปััŽั‚ัั ั„ะธะปัŒั‚ั€ั‹, ัะพั€ั‚ะธั€ะพะฒะบะฐ, ะฟะฐะณะธะฝะฐั†ะธั ะธ ะพั‚ะดะตะปัŒะฝั‹ะน COUNT(*) ั ั‚ะตะผ ะถะต WHERE, ั‡ะธัั‚ั‹ะน SQL ะฑั‹ัั‚ั€ะพ ะพะฑั€ะฐัั‚ะฐะตั‚ ั€ัƒั‡ะฝะพะน ะฑัƒั…ะณะฐะปั‚ะตั€ะธะตะน: args, placeholderยซั‹, fmt.Sprintf ะธ ะบะพะฟะธั€ะพะฒะฐะฝะธะต ัƒัะปะพะฒะธะน ะผะตะถะดัƒ ะทะฐะฟั€ะพัะฐะผะธ.ยป ะ’ ะบะฐะบะพะนโ€‘ั‚ะพ ะผะพะผะตะฝั‚ ั ะฟะพะฝัะป, ั‡ั‚ะพ ะผะตะฝั ั€ะฐะทะดั€ะฐะถะฐะตั‚ ะฝะต SQL. ะœะตะฝั ั€ะฐะทะดั€ะฐะถะฐะตั‚ ั€ะฐะฑะพั‚ะฐ ะฒะพะบั€ัƒะณ SQL. ะขะฐะบ ะฟะพัะฒะธะปัั qrafter โ€” ะฝะตะฑะพะปัŒัˆะพะน typeโ€‘safe SQL query builder ะดะปั Go: ะฑะตะท ORM, ะฑะตะท codegen, ั ั‚ะธะฟะธะทะธั€ะพะฒะฐะฝะฝั‹ะผะธ ะบะพะปะพะฝะบะฐะผะธ, ะทะฐะฒะธัะธะผั‹ะผ ะพั‚ ะดะธะฐะปะตะบั‚ะฐ ั€ะตะฝะดะตั€ะพะผ ะธ ะพะฑั‹ั‡ะฝั‹ะผ SQL + ะฐั€ะณัƒะผะตะฝั‚ะฐะผะธ ะฝะฐ ะฒั‹ั…ะพะดะต.

https://habr.com/ru/articles/1042578/

#golang #sql #postgresql #sqlx #querybuilder #opensource #typesafe

ะฏ ะปัŽะฑะปัŽ SQL, ะฝะพ ัƒัั‚ะฐะป ัะพะฑะธั€ะฐั‚ัŒ WHERE ั‡ะตั€ะตะท fmt.Sprintf: ะทะฐั‡ะตะผ ั ัะดะตะปะฐะป qrafter

ะœะฝะต ะฝั€ะฐะฒะธั‚ัั ั‡ะธัั‚ั‹ะน SQL. ะะต ยซะฝั€ะฐะฒะธั‚ัั, ะฟะพั‚ะพะผัƒ ั‡ั‚ะพ ะฟั€ะธัˆะปะพััŒยป, ะฐ ะฟั€ะฐะฒะดะฐ ะฝั€ะฐะฒะธั‚ัั. ะ’ ั…ะพั€ะพัˆะตะผ SQLโ€‘ะทะฐะฟั€ะพัะต ะพะฑั‹ั‡ะฝะพ ะฒะธะดะฝะพ, ั‡ั‚ะพ ะฟั€ะพะธัั…ะพะดะธั‚ ั ะดะฐะฝะฝั‹ะผะธ: ะพั‚ะบัƒะดะฐ ะฑะตั€ั‘ะผ, ะบะฐะบ ั„ะธะปัŒั‚ั€ัƒะตะผ,...

ะฅะฐะฑั€

Le dรฉveloppement de Knex.js โ€“ un query builder SQL que j'affectionne beaucoup โ€“ va reprendre plus activement.

๐Ÿ”— https://knexjs.org/blog/posts/2026-03-23-welcome/

#sql #querybuilder #JavaScript #lib

Knex, the Garden, and the Long Road Back | Knex.js

Beta knex.js documentation.

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ ์ธก๋ฉด์—์„œ ๋ณธ Drizzle ORM ๋Œ€ Kysely ๋น„๊ต

https://hackers.pub/@hongminhee/2025/drizzle-orm-vs-kysely

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ ์ธก๋ฉด์—์„œ ๋ณธ Drizzle ORM ๋Œ€ Kysely ๋น„๊ต

TypeScript๋กœ ๋ฐฑ์—”๋“œ ์„œ๋ฒ„๋ฅผ ๊ฐœ๋ฐœํ•˜๋ฉด์„œ ์ ์ ˆํ•œ ORM ์„ ํƒ์€ ํ•ญ์ƒ ์ค‘์š”ํ•œ ๊ฒฐ์ • ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค. ์ตœ๊ทผ ์ œ ํ”„๋กœ์ ํŠธ์—์„œ Drizzle ORM๊ณผ Kysely๋ฅผ ๋ชจ๋‘ ์‚ฌ์šฉํ•ด ๋ณผ ๊ธฐํšŒ๊ฐ€ ์žˆ์—ˆ๋Š”๋ฐ, ๊ฐœ์ธ์ ์œผ๋กœ๋Š” Drizzle ORM์ด ๋” ํŽธ๋ฆฌํ•˜๊ณ  ์ƒ์‚ฐ์„ฑ์ด ๋†’์•˜๋˜ ๊ฒฝํ—˜์„ ๊ณต์œ ํ•˜๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค.๋‘ ORM์— ๋Œ€ํ•œ ๊ฐ„๋žตํ•œ ์†Œ๊ฐœ Drizzle ORM์€ TypeScript์šฉ ORM์œผ๋กœ, ํƒ€์ž… ์•ˆ์ „์„ฑ๊ณผ ์ง๊ด€์ ์ธ API๋ฅผ ๊ฐ•์ ์œผ๋กœ ๋‚ด์„ธ์šฐ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์Šคํ‚ค๋งˆ ์ •์˜๋ถ€ํ„ฐ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜, ์ฟผ๋ฆฌ ๋นŒ๋”๊นŒ์ง€ ํ’€์Šคํƒ ๊ฐœ๋ฐœ ๊ฒฝํ—˜์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. Kysely๋Š” โ€œํƒ€์ž… ์•ˆ์ „ํ•œ SQL ์ฟผ๋ฆฌ ๋นŒ๋”โ€๋กœ ์ž์‹ ์„ ์†Œ๊ฐœํ•˜๋ฉฐ, ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์˜ ํƒ€์ž… ์‹œ์Šคํ…œ์„ ํ™œ์šฉํ•ด ์ฟผ๋ฆฌ ์ž‘์„ฑ ์‹œ ํƒ€์ž… ์•ˆ์ „์„ฑ์„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค. ๋‘ ๋„๊ตฌ ๋ชจ๋‘ ํ›Œ๋ฅญํ•˜์ง€๋งŒ, ์ œ ๊ฐœ๋ฐœ ๊ฒฝํ—˜์— ๋น„์ถ”์–ด ๋ณผ ๋•Œ Drizzle ORM์ด ๋ช‡ ๊ฐ€์ง€ ์ธก๋ฉด์—์„œ ๋” ํŽธ๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค.Drizzle ORM์„ ์„ ํ˜ธํ•˜๊ฒŒ ๋œ ์ด์œ  ์Šคํ‚ค๋งˆ ์ •์˜์˜ ์ง๊ด€์„ฑ Drizzle ORM์˜ ์Šคํ‚ค๋งˆ ์ •์˜ ๋ฐฉ์‹์€ ๋งค์šฐ ์ง๊ด€์ ์ด๊ณ  ์„ ์–ธ์ ์ž…๋‹ˆ๋‹ค:import { pgTable, serial, text, integer } from 'drizzle-orm/pg-core';export const users = pgTable('users', { id: serial('id').primaryKey(), name: text('name').notNull(), email: text('email').unique().notNull(), age: integer('age')});<Drizzle ORM์€ ์ด ์Šคํ‚ค๋งˆ ์ •์˜๋กœ๋ถ€ํ„ฐ ์ž๋™์œผ๋กœ CREATE TABLE SQL์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์–ด, ์Šคํ‚ค๋งˆ์™€ ์ฝ”๋“œ๊ฐ€ ํ•ญ์ƒ ๋™๊ธฐํ™”๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด Kysely๋Š” ํƒ€์ž… ์ •์˜์— ๋” ์ค‘์ ์„ ๋‘๊ณ  ์žˆ์–ด ์Šคํ‚ค๋งˆ์™€ ํƒ€์ž… ์ •์˜๊ฐ€ ๋ถ„๋ฆฌ๋˜๋Š” ๊ฒฝํ–ฅ์ด ์žˆ์Šต๋‹ˆ๋‹ค:interface Database { users: { id: Generated<number>; name: string; email: string; age: number | null; };}<์ด ํƒ€์ž… ์ •์˜๋Š” TypeScript ์ฝ”๋“œ์—์„œ ํƒ€์ž… ์•ˆ์ „์„ฑ์„ ์ œ๊ณตํ•˜์ง€๋งŒ, ์ด ํƒ€์ž… ์ •์˜๋งŒ์œผ๋กœ๋Š” CREATE TABLE SQL์„ ์ƒ์„ฑํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์ด ๊ฒฐ์ •์ ์ธ ๋‹จ์ ์ž…๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ ํ…Œ์ด๋ธ”์„ ์ƒ์„ฑํ•˜๋ ค๋ฉด ๋ณ„๋„์˜ SQL ์Šคํฌ๋ฆฝํŠธ๋‚˜ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ํƒ€์ž…๊ณผ ์‹ค์ œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์Šคํ‚ค๋งˆ ๊ฐ„์˜ ๋ถˆ์ผ์น˜ ๊ฐ€๋Šฅ์„ฑ์„ ๋†’์ž…๋‹ˆ๋‹ค. Drizzle์˜ ์ ‘๊ทผ ๋ฐฉ์‹์ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์Šคํ‚ค๋งˆ์™€ TypeScript ํƒ€์ž…์„ ๋” ๊ธด๋ฐ€ํ•˜๊ฒŒ ์—ฐ๊ฒฐํ•ด์ฃผ์–ด ๊ฐœ๋ฐœ ๊ณผ์ •์—์„œ ํ˜ผ๋ž€์„ ์ค„์—ฌ์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๊ฒฝํ—˜ Drizzle ORM์˜ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋„๊ตฌ(drizzle-kit)๋Š” ์ •๋ง ์ธ์ƒ์ ์ด์—ˆ์Šต๋‹ˆ๋‹ค. ์Šคํ‚ค๋งˆ ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ์ž๋™์œผ๋กœ ๊ฐ์ง€ํ•˜๊ณ  SQL ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํŒŒ์ผ์„ ์ƒ์„ฑํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ์ด ๊ฐœ๋ฐœ ์›Œํฌํ”Œ๋กœ์šฐ๋ฅผ ํฌ๊ฒŒ ๊ฐœ์„ ํ–ˆ์Šต๋‹ˆ๋‹ค:npx drizzle-kit generate:pg<์ด ๋ช…๋ น์–ด ํ•˜๋‚˜๋กœ ์Šคํ‚ค๋งˆ ๋ณ€๊ฒฝ์‚ฌํ•ญ์— ๋Œ€ํ•œ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํŒŒ์ผ์ด ์ƒ์„ฑ๋˜๋ฉฐ, ์ด๋ฅผ ๊ฒ€ํ† ํ•˜๊ณ  ์ ์šฉํ•˜๋Š” ๊ณผ์ •์ด ๋งค์šฐ ๊ฐ„๋‹จํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด Kysely์˜ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์€ ๋ณธ์งˆ์ ์œผ๋กœ ์ˆ˜๋™์ ์ž…๋‹ˆ๋‹ค. ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํŒŒ์ผ์„ ์ž‘์„ฑํ•ด์•ผ ํ•˜๋ฉฐ, ์Šคํ‚ค๋งˆ ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ์ž๋™์œผ๋กœ ๊ฐ์ง€ํ•˜๊ฑฐ๋‚˜ SQL์„ ์ƒ์„ฑํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ์ด ์—†์Šต๋‹ˆ๋‹ค:// Kysely์˜ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์˜ˆ์‹œasync function up(db: Kysely<any>): Promise<void> { await db.schema .createTable('users') .addColumn('id', 'serial', (col) => col.primaryKey()) .addColumn('name', 'text', (col) => col.notNull()) .addColumn('email', 'text', (col) => col.unique().notNull()) .addColumn('age', 'integer') .execute();}async function down(db: Kysely<any>): Promise<void> { await db.schema.dropTable('users').execute();}<์ด๋Ÿฌํ•œ ์ˆ˜๋™ ๋ฐฉ์‹์€ ๋ณต์žกํ•œ ์Šคํ‚ค๋งˆ ๋ณ€๊ฒฝ์—์„œ ์‹ค์ˆ˜ํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์•„์ง€๊ณ , ํŠนํžˆ ํฐ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ์ž‘์—…๋Ÿ‰์ด ์ƒ๋‹นํžˆ ์ฆ๊ฐ€ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ Kysely์˜ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์—๋„ ๋‘ ๊ฐ€์ง€ ์ค‘์š”ํ•œ ์žฅ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค:<TypeScript ๊ธฐ๋ฐ˜ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜: Kysely์˜ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์Šคํฌ๋ฆฝํŠธ๋Š” TypeScript๋กœ ์ž‘์„ฑ๋˜๊ธฐ ๋•Œ๋ฌธ์—, ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋กœ์ง์— ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋กœ์ง์„ ํ†ตํ•ฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, S3์™€ ๊ฐ™์€ ์˜ค๋ธŒ์ ํŠธ ์Šคํ† ๋ฆฌ์ง€์˜ ๋ฐ์ดํ„ฐ๋„ ํ•จ๊ป˜ ๋งˆ์ด๊ทธ๋ ˆ์ดํŠธํ•˜๋Š” ๋ณต์žกํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด Drizzle ORM์€ SQL ๊ธฐ๋ฐ˜ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์ด๋ฏ€๋กœ ์ด๋Ÿฌํ•œ ํ†ตํ•ฉ์ด ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.<์–‘๋ฐฉํ–ฅ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜: Kysely๋Š” up๊ณผ down ํ•จ์ˆ˜๋ฅผ ๋ชจ๋‘ ์ •์˜ํ•˜์—ฌ ์—…๊ทธ๋ ˆ์ด๋“œ์™€ ๋‹ค์šด๊ทธ๋ ˆ์ด๋“œ๋ฅผ ๋ชจ๋‘ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ํŠนํžˆ ํŒ€ ํ˜‘์—… ํ™˜๊ฒฝ์—์„œ ์ค‘์š”ํ•œ๋ฐ, ๋‹ค๋ฅธ ๊ฐœ๋ฐœ์ž์˜ ๋ณ€๊ฒฝ์‚ฌํ•ญ๊ณผ ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•  ๊ฒฝ์šฐ ๋กค๋ฐฑ์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. Drizzle ORM์€ ํ˜„์žฌ ์—…๊ทธ๋ ˆ์ด๋“œ๋งŒ ์ง€์›ํ•˜๋ฉฐ, ๋‹ค์šด๊ทธ๋ ˆ์ด๋“œ ๊ธฐ๋Šฅ์ด ์—†์–ด ํ˜‘์—… ์‹œ ๋ถˆํŽธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.<์ฐธ๊ณ ๋กœ, Python ์ƒํƒœ๊ณ„์˜ SQLAlchemy ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋„๊ตฌ์ธ Alembic์€ ํ›จ์”ฌ ๋” ๋ฐœ์ „๋œ ํ˜•ํƒœ์˜ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. Alembic์€ ๋น„์„ ํ˜•์ ์ธ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๊ฒฝ๋กœ(๋ธŒ๋žœ์น˜ํฌ์ธํŠธ ์ƒ์„ฑ ๊ฐ€๋Šฅ)๋ฅผ ์ง€์›ํ•˜์—ฌ ๋ณต์žกํ•œ ํŒ€ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ๋„ ์œ ์—ฐํ•˜๊ฒŒ ๋Œ€์‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์ƒ์ ์œผ๋กœ๋Š” JavaScript/TypeScript ์ƒํƒœ๊ณ„์˜ ORM๋„ ์ด๋Ÿฌํ•œ ์ˆ˜์ค€์˜ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋„๊ตฌ๋ฅผ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ด ๋ฐ”๋žŒ์งํ•ฉ๋‹ˆ๋‹ค.๊ด€๊ณ„ ์„ค์ •์˜ ์šฉ์ด์„ฑ Drizzle ORM์—์„œ ํ…Œ์ด๋ธ” ๊ฐ„ ๊ด€๊ณ„ ์„ค์ •์ด ๋งค์šฐ ์ง๊ด€์ ์ด์—ˆ์Šต๋‹ˆ๋‹ค:import { relations } from 'drizzle-orm';export const usersRelations = relations(users, ({ one, many }) => ({ profile: one(profiles, { fields: [users.id], references: [profiles.userId], }), posts: many(posts)}));<์ด ๋ฐฉ์‹์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„ค๊ณ„์˜ ๋ณธ์งˆ์ ์ธ, ๊ด€๊ณ„์ ์ธ ์ธก๋ฉด์„ ๋ช…ํ™•ํ•˜๊ฒŒ ํ‘œํ˜„ํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.์ฟผ๋ฆฌ ์ž‘์„ฑ์˜ ํŽธ์˜์„ฑ๊ณผ ๋™์ผ ์ด๋ฆ„ ์นผ๋Ÿผ ๋ฌธ์ œ ์ฒ˜๋ฆฌ ๋‘ ORM ๋ชจ๋‘ ์ฟผ๋ฆฌ ์ž‘์„ฑ์„ ์œ„ํ•œ API๋ฅผ ์ œ๊ณตํ•˜์ง€๋งŒ, Drizzle์˜ ์ ‘๊ทผ ๋ฐฉ์‹์ด ๋” ์ง๊ด€์ ์ด๊ณ  ๊ด€๊ณ„ํ˜• ๋ชจ๋ธ์„ ํ™œ์šฉํ•˜๊ธฐ ์‰ฌ์› ์Šต๋‹ˆ๋‹ค:// Drizzle ORM - db.query ๋ฐฉ์‹์œผ๋กœ ๊ด€๊ณ„ ํ™œ์šฉconst result = await db.query.posts.findMany({ where: eq(posts.published, true), with: { user: true // ๊ฒŒ์‹œ๋ฌผ ์ž‘์„ฑ์ž ์ •๋ณด๋ฅผ ํ•จ๊ป˜ ์กฐํšŒ }});// ๊ฒฐ๊ณผ ์ ‘๊ทผ์ด ์ง๊ด€์ ์ด๊ณ  ํƒ€์ž… ์•ˆ์ „ํ•จconsole.log(result[0].title); // ๊ฒŒ์‹œ๋ฌผ ์ œ๋ชฉconsole.log(result[0].user.name); // ์ž‘์„ฑ์ž ์ด๋ฆ„ - ๊ฐ์ฒด ๊ตฌ์กฐ๋กœ ๋ช…ํ™•ํ•˜๊ฒŒ ๊ตฌ๋ถ„๋จ console.log(result[0].user.id); // ์ž‘์„ฑ์ž ID - ๊ฒŒ์‹œ๋ฌผ ID์™€ ์ด๋ฆ„์ด ๊ฐ™์•„๋„ ๋ฌธ์ œ ์—†์Œ // Kyselyconst result = await db .selectFrom('posts') .where('posts.published', '=', true) .leftJoin('users', 'posts.userId', 'users.id') .selectAll();// ๊ฒฐ๊ณผ ์ ‘๊ทผ ์‹œ ์นผ๋Ÿผ ์ด๋ฆ„ ์ถฉ๋Œ ๋ฌธ์ œconsole.log(result[0].id) // ์˜ค๋ฅ˜: posts.id์™€ users.id ์ค‘ ์–ด๋–ค ๊ฒƒ์ธ์ง€ ๋ชจํ˜ธํ•จ console.log(result[0].name) // ์˜ค๋ฅ˜: ๋‘˜ ๋‹ค name ์นผ๋Ÿผ์ด ์žˆ๋‹ค๋ฉด ๋ชจํ˜ธํ•จ <Drizzle์˜ ์ ‘๊ทผ ๋ฐฉ์‹์ด ํ…Œ์ด๋ธ”๊ณผ ์ปฌ๋Ÿผ์„ ์ฐธ์กฐํ•  ๋•Œ ํƒ€์ž… ์•ˆ์ „์„ฑ์„ ๋” ๊ฐ•๋ ฅํ•˜๊ฒŒ ๋ณด์žฅํ•˜๊ณ , ๊ด€๊ณ„๋ฅผ ํ™œ์šฉํ•œ ์ฟผ๋ฆฌ ์ž‘์„ฑ์ด ๋” ์ง๊ด€์ ์ด์—ˆ์Šต๋‹ˆ๋‹ค. ํŠนํžˆ ์—ฌ๋Ÿฌ ํ…Œ์ด๋ธ” ์กฐ์ธ ์‹œ ๋™์ผํ•œ ์ด๋ฆ„์˜ ์นผ๋Ÿผ ์ฒ˜๋ฆฌ ๋ถ€๋ถ„์—์„œ Drizzle ORM์ด ํ›จ์”ฌ ๋” ํŽธ๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์ œ ๊ฐœ๋ฐœ ๊ฒฝํ—˜์—์„œ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ์ฐจ์ด์  ์ค‘ ํ•˜๋‚˜์˜€์Šต๋‹ˆ๋‹ค.// Drizzle ORM - ๋™์ผ ์ด๋ฆ„ ์นผ๋Ÿผ ์ฒ˜๋ฆฌconst result = await db.query.posts.findMany({ with: { user: true // posts.id์™€ users.id๊ฐ€ ๋ชจ๋‘ ์žˆ์ง€๋งŒ ์ž๋™์œผ๋กœ ๊ตฌ๋ถ„๋จ }});// ๊ฒฐ๊ณผ์— ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ ‘๊ทผ ๊ฐ€๋Šฅ console.log(result[0].id); // ๊ฒŒ์‹œ๋ฌผ ID console.log(result[0].user.id); // ์‚ฌ์šฉ์ž ID - ๋ช…ํ™•ํ•˜๊ฒŒ ๊ตฌ๋ถ„๋จ console.log(result[0].user.name); // ์‚ฌ์šฉ์ž ์ด๋ฆ„ // Kysely - ๋™์ผ ์ด๋ฆ„ ์นผ๋Ÿผ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•ด ๋ณ„์นญ ํ•„์š”const result = await db .selectFrom('posts') .leftJoin('users', 'posts.userId', 'users.id') .select([ 'posts.id as postId', // ๋ณ„์นญ ํ•„์ˆ˜ 'posts.title', 'posts.content', 'users.id as userId', // ๋ณ„์นญ ํ•„์ˆ˜ 'users.name as userName', // ์นผ๋Ÿผ ์ด๋ฆ„์ด ๊ฐ™์„ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋ณ„์นญ ํ•„์ˆ˜ 'users.email as userEmail' // ์ผ๊ด€์„ฑ์„ ์œ„ํ•ด ๋ชจ๋“  ์‚ฌ์šฉ์ž ๊ด€๋ จ ์นผ๋Ÿผ์— ์ ‘๋‘์–ด ํ•„์š” ]);// ๋ณ„์นญ์„ ํ†ตํ•œ ์ ‘๊ทผconsole.log(result[0].postId); // ๊ฒŒ์‹œ๋ฌผ IDconsole.log(result[0].userId); // ์‚ฌ์šฉ์ž IDconsole.log(result[0].userName); // ์‚ฌ์šฉ์ž ์ด๋ฆ„<Drizzle ORM์€ ํ…Œ์ด๋ธ”๊ณผ ์นผ๋Ÿผ์„ ๊ฐ์ฒด๋กœ ์ฐธ์กฐํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ๋™์ผํ•œ ์ด๋ฆ„์˜ ์นผ๋Ÿผ์ด ์žˆ์–ด๋„ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๊ณ„์ธต ๊ตฌ์กฐ๋กœ ์ฒ˜๋ฆฌ๋˜๋ฉฐ ํƒ€์ž… ์ถ”๋ก ๋„ ์ •ํ™•ํ•˜๊ฒŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด Kysely์—์„œ๋Š” ๋ฌธ์ž์—ด ๊ธฐ๋ฐ˜ ์ ‘๊ทผ ๋ฐฉ์‹ ๋•Œ๋ฌธ์— ๋ณ„์นญ์„ ์ˆ˜๋™์œผ๋กœ ์ง€์ •ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์•˜๊ณ , ๋ณต์žกํ•œ ์กฐ์ธ์—์„œ ์ด๋Ÿฐ ์ž‘์—…์ด ๋ฒˆ๊ฑฐ๋กœ์›Œ์กŒ์Šต๋‹ˆ๋‹ค. ํŠนํžˆ ์—ฌ๋Ÿฌ ํ…Œ์ด๋ธ”์— ๊ฐ™์€ ์ด๋ฆ„์˜ ์นผ๋Ÿผ์ด ๋งŽ์„์ˆ˜๋ก ๋ชจ๋“  ์นผ๋Ÿผ์— ๋ช…์‹œ์ ์ธ ๋ณ„์นญ์„ ์ง€์ •ํ•ด์•ผ ํ•˜๋Š” ๋ถˆํŽธํ•จ์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ Drizzle ORM์€ ๊ฒฐ๊ณผ ํƒ€์ž…์„ ์ž๋™์œผ๋กœ ์ •ํ™•ํ•˜๊ฒŒ ์ถ”๋ก ํ•ด์ฃผ์–ด ๋ณ„๋„์˜ ํƒ€์ž… ์ง€์ • ์—†์ด๋„ ์•ˆ์ „ํ•˜๊ฒŒ ๊ฒฐ๊ณผ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.Kysely์˜ ์žฅ์  ๋ฌผ๋ก  Kysely๋„ ์—ฌ๋Ÿฌ ๊ฐ•์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค:๋” ๊ฐ€๋ฒผ์šด ๊ตฌ์กฐ: ํ•„์š”ํ•œ ๊ธฐ๋Šฅ๋งŒ ํฌํ•จํ•  ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“ˆํ™”๋œ ๊ตฌ์กฐSQL์— ๋” ๊ฐ€๊นŒ์šด ์ ‘๊ทผ: SQL ๊ตฌ๋ฌธ์— ๋งค์šฐ ์ถฉ์‹คํ•œ API ์„ค๊ณ„์œ ์—ฐ์„ฑ: ๋ณต์žกํ•œ ์ฟผ๋ฆฌ์—์„œ ๋•Œ๋กœ ๋” ์œ ์—ฐํ•œ ์ž‘์„ฑ์ด ๊ฐ€๋Šฅ<๋˜ํ•œ ์•ž์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด, Kysely์˜ TypeScript ๊ธฐ๋ฐ˜ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜๊ณผ ์–‘๋ฐฉํ–ฅ(up/down) ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์ง€์›์€ ํŠน์ • ์ƒํ™ฉ์—์„œ Drizzle ORM๋ณด๋‹ค ์šฐ์œ„์— ์žˆ๋Š” ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค.SQLAlchemy์™€์˜ ๋น„๊ต ๋ฐ ์•ž์œผ๋กœ์˜ ๊ธฐ๋Œ€ JavaScript/TypeScript ์ƒํƒœ๊ณ„์˜ ORM์„ ์ด์•ผ๊ธฐํ•˜๊ธฐ ์ „์—, ์—ฌ๋Ÿฌ ์–ธ์–ด ์ค‘์—์„œ๋„ Python์˜ SQLAlchemy๋Š” ํŠน๋ณ„ํ•œ ์œ„์น˜๋ฅผ ์ฐจ์ง€ํ•ฉ๋‹ˆ๋‹ค. ๊ฐœ์ธ์ ์œผ๋กœ ์—ฌํƒœ ์‚ฌ์šฉํ•ด๋ณธ ๋‹ค์–‘ํ•œ ์–ธ์–ด์˜ ORM ์ค‘์—์„œ SQLAlchemy๊ฐ€ ๊ฐ€์žฅ ๊ธฐ๋Šฅ์ด ํ’๋ถ€ํ•˜๊ณ  ๊ฐ•๋ ฅํ•˜๋‹ค๊ณ  ๋А๊ผˆ์Šต๋‹ˆ๋‹ค. ๋ณต์žกํ•œ ์ฟผ๋ฆฌ ๊ตฌ์„ฑ, ๊ณ ๊ธ‰ ๊ด€๊ณ„ ๋งคํ•‘, ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ, ์ด๋ฒคํŠธ ์‹œ์Šคํ…œ ๋“ฑ SQLAlchemy์˜ ๊ธฐ๋Šฅ์€ ์ •๋ง ๋ฐฉ๋Œ€ํ•ฉ๋‹ˆ๋‹ค. Drizzle ORM์€ JavaScript ์ƒํƒœ๊ณ„์—์„œ ๋งค์šฐ ์ธ์ƒ์ ์ธ ๋ฐœ์ „์„ ์ด๋ฃจ์—ˆ์ง€๋งŒ, ์•„์ง SQLAlchemy์˜ ๊ฒฝ์ง€์—๋Š” ์ด๋ฅด์ง€ ๋ชปํ–ˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ํŠนํžˆ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ถ€๋ถ„์—์„œ SQLAlchemy์˜ ์„ฑ์ˆ™๋„์™€ ๊ธฐ๋Šฅ ํ’๋ถ€ํ•จ์ด ๋‹๋ณด์ž…๋‹ˆ๋‹ค:๋ณต์žกํ•œ ์„œ๋ธŒ์ฟผ๋ฆฌ์™€ ์œˆ๋„์šฐ ํ•จ์ˆ˜ ์ง€์›๋‹ค์–‘ํ•œ ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ์™€ ํ›…๋‹ค์–‘ํ•œ ์ƒ์† ์ „๋žต๋ณต์žกํ•œ ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ์™€ ์„ธ์…˜ ๊ด€๋ฆฌ๋Œ€๊ทœ๋ชจ ํ”„๋กœ์ ํŠธ์—์„œ ๊ฒ€์ฆ๋œ ์•ˆ์ •์„ฑAlembic์„ ํ†ตํ•œ ๋น„์„ ํ˜•์  ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์ง€์›๋†€๋ผ์šธ ์ •๋„๋กœ ๋ฐฉ๋Œ€ํ•˜๊ณ  ์ƒ์„ธํ•œ ๋ฌธ์„œํ™”<๊ฒฐ๋ก  ๋‘ ORM ๋ชจ๋‘ ํ›Œ๋ฅญํ•œ ๋„๊ตฌ์ด์ง€๋งŒ, ์ œ ๊ฐœ๋ฐœ ์Šคํƒ€์ผ๊ณผ ํ”„๋กœ์ ํŠธ ์š”๊ตฌ์‚ฌํ•ญ์—๋Š” Drizzle ORM์ด ๋” ์ž˜ ๋งž์•˜์Šต๋‹ˆ๋‹ค. ํŠนํžˆ ์Šคํ‚ค๋งˆ ์ •์˜์˜ ์ง๊ด€์„ฑ, ๊ฐ•๋ ฅํ•œ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋„๊ตฌ, ๊ทธ๋ฆฌ๊ณ  ์ „๋ฐ˜์ ์ธ ๊ฐœ๋ฐœ์ž ๊ฒฝํ—˜ ์ธก๋ฉด์—์„œ Drizzle ORM์ด ๋” ์ƒ์‚ฐ์ ์ธ ๊ฐœ๋ฐœ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค. ๋™์ผ ์ด๋ฆ„ ์นผ๋Ÿผ ์ฒ˜๋ฆฌ์™€ ๊ฐ™์€ ์‹ค์งˆ์ ์ธ ๋ฌธ์ œ์—์„œ Drizzle ORM์˜ ๊ฐ์ฒด ๊ธฐ๋ฐ˜ ์ ‘๊ทผ ๋ฐฉ์‹์ด ๊ฐ€์ ธ๋‹ค์ฃผ๋Š” ํŽธ๋ฆฌํ•จ์€ ์‹ค์ œ ํ”„๋กœ์ ํŠธ์—์„œ ํฐ ์ฐจ์ด๋ฅผ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. ORM ์„ ํƒ์€ ๊ฒฐ๊ตญ ํ”„๋กœ์ ํŠธ ํŠน์„ฑ๊ณผ ๊ฐœ์ธ ์„ ํ˜ธ๋„์— ํฌ๊ฒŒ ์ขŒ์šฐ๋ฉ๋‹ˆ๋‹ค. ์ƒˆ๋กœ์šด ํ”„๋กœ์ ํŠธ๋ฅผ ์‹œ์ž‘ํ•œ๋‹ค๋ฉด ๋‘ ๋„๊ตฌ ๋ชจ๋‘ ๊ฐ„๋‹จํžˆ ํ…Œ์ŠคํŠธํ•ด๋ณด๊ณ  ์ž์‹ ์˜ ์›Œํฌํ”Œ๋กœ์šฐ์— ๋” ์ ํ•ฉํ•œ ๊ฒƒ์„ ์„ ํƒํ•˜๋Š” ๊ฒƒ์ด ์ข‹๊ฒ ์ง€๋งŒ, ์ œ ๊ฒฝ์šฐ์—๋Š” Drizzle ORM์ด ๋ช…ํ™•ํ•œ ์Šน์ž์˜€์Šต๋‹ˆ๋‹ค. ์•ž์œผ๋กœ Drizzle ORM์ด ๋”์šฑ ๋ฐœ์ „ํ•˜์—ฌ SQLAlchemy ์ˆ˜์ค€์˜ ํ’๋ถ€ํ•œ ๊ธฐ๋Šฅ๊ณผ ์œ ์—ฐ์„ฑ์„ ์ œ๊ณตํ•˜๊ฒŒ ๋˜๊ธธ ๋ฐ”๋ž๋‹ˆ๋‹ค. JavaScript/TypeScript ์ƒํƒœ๊ณ„์—๋„ ๊ทธ๋Ÿฐ ์ˆ˜์ค€์˜ ๊ฐ•๋ ฅํ•œ ORM์ด ์žˆ์œผ๋ฉด ์ข‹๊ฒ ์Šต๋‹ˆ๋‹ค. ๋‹คํ–‰ํžˆ๋„ Drizzle ORM์€ ๊ณ„์†ํ•ด์„œ ๋ฐœ์ „ํ•˜๊ณ  ์žˆ์œผ๋ฉฐ, ๊ทธ ๋ฐœ์ „ ์†๋„๋ฅผ ๋ณด๋ฉด ๊ธฐ๋Œ€๊ฐ€ ํฝ๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ๋ถ„์˜ ๊ฒฝํ—˜์€ ์–ด๋–ค๊ฐ€์š”? ๋‹ค๋ฅธ ORM ๋„๊ตฌ๋‚˜ ์–ธ์–ด๋ฅผ ์‚ฌ์šฉํ•ด๋ณด์…จ๋‹ค๋ฉด ์˜๊ฒฌ์„ ๊ณต์œ ํ•ด์ฃผ์„ธ์š”!

Hackers' Pub

Unpopular opinion might be an overhead but I wish most query builder be immutable by default until they process or execute any non building action. Having to clone a query builder because you need to re-use part of it or create a brand new instance seems anti-POLA (Principle of least astonishment)

#php #querybuilder #orm

Simplifying #MySQL Query Analysis with #Laravel Visual Explains ๐Ÿ”

๐Ÿ› ๏ธ #Laravel package that transforms complex MySQL EXPLAIN outputs into clear, comprehensible metrics through https://mysqlexplain.com

๐Ÿ“Š Features three key #QueryBuilder methods:

MySQL Visual Explain

Optimize MySQL queries with easy-to-understand Visual Explains.

Did you know you could do the following with #leagueCSV ? Querying a #CSV document in #php has never been so much easier using a #querybuilder
QueryBuilder SQL-debugging mit ":dcValue"-Platzhalter-Ersetzung

Hallo zusammen, falls ihr auch hin und wieder mit dem Query builder arbeitet und ihr das sich daraus ergebende SQL direkt testen kรถnnen mรถchtet, ohne erst a...

Community Hub fรผr TYPO3

Updated my #foss project after a long time! ๐Ÿ˜ƒ

CHANGELOG
- Minor UI/UX changes.
- Updated readme

DEMO:
https://swapnilmj.github.io/web-vqd/

Project page: https://codeberg.org/swapnilmj/web-vqd

#opensource #mysql #querybuilder

Visual Query Designer

kalvn (@[email protected])

Les ORMs sont rarement la solution qu'il vous faut. Ils apportent quelque chose mais รงa ร  un prix que tout le monde n'est pas prรชt ร  payer. Je prรฉfรจre de loin les query builders type Knex.js (qui est d'ailleurs utilisรฉ comme base de beaucoup d'ORMs JavaScript). You might not need an ORM https://sometechblog.com/posts/you-might-not-need-an-orm/ #orm โ€” https://links.kalvn.net/shaare/746Esw

Mastodon