├── .gitignore ├── examples ├── symfony-example │ ├── migrations │ │ └── .gitignore │ ├── gen.go │ ├── config │ │ ├── routes.yaml │ │ ├── routes │ │ │ └── framework.yaml │ │ ├── preload.php │ │ ├── bundles.php │ │ ├── packages │ │ │ ├── doctrine_migrations.yaml │ │ │ ├── routing.yaml │ │ │ ├── framework.yaml │ │ │ ├── cache.yaml │ │ │ └── doctrine.yaml │ │ └── services.yaml │ ├── sqlc │ │ └── authors │ │ │ ├── postgresql │ │ │ ├── schema.sql │ │ │ └── query.sql │ │ │ └── mysql │ │ │ ├── schema.sql │ │ │ └── query.sql │ ├── docker-compose.yml │ ├── public │ │ └── index.php │ ├── src │ │ ├── Kernel.php │ │ ├── Sqlc │ │ │ └── MySQL │ │ │ │ ├── Author.php │ │ │ │ ├── BookByTagsRow.php │ │ │ │ ├── BookByTagsMultipleRow.php │ │ │ │ ├── Book.php │ │ │ │ ├── Queries.php │ │ │ │ └── QueriesImpl.php │ │ └── Controller │ │ │ └── TestController.php │ ├── tests │ │ ├── bootstrap.php │ │ └── PersistenceTest.php │ ├── sqlc.yaml │ ├── .gitignore │ ├── composer.json │ └── symfony.lock ├── go.mod └── go.sum ├── internal ├── core │ ├── config.go │ ├── util.go │ ├── mysql_type.go │ ├── models.go │ └── gen.go ├── tmpl │ ├── models.tmpl │ ├── query_interface.tmpl │ └── query_impl.tmpl └── gen.go ├── .idea ├── vcs.xml ├── modules.xml ├── aws.xml ├── php.xml └── workspace.xml ├── plugin └── main.go ├── Makefile ├── go.mod ├── sqlc-plugin-php-dbal.iml ├── LICENSE ├── README.md └── go.sum /.gitignore: -------------------------------------------------------------------------------- 1 | bin -------------------------------------------------------------------------------- /examples/symfony-example/migrations/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /internal/core/config.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | type Config struct { 4 | Package string `json:"package"` 5 | } 6 | -------------------------------------------------------------------------------- /examples/symfony-example/gen.go: -------------------------------------------------------------------------------- 1 | //go:generate go run github.com/sqlc-dev/sqlc/cmd/sqlc generate 2 | 3 | package symfony_example 4 | -------------------------------------------------------------------------------- /examples/symfony-example/config/routes.yaml: -------------------------------------------------------------------------------- 1 | controllers: 2 | resource: 3 | path: ../src/Controller/ 4 | namespace: App\Controller 5 | type: attribute 6 | -------------------------------------------------------------------------------- /examples/symfony-example/config/routes/framework.yaml: -------------------------------------------------------------------------------- 1 | when@dev: 2 | _errors: 3 | resource: '@FrameworkBundle/Resources/config/routing/errors.xml' 4 | prefix: /_error 5 | -------------------------------------------------------------------------------- /examples/symfony-example/sqlc/authors/postgresql/schema.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE author ( 2 | id BIGSERIAL PRIMARY KEY, 3 | name text NOT NULL, 4 | bio text 5 | ); 6 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /examples/symfony-example/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.1' 2 | 3 | services: 4 | db: 5 | image: mysql:8.4 6 | restart: always 7 | ports: 8 | - "3306:3306" 9 | environment: 10 | MYSQL_ROOT_PASSWORD: kausi -------------------------------------------------------------------------------- /examples/symfony-example/config/preload.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/symfony-example/config/bundles.php: -------------------------------------------------------------------------------- 1 | ['all' => true], 5 | Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true], 6 | Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true], 7 | ]; 8 | -------------------------------------------------------------------------------- /examples/symfony-example/config/packages/doctrine_migrations.yaml: -------------------------------------------------------------------------------- 1 | doctrine_migrations: 2 | migrations_paths: 3 | # namespace is arbitrary but should be different from App\Migrations 4 | # as migrations classes should NOT be autoloaded 5 | 'DoctrineMigrations': '%kernel.project_dir%/migrations' 6 | enable_profiler: false 7 | -------------------------------------------------------------------------------- /examples/symfony-example/tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | bootEnv(dirname(__DIR__).'/.env'); 9 | } 10 | 11 | if ($_SERVER['APP_DEBUG']) { 12 | umask(0000); 13 | } 14 | -------------------------------------------------------------------------------- /examples/symfony-example/src/Sqlc/MySQL/Author.php: -------------------------------------------------------------------------------- 1 | symfony/framework-bundle ### 3 | /.env.local 4 | /.env.local.php 5 | /.env.*.local 6 | /config/secrets/prod/prod.decrypt.private.php 7 | /public/bundles/ 8 | /var/ 9 | /vendor/ 10 | ###< symfony/framework-bundle ### 11 | 12 | ###> symfony/phpunit-bridge ### 13 | .phpunit.result.cache 14 | /phpunit.xml 15 | ###< symfony/phpunit-bridge ### 16 | 17 | ###> phpunit/phpunit ### 18 | /phpunit.xml 19 | .phpunit.result.cache 20 | ###< phpunit/phpunit ### 21 | -------------------------------------------------------------------------------- /examples/symfony-example/config/packages/framework.yaml: -------------------------------------------------------------------------------- 1 | # see https://symfony.com/doc/current/reference/configuration/framework.html 2 | framework: 3 | secret: '%env(APP_SECRET)%' 4 | 5 | # Note that the session will be started ONLY if you read or write from it. 6 | session: true 7 | 8 | #esi: true 9 | #fragments: true 10 | 11 | when@test: 12 | framework: 13 | test: true 14 | session: 15 | storage_factory_id: session.storage.factory.mock_file 16 | -------------------------------------------------------------------------------- /examples/symfony-example/src/Sqlc/MySQL/BookByTagsRow.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 16 | 17 | -------------------------------------------------------------------------------- /internal/tmpl/models.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/symfony-example/config/packages/cache.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | cache: 3 | # Unique name of your app: used to compute stable namespaces for cache keys. 4 | #prefix_seed: your_vendor_name/app_name 5 | 6 | # The "app" cache stores to the filesystem by default. 7 | # The data in this cache should persist between deploys. 8 | # Other options include: 9 | 10 | # Redis 11 | #app: cache.adapter.redis 12 | #default_redis_provider: redis://localhost 13 | 14 | # APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues) 15 | #app: cache.adapter.apcu 16 | 17 | # Namespaced pools use the above "app" backend by default 18 | #pools: 19 | #my.dedicated.cache: null 20 | -------------------------------------------------------------------------------- /internal/tmpl/query_interface.tmpl: -------------------------------------------------------------------------------- 1 | 18 | */ 19 | public function {{.MethodName}}({{.Arg.Args}}): array; 20 | {{- end}} 21 | {{- if eq .Cmd ":exec"}} 22 | public function {{.MethodName}}({{.Arg.Args}}): void; 23 | {{- end}} 24 | {{- if eq .Cmd ":execrows"}} 25 | public function {{.MethodName}}({{.Arg.Args}}): int|string; 26 | {{- end}} 27 | {{- if eq .Cmd ":execresult"}} 28 | public function {{.MethodName}}({{.Arg.Args}}): int|string; 29 | {{- end}} 30 | {{end}} 31 | } 32 | 33 | -------------------------------------------------------------------------------- /examples/symfony-example/tests/PersistenceTest.php: -------------------------------------------------------------------------------- 1 | get(Connection::class); 17 | 18 | $sub = new QueriesImpl($connection); 19 | 20 | $date = new \DateTimeImmutable(); 21 | $sub->createBook( 22 | authorId: 3, isbn: "someISBN", bookType: "someType", uuidToBin: Uuid::v7()->toString(), yr: 2323, available: $date, tags: "testTag" 23 | ); 24 | $books = $sub->bookByTags("testTag"); 25 | 26 | self::assertEquals(1, count($books)); 27 | 28 | self::assertEquals("someISBN", $books[0]->isbn); 29 | } 30 | } -------------------------------------------------------------------------------- /examples/symfony-example/sqlc/authors/mysql/schema.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE author ( 2 | author_id integer NOT NULL AUTO_INCREMENT PRIMARY KEY, 3 | name text NOT NULL 4 | ) ENGINE=InnoDB; 5 | 6 | CREATE INDEX authors_name_idx ON author(name(255)); 7 | 8 | CREATE TABLE book ( 9 | book_id integer NOT NULL AUTO_INCREMENT PRIMARY KEY, 10 | author_id integer NOT NULL, 11 | isbn varchar(255) NOT NULL DEFAULT '', 12 | book_type VARCHAR(100) NOT NULL DEFAULT 'FICTION', 13 | title binary(16) NOT NULL COMMENT "UUID", 14 | yr integer NOT NULL DEFAULT 2000, 15 | available datetime NOT NULL DEFAULT NOW(), 16 | tags text NOT NULL 17 | -- CONSTRAINT FOREIGN KEY (author_id) REFERENCES authors(author_id) 18 | ) ENGINE=InnoDB; 19 | 20 | 21 | /* 22 | CREATE FUNCTION say_hello(s text) RETURNS text 23 | DETERMINISTIC 24 | RETURN CONCAT('hello ', s); 25 | */ 26 | -------------------------------------------------------------------------------- /internal/core/mysql_type.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "github.com/sqlc-dev/plugin-sdk-go/plugin" 5 | "github.com/sqlc-dev/plugin-sdk-go/sdk" 6 | ) 7 | 8 | func mysqlType(col *plugin.Column) string { 9 | columnType := sdk.DataType(col.Type) 10 | 11 | switch columnType { 12 | 13 | case "varchar", "text", "char", "tinytext", "mediumtext", "longtext": 14 | return "string" 15 | 16 | case "int", "integer", "smallint", "mediumint", "year", "bigint": 17 | return "int" 18 | 19 | case "blob", "binary", "varbinary", "tinyblob", "mediumblob", "longblob": 20 | return "string" 21 | 22 | case "double", "double precision", "real": 23 | return "float" 24 | 25 | case "decimal", "dec", "fixed": 26 | return "string" 27 | 28 | case "enum": 29 | return "string" 30 | 31 | case "date", "datetime", "time", "timestamp": 32 | return "\\DateTimeImmutable" 33 | 34 | case "boolean", "bool", "tinyint": 35 | return "boolean" 36 | 37 | case "json": 38 | return "string" 39 | 40 | case "any": 41 | return "mixed" 42 | 43 | default: 44 | return "mixed" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /examples/symfony-example/config/packages/doctrine.yaml: -------------------------------------------------------------------------------- 1 | doctrine: 2 | dbal: 3 | url: '%env(resolve:DATABASE_URL)%' 4 | 5 | # IMPORTANT: You MUST configure your server version, 6 | # either here or in the DATABASE_URL env var (see .env file) 7 | #server_version: '16' 8 | 9 | profiling_collect_backtrace: '%kernel.debug%' 10 | use_savepoints: true 11 | 12 | when@test: 13 | doctrine: 14 | dbal: 15 | # "TEST_TOKEN" is typically set by ParaTest 16 | dbname_suffix: '_test%env(default::TEST_TOKEN)%' 17 | 18 | when@prod: 19 | doctrine: 20 | orm: 21 | auto_generate_proxy_classes: false 22 | proxy_dir: '%kernel.build_dir%/doctrine/orm/Proxies' 23 | query_cache_driver: 24 | type: pool 25 | pool: doctrine.system_cache_pool 26 | result_cache_driver: 27 | type: pool 28 | pool: doctrine.result_cache_pool 29 | 30 | framework: 31 | cache: 32 | pools: 33 | doctrine.result_cache_pool: 34 | adapter: cache.app 35 | doctrine.system_cache_pool: 36 | adapter: cache.system 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Tabbed 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples/symfony-example/src/Controller/TestController.php: -------------------------------------------------------------------------------- 1 | connection))->createBook( 24 | authorId: 3, isbn: "someISBN", bookType: "someType", uuidToBin: Uuid::v7()->toString(), yr: 2323, available: new \DateTimeImmutable(), tags: "kausimausi" 25 | ); 26 | var_dump($id); 27 | } catch (Exception $e) { 28 | var_dump($e); 29 | } 30 | 31 | return new JsonResponse(); 32 | } 33 | } -------------------------------------------------------------------------------- /examples/symfony-example/config/services.yaml: -------------------------------------------------------------------------------- 1 | # This file is the entry point to configure your own services. 2 | # Files in the packages/ subdirectory configure your dependencies. 3 | 4 | # Put parameters here that don't need to change on each machine where the app is deployed 5 | # https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration 6 | parameters: 7 | 8 | services: 9 | # default configuration for services in *this* file 10 | _defaults: 11 | autowire: true # Automatically injects dependencies in your services. 12 | autoconfigure: true # Automatically registers your services as commands, event subscribers, etc. 13 | 14 | # makes classes in src/ available to be used as services 15 | # this creates a service per class whose id is the fully-qualified class name 16 | App\: 17 | resource: '../src/' 18 | exclude: 19 | - '../src/DependencyInjection/' 20 | - '../src/Entity/' 21 | - '../src/Kernel.php' 22 | 23 | # add more service definitions when explicit configuration is needed 24 | # please note that last definitions always *replace* previous ones 25 | -------------------------------------------------------------------------------- /examples/symfony-example/src/Sqlc/MySQL/Queries.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | public function bookByTags(string $tags): array; 15 | 16 | /** 17 | * @return array 18 | */ 19 | public function bookByTagsMultiple(array $tags): array; 20 | 21 | /** 22 | * @return array 23 | */ 24 | public function bookByTitleYear(string $uuidToBin, int $yr): array; 25 | 26 | public function createAuthor(string $name): int|string; 27 | 28 | public function createBook( 29 | int $authorId, 30 | string $isbn, 31 | string $bookType, 32 | string $uuidToBin, 33 | int $yr, 34 | \DateTimeImmutable $available, 35 | string $tags): int|string; 36 | 37 | public function deleteAuthorBeforeYear(int $yr, int $authorId): void; 38 | 39 | public function deleteBook(int $bookId): void; 40 | 41 | public function getAuthor(int $authorId): ?Author; 42 | 43 | public function getBook(int $bookId): ?Book; 44 | 45 | public function updateBook( 46 | string $title, 47 | string $tags, 48 | int $bookId): void; 49 | 50 | public function updateBookISBN( 51 | string $title, 52 | string $tags, 53 | string $isbn, 54 | int $bookId): void; 55 | 56 | } 57 | 58 | -------------------------------------------------------------------------------- /examples/symfony-example/sqlc/authors/mysql/query.sql: -------------------------------------------------------------------------------- 1 | /* name: GetAuthor :one */ 2 | SELECT * FROM author 3 | WHERE author_id = ?; 4 | 5 | /* name: GetBook :one */ 6 | SELECT * FROM book 7 | WHERE book_id = ?; 8 | 9 | /* name: DeleteBook :exec */ 10 | DELETE FROM book 11 | WHERE book_id = ?; 12 | 13 | /* name: bookByTitleYear :many */ 14 | SELECT * FROM book 15 | WHERE title = UUID_TO_BIN(?) AND yr = ?; 16 | 17 | /* name: bookByTags :many */ 18 | SELECT 19 | book_id, 20 | title, 21 | name, 22 | isbn, 23 | tags 24 | FROM book 25 | LEFT JOIN author ON book.author_id = author.author_id 26 | WHERE tags = ?; 27 | 28 | /* name: bookByTagsMultiple :many */ 29 | SELECT 30 | book_id, 31 | title, 32 | name, 33 | isbn, 34 | tags 35 | FROM book 36 | LEFT JOIN author ON book.author_id = author.author_id 37 | WHERE tags IN (sqlc.slice(tags)); 38 | 39 | /* name: CreateAuthor :execresult */ 40 | INSERT INTO author (name) VALUES (?); 41 | 42 | /* name: CreateBook :execresult */ 43 | INSERT INTO book ( 44 | author_id, 45 | isbn, 46 | book_type, 47 | title, 48 | yr, 49 | available, 50 | tags 51 | ) VALUES ( 52 | ?, 53 | ?, 54 | ?, 55 | UUID_TO_BIN(?), 56 | ?, 57 | ?, 58 | ? 59 | ); 60 | 61 | /* name: UpdateBook :exec */ 62 | UPDATE book 63 | SET title = ?, tags = ? 64 | WHERE book_id = ?; 65 | 66 | /* name: UpdateBookISBN :exec */ 67 | UPDATE book 68 | SET title = ?, tags = ?, isbn = ? 69 | WHERE book_id = ?; 70 | 71 | /* name: DeleteAuthorBeforeYear :exec */ 72 | DELETE FROM book 73 | WHERE yr < ? AND author_id = ?; 74 | -- WHERE yr < sqlc.arg(min_publish_year) AND author_id = ?; 75 | -------------------------------------------------------------------------------- /internal/core/models.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import "github.com/sqlc-dev/plugin-sdk-go/plugin" 4 | 5 | type Query struct { 6 | ClassName string 7 | Cmd string 8 | Comments []string 9 | MethodName string 10 | FieldName string 11 | ConstantName string 12 | SQL string 13 | SourceName string 14 | Ret QueryValue 15 | Arg Params 16 | } 17 | 18 | type Field struct { 19 | ID int 20 | Name string 21 | OriginalColumnName string 22 | Type phpType 23 | Comment string 24 | } 25 | 26 | type ModelClass struct { 27 | Table plugin.Identifier 28 | Name string 29 | Fields []Field 30 | Comment string 31 | } 32 | 33 | type QueryValue struct { 34 | Name string 35 | Struct *ModelClass 36 | Typ phpType 37 | } 38 | 39 | func (v QueryValue) IsStruct() bool { 40 | return v.Struct != nil 41 | } 42 | 43 | func (v QueryValue) isEmpty() bool { 44 | return v.Typ == (phpType{}) && v.Name == "" && v.Struct == nil 45 | } 46 | 47 | func (v QueryValue) Type() string { 48 | if v.Typ != (phpType{}) { 49 | return v.Typ.String() 50 | } 51 | if v.Struct != nil { 52 | return v.Struct.Name 53 | } 54 | panic("no type for QueryValue: " + v.Name) 55 | } 56 | 57 | type QueriesTmplCtx struct { 58 | Package string 59 | Queries []Query 60 | Settings *plugin.Settings 61 | SqlcVersion string 62 | SourceName string 63 | } 64 | 65 | type ModelsTmplCtx struct { 66 | Package string 67 | ModelClass *ModelClass 68 | SqlcVersion string 69 | SourceName string 70 | } 71 | 72 | type phpType struct { 73 | Name string 74 | IsArray bool 75 | IsNull bool 76 | DataType string 77 | Engine string 78 | } 79 | 80 | func (t phpType) String() string { 81 | v := t.Name 82 | if t.IsArray { 83 | v = "array" 84 | } else if t.IsNull { 85 | v = "?" + v 86 | } 87 | return v 88 | } 89 | 90 | func (t phpType) IsDateTimeImmutable() bool { 91 | return t.Name == "\\DateTimeImmutable" 92 | } 93 | 94 | func (t phpType) IsInt() bool { 95 | return t.Name == "int" 96 | } 97 | 98 | func (t phpType) IsFloat() bool { 99 | return t.Name == "float" 100 | } 101 | 102 | func (t phpType) IsString() bool { 103 | return t.Name == "string" 104 | } 105 | -------------------------------------------------------------------------------- /examples/symfony-example/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "project", 3 | "license": "proprietary", 4 | "minimum-stability": "stable", 5 | "prefer-stable": true, 6 | "require": { 7 | "php": ">=8.2", 8 | "ext-ctype": "*", 9 | "ext-iconv": "*", 10 | "ext-pdo_mysql": "*", 11 | "doctrine/dbal": "^4.2", 12 | "doctrine/doctrine-bundle": "^2.13", 13 | "doctrine/doctrine-migrations-bundle": "^3.4", 14 | "doctrine/orm": "^3.3", 15 | "symfony/console": "7.2.*", 16 | "symfony/dotenv": "7.2.*", 17 | "symfony/flex": "^2", 18 | "symfony/framework-bundle": "7.2.*", 19 | "symfony/runtime": "7.2.*", 20 | "symfony/uid": "7.2.*", 21 | "symfony/yaml": "7.2.*" 22 | }, 23 | "config": { 24 | "allow-plugins": { 25 | "php-http/discovery": true, 26 | "symfony/flex": true, 27 | "symfony/runtime": true 28 | }, 29 | "bump-after-update": true, 30 | "sort-packages": true 31 | }, 32 | "autoload": { 33 | "psr-4": { 34 | "App\\": "src/" 35 | } 36 | }, 37 | "autoload-dev": { 38 | "psr-4": { 39 | "App\\Tests\\": "tests/" 40 | } 41 | }, 42 | "replace": { 43 | "symfony/polyfill-ctype": "*", 44 | "symfony/polyfill-iconv": "*", 45 | "symfony/polyfill-php72": "*", 46 | "symfony/polyfill-php73": "*", 47 | "symfony/polyfill-php74": "*", 48 | "symfony/polyfill-php80": "*", 49 | "symfony/polyfill-php81": "*", 50 | "symfony/polyfill-php82": "*" 51 | }, 52 | "scripts": { 53 | "auto-scripts": { 54 | "cache:clear": "symfony-cmd", 55 | "assets:install %PUBLIC_DIR%": "symfony-cmd" 56 | }, 57 | "post-install-cmd": [ 58 | "@auto-scripts" 59 | ], 60 | "post-update-cmd": [ 61 | "@auto-scripts" 62 | ] 63 | }, 64 | "conflict": { 65 | "symfony/symfony": "*" 66 | }, 67 | "extra": { 68 | "symfony": { 69 | "allow-contrib": false, 70 | "require": "7.2.*" 71 | } 72 | }, 73 | "require-dev": { 74 | "phpunit/phpunit": "^9.5", 75 | "symfony/browser-kit": "7.2.*", 76 | "symfony/css-selector": "7.2.*", 77 | "symfony/phpunit-bridge": "^7.2" 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /examples/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/lcarilla/sqlc-plugin-php-dbal/example 2 | 3 | go 1.24.1 4 | 5 | require ( 6 | cel.dev/expr v0.18.0 // indirect 7 | filippo.io/edwards25519 v1.1.0 // indirect 8 | github.com/antlr4-go/antlr/v4 v4.13.1 // indirect 9 | github.com/cubicdaiya/gonp v1.0.4 // indirect 10 | github.com/davecgh/go-spew v1.1.1 // indirect 11 | github.com/dustin/go-humanize v1.0.1 // indirect 12 | github.com/fatih/structtag v1.2.0 // indirect 13 | github.com/go-sql-driver/mysql v1.8.1 // indirect 14 | github.com/google/cel-go v0.22.1 // indirect 15 | github.com/google/uuid v1.6.0 // indirect 16 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 17 | github.com/jackc/pgpassfile v1.0.0 // indirect 18 | github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect 19 | github.com/jackc/pgx/v5 v5.7.2 // indirect 20 | github.com/jackc/puddle/v2 v2.2.2 // indirect 21 | github.com/jinzhu/inflection v1.0.0 // indirect 22 | github.com/mattn/go-isatty v0.0.20 // indirect 23 | github.com/ncruces/go-strftime v0.1.9 // indirect 24 | github.com/pganalyze/pg_query_go/v5 v5.1.0 // indirect 25 | github.com/pingcap/errors v0.11.5-0.20240311024730-e056997136bb // indirect 26 | github.com/pingcap/failpoint v0.0.0-20240528011301-b51a646c7c86 // indirect 27 | github.com/pingcap/log v1.1.0 // indirect 28 | github.com/pingcap/tidb/pkg/parser v0.0.0-20241203170126-9812d85d0d25 // indirect 29 | github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect 30 | github.com/riza-io/grpc-go v0.2.0 // indirect 31 | github.com/spf13/cobra v1.8.1 // indirect 32 | github.com/spf13/pflag v1.0.5 // indirect 33 | github.com/sqlc-dev/sqlc v1.28.0 // indirect 34 | github.com/stoewer/go-strcase v1.2.0 // indirect 35 | github.com/tetratelabs/wazero v1.8.2 // indirect 36 | github.com/wasilibs/go-pgquery v0.0.0-20240606042535-c0843d6592cc // indirect 37 | github.com/wasilibs/wazero-helpers v0.0.0-20240604052452-61d7981e9a38 // indirect 38 | go.uber.org/atomic v1.11.0 // indirect 39 | go.uber.org/multierr v1.11.0 // indirect 40 | go.uber.org/zap v1.27.0 // indirect 41 | golang.org/x/crypto v0.31.0 // indirect 42 | golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect 43 | golang.org/x/net v0.33.0 // indirect 44 | golang.org/x/sync v0.10.0 // indirect 45 | golang.org/x/sys v0.28.0 // indirect 46 | golang.org/x/text v0.21.0 // indirect 47 | google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53 // indirect 48 | google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 // indirect 49 | google.golang.org/grpc v1.69.4 // indirect 50 | google.golang.org/protobuf v1.36.3 // indirect 51 | gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect 52 | gopkg.in/yaml.v3 v3.0.1 // indirect 53 | modernc.org/libc v1.55.3 // indirect 54 | modernc.org/mathutil v1.6.0 // indirect 55 | modernc.org/memory v1.8.0 // indirect 56 | modernc.org/sqlite v1.34.5 // indirect 57 | ) 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SQLC PHP DBAL Plugin 2 | 3 | A SQLC plugin that generates PHP code using Doctrine DBAL for type-safe database operations. This plugin allows you to write SQL queries and automatically generates PHP classes with proper type hints and database abstraction. 4 | 5 | ## Features 6 | 7 | - Generates PHP classes from SQL queries using Doctrine DBAL 8 | - Supports MySQL (PostgreSQL support in development) 9 | - Type-safe database operations 10 | - Integration with Symfony framework 11 | - Support for various SQL operations: 12 | - SELECT queries (single and multiple results) 13 | - INSERT operations 14 | - UPDATE operations 15 | - DELETE operations 16 | - Complex joins 17 | - Parameterized queries 18 | - Array parameters 19 | 20 | ## Installation 21 | 22 | 1. Download the latest release from the [releases page](https://github.com/lcarilla/sqlc-plugin-php-dbal/releases) 23 | 2. Add the plugin to your `sqlc.yaml` configuration: 24 | 25 | ```yaml 26 | version: '2' 27 | plugins: 28 | - name: php 29 | wasm: 30 | url: https://github.com/lcarilla/sqlc-plugin-php-dbal/releases/download/v0.0.2/sqlc-gen-php.wasm 31 | sha256: 74f7a968592aeb6171113ad0cb972b7da9739c33f26738fbd6b2eee8893ce157 32 | ``` 33 | 34 | ## Configuration 35 | 36 | Configure your SQL queries in `sqlc.yaml`: 37 | 38 | ```yaml 39 | sql: 40 | - schema: sqlc/authors/mysql/schema.sql 41 | queries: sqlc/authors/mysql/query.sql 42 | engine: mysql 43 | codegen: 44 | - out: src/Sqlc/MySQL 45 | plugin: php 46 | options: 47 | package: "App\\Sqlc\\MySQL" 48 | ``` 49 | 50 | Exmaple of a complete `sqlc.yaml` config: 51 | ```yaml 52 | version: '2' 53 | plugins: 54 | - name: php 55 | wasm: 56 | url: https://github.com/lcarilla/sqlc-plugin-php-dbal/releases/download/v0.0.2/sqlc-gen-php.wasm 57 | sha256: 74f7a968592aeb6171113ad0cb972b7da9739c33f26738fbd6b2eee8893ce157 58 | sql: 59 | - schema: sqlc/authors/mysql/schema.sql 60 | queries: sqlc/authors/mysql/query.sql 61 | engine: mysql 62 | codegen: 63 | - out: src/Sqlc/MySQL 64 | plugin: php 65 | options: 66 | package: "App\\Sqlc\\MySQL" 67 | ``` 68 | 69 | ### Options 70 | 71 | - `package`: The PHP namespace for generated classes 72 | - `out`: Output directory for generated code 73 | 74 | ## Example Usage 75 | 76 | ### Schema Definition 77 | 78 | ```sql 79 | CREATE TABLE author ( 80 | author_id integer NOT NULL AUTO_INCREMENT PRIMARY KEY, 81 | name text NOT NULL 82 | ) ENGINE=InnoDB; 83 | ``` 84 | 85 | ### Query Definition 86 | 87 | ```sql 88 | /* name: GetAuthor :one */ 89 | SELECT * FROM author 90 | WHERE author_id = ?; 91 | ``` 92 | 93 | ### Generated PHP Code 94 | 95 | The plugin will generate PHP classes for the Models and Queries that you can use in your application: 96 | 97 | ```php 98 | use App\Sqlc\MySQL\QueriesImpl; 99 | 100 | $author = new QueriesImpl($connection)->getAuthor(authorId: 1); 101 | ``` 102 | 103 | ## Development Status 104 | 105 | - ✅ MySQL support 106 | - 🚧 PostgreSQL support (Work in Progress) 107 | - ✅ Basic CRUD operations 108 | - ✅ Complex queries with joins 109 | - ✅ Type-safe parameters 110 | - ✅ Array parameters 111 | 112 | ## Contributing 113 | 114 | Contributions are welcome! Please feel free to submit a Pull Request. 115 | 116 | ## License 117 | 118 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. 119 | -------------------------------------------------------------------------------- /internal/gen.go: -------------------------------------------------------------------------------- 1 | package generator 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "context" 7 | _ "embed" 8 | "encoding/json" 9 | "strings" 10 | _ "strings" 11 | "text/template" 12 | 13 | "github.com/lcarilla/sqlc-plugin-php-dbal/internal/core" 14 | "github.com/sqlc-dev/plugin-sdk-go/plugin" 15 | "github.com/sqlc-dev/plugin-sdk-go/sdk" 16 | ) 17 | 18 | //go:embed tmpl/models.tmpl 19 | var modelsTemplate string 20 | 21 | //go:embed tmpl/query_impl.tmpl 22 | var queryImplTemplate string 23 | 24 | //go:embed tmpl/query_interface.tmpl 25 | var queryInterfaceTemplate string 26 | 27 | func Offset(v int) int { 28 | return v + 1 29 | } 30 | 31 | func RemoveBlankLines(s string) string { 32 | skipNextSpace := false 33 | var lines []string 34 | for _, l := range strings.Split(s, "\n") { 35 | isSpace := len(strings.TrimSpace(l)) == 0 36 | if !isSpace || !skipNextSpace { 37 | lines = append(lines, l) 38 | } 39 | skipNextSpace = isSpace 40 | } 41 | o := strings.Join(lines, "\n") 42 | o += "\n" 43 | return o 44 | } 45 | 46 | func executeTemplate(name string, t *template.Template, ctx interface{}, output map[string]string) error { 47 | var b bytes.Buffer 48 | w := bufio.NewWriter(&b) 49 | if err := t.Execute(w, ctx); err != nil { 50 | return err 51 | } 52 | if err := w.Flush(); err != nil { 53 | return err 54 | } 55 | output[name] = RemoveBlankLines(b.String()) 56 | return nil 57 | } 58 | 59 | func Generate(_ context.Context, req *plugin.GenerateRequest) (*plugin.GenerateResponse, error) { 60 | var conf core.Config 61 | if len(req.PluginOptions) > 0 { 62 | if err := json.Unmarshal(req.PluginOptions, &conf); err != nil { 63 | return nil, err 64 | } 65 | } 66 | 67 | modelClasses := core.BuildDataClasses(req) 68 | queries, emitModelClasses, err := core.BuildQueries(req, modelClasses) 69 | if err != nil { 70 | return nil, err 71 | } 72 | 73 | funcMap := template.FuncMap{ 74 | "lowerTitle": sdk.LowerTitle, 75 | "comment": sdk.DoubleSlashComment, 76 | "offset": Offset, 77 | } 78 | 79 | modelsFile := template.Must(template.New("table").Funcs(funcMap).Parse(modelsTemplate)) 80 | sqlFile := template.Must(template.New("table").Funcs(funcMap).Parse(queryImplTemplate)) 81 | ifaceFile := template.Must(template.New("table").Funcs(funcMap).Parse(queryInterfaceTemplate)) 82 | 83 | queryTemplateContext := core.QueriesTmplCtx{ 84 | Settings: req.Settings, 85 | Package: conf.Package, 86 | Queries: queries, 87 | SqlcVersion: req.SqlcVersion, 88 | } 89 | 90 | output := map[string]string{} 91 | 92 | if err := executeTemplate("Queries.php", ifaceFile, queryTemplateContext, output); err != nil { 93 | return nil, err 94 | } 95 | if err := executeTemplate("QueriesImpl.php", sqlFile, queryTemplateContext, output); err != nil { 96 | return nil, err 97 | } 98 | 99 | for i := range modelClasses { 100 | modelClass := &modelClasses[i] 101 | if err := executeTemplate(modelClass.Name+".php", modelsFile, &core.ModelsTmplCtx{ 102 | Package: conf.Package, 103 | SqlcVersion: req.SqlcVersion, 104 | ModelClass: modelClass, 105 | }, output); err != nil { 106 | return nil, err 107 | } 108 | } 109 | 110 | for _, modelClass := range emitModelClasses { 111 | if err := executeTemplate(modelClass.Name+".php", modelsFile, &core.ModelsTmplCtx{ 112 | Package: conf.Package, 113 | SqlcVersion: req.SqlcVersion, 114 | ModelClass: modelClass, 115 | }, output); err != nil { 116 | return nil, err 117 | } 118 | } 119 | 120 | resp := plugin.GenerateResponse{} 121 | for filename, code := range output { 122 | resp.Files = append(resp.Files, &plugin.File{ 123 | Name: filename, 124 | Contents: []byte(code), 125 | }) 126 | } 127 | 128 | return &resp, nil 129 | } 130 | -------------------------------------------------------------------------------- /internal/tmpl/query_impl.tmpl: -------------------------------------------------------------------------------- 1 | connection->executeQuery({{.ConstantName}}, $params, $types); 42 | $results = $query->fetchAllAssociative(); 43 | /** 44 | * @var $ret array<{{.Ret.Type}}> 45 | */ 46 | $ret = []; 47 | if(count($results) != 1){ 48 | throw new \Exception("NOT 1 ROW RETURNED"); 49 | } 50 | foreach ($results as $row) { 51 | $ret[] = new {{.Ret.Type}}({{.Ret.ResultSet}}); 52 | } 53 | 54 | return $ret[0]; 55 | } 56 | {{end}} 57 | 58 | {{if eq .Cmd ":many"}} 59 | {{range .Comments}}//{{.}} 60 | {{end}} 61 | /** 62 | * @throws Exception 63 | */ 64 | public function {{.MethodName}}({{.Arg.Args}}): array 65 | { 66 | $params = [ 67 | {{ .Arg.Bindings }} 68 | ]; 69 | $types = [ 70 | {{ .Arg.DBALTypes }} 71 | ]; 72 | $query = $this->connection->executeQuery({{.ConstantName}}, $params, $types); 73 | $results = $query->fetchAllAssociative(); 74 | /** 75 | * @var $ret array<{{.Ret.Type}}> 76 | */ 77 | $ret = []; 78 | foreach ($results as $row) { 79 | $ret[] = new {{.Ret.Type}}({{.Ret.ResultSet}}); 80 | } 81 | return $ret; 82 | } 83 | {{end}} 84 | 85 | {{if eq .Cmd ":exec"}} 86 | {{range .Comments}}//{{.}} 87 | {{end}} 88 | /** 89 | * @throws Exception 90 | */ 91 | public function {{.MethodName}}({{.Arg.Args}}): void 92 | { 93 | $params = [ 94 | {{ .Arg.Bindings }} 95 | ]; 96 | $types = [ 97 | {{ .Arg.DBALTypes }} 98 | ]; 99 | $this->connection->executeQuery({{.ConstantName}}, $params, $types); 100 | } 101 | {{end}} 102 | 103 | {{if eq .Cmd ":execrows"}} 104 | {{range .Comments}}//{{.}} 105 | {{end}} 106 | /** 107 | * @throws Exception 108 | */ 109 | public function {{.MethodName}}({{.Arg.Args}}): int|string 110 | { 111 | $params = [ 112 | {{ .Arg.Bindings }} 113 | ]; 114 | $types = [ 115 | {{ .Arg.DBALTypes }} 116 | ]; 117 | $this->connection->executeQuery({{.ConstantName}}, $params, $types); 118 | 119 | return $this->connection->lastInsertId(); 120 | } 121 | {{end}} 122 | 123 | {{if eq .Cmd ":execresult"}} 124 | {{range .Comments}}//{{.}} 125 | {{end}} 126 | /** 127 | * @throws Exception 128 | */ 129 | public function {{.MethodName}}({{.Arg.Args}}): int|string { 130 | $params = [ 131 | {{ .Arg.Bindings }} 132 | ]; 133 | $types = [ 134 | {{ .Arg.DBALTypes }} 135 | ]; 136 | $this->connection->executeQuery({{.ConstantName}}, $params, $types); 137 | 138 | return $this->connection->lastInsertId(); 139 | } 140 | {{end}} 141 | {{end}} 142 | } 143 | 144 | -------------------------------------------------------------------------------- /examples/symfony-example/symfony.lock: -------------------------------------------------------------------------------- 1 | { 2 | "doctrine/doctrine-bundle": { 3 | "version": "2.13", 4 | "recipe": { 5 | "repo": "github.com/symfony/recipes", 6 | "branch": "main", 7 | "version": "2.13", 8 | "ref": "8d96c0b51591ffc26794d865ba3ee7d193438a83" 9 | }, 10 | "files": [ 11 | "config/packages/doctrine.yaml", 12 | "src/Entity/.gitignore", 13 | "src/Repository/.gitignore" 14 | ] 15 | }, 16 | "doctrine/doctrine-migrations-bundle": { 17 | "version": "3.4", 18 | "recipe": { 19 | "repo": "github.com/symfony/recipes", 20 | "branch": "main", 21 | "version": "3.1", 22 | "ref": "1d01ec03c6ecbd67c3375c5478c9a423ae5d6a33" 23 | }, 24 | "files": [ 25 | "config/packages/doctrine_migrations.yaml", 26 | "migrations/.gitignore" 27 | ] 28 | }, 29 | "phpunit/phpunit": { 30 | "version": "9.6", 31 | "recipe": { 32 | "repo": "github.com/symfony/recipes", 33 | "branch": "main", 34 | "version": "9.6", 35 | "ref": "6a9341aa97d441627f8bd424ae85dc04c944f8b4" 36 | }, 37 | "files": [ 38 | ".env.test", 39 | "phpunit.xml.dist", 40 | "tests/bootstrap.php" 41 | ] 42 | }, 43 | "symfony/console": { 44 | "version": "7.2", 45 | "recipe": { 46 | "repo": "github.com/symfony/recipes", 47 | "branch": "main", 48 | "version": "5.3", 49 | "ref": "1781ff40d8a17d87cf53f8d4cf0c8346ed2bb461" 50 | }, 51 | "files": [ 52 | "bin/console" 53 | ] 54 | }, 55 | "symfony/flex": { 56 | "version": "2.4", 57 | "recipe": { 58 | "repo": "github.com/symfony/recipes", 59 | "branch": "main", 60 | "version": "2.4", 61 | "ref": "52e9754527a15e2b79d9a610f98185a1fe46622a" 62 | }, 63 | "files": [ 64 | ".env", 65 | ".env.dev" 66 | ] 67 | }, 68 | "symfony/framework-bundle": { 69 | "version": "7.2", 70 | "recipe": { 71 | "repo": "github.com/symfony/recipes", 72 | "branch": "main", 73 | "version": "7.2", 74 | "ref": "87bcf6f7c55201f345d8895deda46d2adbdbaa89" 75 | }, 76 | "files": [ 77 | "config/packages/cache.yaml", 78 | "config/packages/framework.yaml", 79 | "config/preload.php", 80 | "config/routes/framework.yaml", 81 | "config/services.yaml", 82 | "public/index.php", 83 | "src/Controller/.gitignore", 84 | "src/Kernel.php" 85 | ] 86 | }, 87 | "symfony/phpunit-bridge": { 88 | "version": "7.2", 89 | "recipe": { 90 | "repo": "github.com/symfony/recipes", 91 | "branch": "main", 92 | "version": "6.3", 93 | "ref": "a411a0480041243d97382cac7984f7dce7813c08" 94 | }, 95 | "files": [ 96 | ".env.test", 97 | "bin/phpunit", 98 | "phpunit.xml.dist", 99 | "tests/bootstrap.php" 100 | ] 101 | }, 102 | "symfony/routing": { 103 | "version": "7.2", 104 | "recipe": { 105 | "repo": "github.com/symfony/recipes", 106 | "branch": "main", 107 | "version": "7.0", 108 | "ref": "21b72649d5622d8f7da329ffb5afb232a023619d" 109 | }, 110 | "files": [ 111 | "config/packages/routing.yaml", 112 | "config/routes.yaml" 113 | ] 114 | }, 115 | "symfony/uid": { 116 | "version": "7.2", 117 | "recipe": { 118 | "repo": "github.com/symfony/recipes", 119 | "branch": "main", 120 | "version": "7.0", 121 | "ref": "0df5844274d871b37fc3816c57a768ffc60a43a5" 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /.idea/php.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 60 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= 2 | github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= 3 | github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= 4 | github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= 5 | github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= 6 | github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= 7 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 8 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 9 | github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= 10 | github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 11 | github.com/sqlc-dev/plugin-sdk-go v1.23.0 h1:iSeJhnXPlbDXlbzUEebw/DxsGzE9rdDJArl8Hvt0RMM= 12 | github.com/sqlc-dev/plugin-sdk-go v1.23.0/go.mod h1:I1r4THOfyETD+LI2gogN2LX8wCjwUZrgy/NU4In3llA= 13 | go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY= 14 | go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE= 15 | go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY= 16 | go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE= 17 | go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY= 18 | go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ= 19 | go.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk= 20 | go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0= 21 | go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= 22 | go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4JjxTeYusH7zMc= 23 | go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8= 24 | go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk= 25 | go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys= 26 | go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A= 27 | go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k= 28 | golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= 29 | golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= 30 | golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c= 31 | golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= 32 | golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= 33 | golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 34 | golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= 35 | golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= 36 | golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= 37 | golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= 38 | golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= 39 | golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= 40 | google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 h1:X58yt85/IXCx0Y3ZwN6sEIKZzQtDEYaBWrDvErdXrRE= 41 | google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= 42 | google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4 h1:iK2jbkWL86DXjEx0qiHcRE9dE4/Ahua5k6V8OWFb//c= 43 | google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I= 44 | google.golang.org/grpc v1.69.4 h1:MF5TftSMkd8GLw/m0KM6V8CMOCY6NZ1NQDPGFgbTt4A= 45 | google.golang.org/grpc v1.69.4/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= 46 | google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg= 47 | google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= 48 | google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU= 49 | google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= 50 | google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= 51 | google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= 52 | -------------------------------------------------------------------------------- /internal/core/gen.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "golang.org/x/text/cases" 7 | "golang.org/x/text/language" 8 | "sort" 9 | "strings" 10 | 11 | "github.com/sqlc-dev/plugin-sdk-go/metadata" 12 | "github.com/sqlc-dev/plugin-sdk-go/plugin" 13 | "github.com/sqlc-dev/plugin-sdk-go/sdk" 14 | ) 15 | 16 | func dbalParameter(name string) string { 17 | return fmt.Sprintf("$%s,", name) 18 | } 19 | 20 | type Params struct { 21 | ModelClass *ModelClass 22 | } 23 | 24 | func (v Params) isEmpty() bool { 25 | return len(v.ModelClass.Fields) == 0 26 | } 27 | 28 | func (v Params) Args() string { 29 | if v.isEmpty() { 30 | return "" 31 | } 32 | var out []string 33 | fields := v.ModelClass.Fields 34 | for _, f := range fields { 35 | out = append(out, f.Type.String()+" $"+f.Name) 36 | } 37 | if len(out) < 3 { 38 | return strings.Join(out, ", ") 39 | } 40 | return "\n" + indent(strings.Join(out, ",\n"), 6, -1) 41 | } 42 | 43 | func (v Params) Bindings() string { 44 | if v.isEmpty() { 45 | return "" 46 | } 47 | var out []string 48 | for _, f := range v.ModelClass.Fields { 49 | out = append(out, dbalParameter(f.Name)) 50 | } 51 | return indent(strings.Join(out, "\n"), 10, 0) 52 | } 53 | 54 | func dbalType(t phpType) string { 55 | if t.IsInt() { 56 | if t.IsArray { 57 | return "ArrayParameterType::INTEGER" 58 | } 59 | return "ParameterType::INTEGER" 60 | } 61 | if t.IsDateTimeImmutable() { 62 | return "Types::DATE_IMMUTABLE" 63 | } 64 | if t.IsString() { 65 | if t.IsArray { 66 | return "ArrayParameterType::STRING" 67 | } 68 | return "ParameterType::STRING" 69 | } 70 | return "ParameterType::STRING" 71 | } 72 | 73 | func (v Params) DBALTypes() string { 74 | if v.isEmpty() { 75 | return "" 76 | } 77 | var out []string 78 | for _, f := range v.ModelClass.Fields { 79 | out = append(out, dbalType(f.Type)+",") 80 | } 81 | return indent(strings.Join(out, "\n"), 10, 0) 82 | } 83 | 84 | func dbalRowMapping(t phpType, name string) string { 85 | if t.IsDateTimeImmutable() { 86 | return fmt.Sprintf(`$row["%s"] == null ? null : new \DateTimeImmutable($row["%s"])`, name, name) 87 | } 88 | return fmt.Sprintf(`$row["%s"]`, name) 89 | } 90 | 91 | func (v QueryValue) ResultSet() string { 92 | var out []string 93 | for _, f := range v.Struct.Fields { 94 | out = append(out, dbalRowMapping(f.Type, f.OriginalColumnName)) 95 | } 96 | ret := indent(strings.Join(out, ",\n"), 4, -1) 97 | return ret 98 | } 99 | 100 | func dataClassName(name string) string { 101 | out := "" 102 | for _, p := range strings.Split(name, "_") { 103 | out += cases.Title(language.English).String(p) 104 | } 105 | return out 106 | } 107 | 108 | func memberName(name string) string { 109 | return sdk.LowerTitle(dataClassName(name)) 110 | } 111 | 112 | func BuildDataClasses(req *plugin.GenerateRequest) []ModelClass { 113 | var structs []ModelClass 114 | for _, schema := range req.Catalog.Schemas { 115 | if schema.Name == "pg_catalog" || schema.Name == "information_schema" { 116 | continue 117 | } 118 | for _, table := range schema.Tables { 119 | var tableName string 120 | if schema.Name == req.Catalog.DefaultSchema { 121 | tableName = table.Rel.Name 122 | } else { 123 | tableName = schema.Name + "_" + table.Rel.Name 124 | } 125 | structName := dataClassName(tableName) 126 | s := ModelClass{ 127 | Table: plugin.Identifier{Schema: schema.Name, Name: table.Rel.Name}, 128 | Name: structName, 129 | Comment: table.Comment, 130 | } 131 | for _, column := range table.Columns { 132 | s.Fields = append(s.Fields, Field{ 133 | OriginalColumnName: column.Name, 134 | Name: memberName(column.Name), 135 | Type: makePhpTypeFromSqlcColumn(req, column), 136 | Comment: column.Comment, 137 | }) 138 | } 139 | structs = append(structs, s) 140 | } 141 | } 142 | if len(structs) > 0 { 143 | sort.Slice(structs, func(i, j int) bool { return structs[i].Name < structs[j].Name }) 144 | } 145 | return structs 146 | } 147 | 148 | func makePhpTypeFromSqlcColumn(req *plugin.GenerateRequest, col *plugin.Column) phpType { 149 | typ := mapSqlColumnTypeToPhpType(req, col) 150 | return phpType{ 151 | Name: typ, 152 | IsArray: col.IsSqlcSlice, 153 | IsNull: !col.NotNull, 154 | DataType: sdk.DataType(col.Type), 155 | Engine: req.Settings.Engine, 156 | } 157 | } 158 | 159 | func mapSqlColumnTypeToPhpType(req *plugin.GenerateRequest, col *plugin.Column) string { 160 | switch req.Settings.Engine { 161 | case "mysql": 162 | return mysqlType(col) 163 | default: 164 | return "Any" 165 | } 166 | } 167 | 168 | type goColumn struct { 169 | id int 170 | *plugin.Column 171 | } 172 | 173 | func phpColumnsToStruct(req *plugin.GenerateRequest, name string, columns []goColumn, namer func(*plugin.Column, int) string) *ModelClass { 174 | gs := ModelClass{ 175 | Name: name, 176 | } 177 | idSeen := map[int]Field{} 178 | nameSeen := map[string]int{} 179 | for _, c := range columns { 180 | if _, ok := idSeen[c.id]; ok { 181 | continue 182 | } 183 | fieldName := memberName(namer(c.Column, c.id)) 184 | if v := nameSeen[c.Name]; v > 0 { 185 | fieldName = fmt.Sprintf("%s_%d", fieldName, v+1) 186 | } 187 | field := Field{ 188 | OriginalColumnName: c.Column.Name, 189 | ID: c.id, 190 | Name: fieldName, 191 | Type: makePhpTypeFromSqlcColumn(req, c.Column), 192 | } 193 | gs.Fields = append(gs.Fields, field) 194 | nameSeen[c.Name]++ 195 | idSeen[c.id] = field 196 | } 197 | return &gs 198 | } 199 | 200 | func phpParamName(c *plugin.Column, number int) string { 201 | if c.Name != "" { 202 | return c.Name 203 | } 204 | return fmt.Sprintf("dollar_%d", number) 205 | } 206 | 207 | func phpColumnName(c *plugin.Column, pos int) string { 208 | if c.Name != "" { 209 | return c.Name 210 | } 211 | return fmt.Sprintf("column_%d", pos+1) 212 | } 213 | 214 | func BuildQueries(req *plugin.GenerateRequest, modelClasses []ModelClass) ([]Query, []*ModelClass, error) { 215 | queries := make([]Query, 0, len(req.Queries)) 216 | emitModelClasses := make([]*ModelClass, 0) 217 | 218 | for _, query := range req.Queries { 219 | if query.Name == "" || query.Cmd == "" { 220 | continue 221 | } 222 | if query.Cmd == metadata.CmdCopyFrom { 223 | return nil, nil, errors.New("support for CopyFrom in PHP is not implemented") 224 | } 225 | 226 | queryString := query.Text 227 | queryStruct := Query{ 228 | Cmd: query.Cmd, 229 | ClassName: strings.ToUpper(query.Name[:1]) + query.Name[1:], 230 | ConstantName: sdk.LowerTitle(query.Name), 231 | FieldName: sdk.LowerTitle(query.Name) + "Stmt", 232 | MethodName: sdk.LowerTitle(query.Name), 233 | SourceName: query.Filename, 234 | SQL: queryString, 235 | Comments: query.Comments, 236 | } 237 | 238 | var cols []goColumn 239 | for _, p := range query.Params { 240 | cols = append(cols, goColumn{ 241 | id: int(p.Number), 242 | Column: p.Column, 243 | }) 244 | } 245 | params := phpColumnsToStruct(req, queryStruct.ClassName+"Bindings", cols, phpParamName) 246 | queryStruct.Arg = Params{ModelClass: params} 247 | 248 | if len(query.Columns) == 1 { 249 | c := query.Columns[0] 250 | queryStruct.Ret = QueryValue{ 251 | Name: "results", 252 | Typ: makePhpTypeFromSqlcColumn(req, c), 253 | } 254 | } else if len(query.Columns) > 1 { 255 | var gs *ModelClass 256 | 257 | for i := range modelClasses { 258 | s := &modelClasses[i] 259 | if len(s.Fields) != len(query.Columns) { 260 | continue 261 | } 262 | same := true 263 | for i, f := range s.Fields { 264 | c := query.Columns[i] 265 | if f.Name != memberName(phpColumnName(c, i)) || f.Type != makePhpTypeFromSqlcColumn(req, c) || !sdk.SameTableName(c.Table, &s.Table, req.Catalog.DefaultSchema) { 266 | same = false 267 | break 268 | } 269 | } 270 | if same { 271 | gs = s 272 | break 273 | } 274 | } 275 | 276 | if gs == nil { 277 | var columns []goColumn 278 | for i, c := range query.Columns { 279 | columns = append(columns, goColumn{id: i, Column: c}) 280 | } 281 | gs = phpColumnsToStruct(req, queryStruct.ClassName+"Row", columns, phpColumnName) 282 | emitModelClasses = append(emitModelClasses, gs) 283 | } 284 | 285 | queryStruct.Ret = QueryValue{ 286 | Name: "results", 287 | Struct: gs, 288 | } 289 | } 290 | 291 | queries = append(queries, queryStruct) 292 | } 293 | 294 | sort.Slice(queries, func(i, j int) bool { return queries[i].MethodName < queries[j].MethodName }) 295 | return queries, emitModelClasses, nil 296 | } 297 | -------------------------------------------------------------------------------- /examples/symfony-example/src/Sqlc/MySQL/QueriesImpl.php: -------------------------------------------------------------------------------- 1 | connection->executeQuery(bookByTags, $params, $types); 116 | $results = $query->fetchAllAssociative(); 117 | /** 118 | * @var $ret array 119 | */ 120 | $ret = []; 121 | foreach ($results as $row) { 122 | $ret[] = new BookByTagsRow( $row["book_id"], 123 | $row["title"], 124 | $row["name"], 125 | $row["isbn"], 126 | $row["tags"]); 127 | } 128 | return $ret; 129 | } 130 | 131 | /** 132 | * @throws Exception 133 | */ 134 | public function bookByTagsMultiple(array $tags): array 135 | { 136 | $params = [ 137 | $tags, 138 | ]; 139 | $types = [ 140 | ArrayParameterType::STRING, 141 | ]; 142 | $query = $this->connection->executeQuery(bookByTagsMultiple, $params, $types); 143 | $results = $query->fetchAllAssociative(); 144 | /** 145 | * @var $ret array 146 | */ 147 | $ret = []; 148 | foreach ($results as $row) { 149 | $ret[] = new BookByTagsMultipleRow( $row["book_id"], 150 | $row["title"], 151 | $row["name"], 152 | $row["isbn"], 153 | $row["tags"]); 154 | } 155 | return $ret; 156 | } 157 | 158 | /** 159 | * @throws Exception 160 | */ 161 | public function bookByTitleYear(string $uuidToBin, int $yr): array 162 | { 163 | $params = [ 164 | $uuidToBin, 165 | $yr, 166 | ]; 167 | $types = [ 168 | ParameterType::STRING, 169 | ParameterType::INTEGER, 170 | ]; 171 | $query = $this->connection->executeQuery(bookByTitleYear, $params, $types); 172 | $results = $query->fetchAllAssociative(); 173 | /** 174 | * @var $ret array 175 | */ 176 | $ret = []; 177 | foreach ($results as $row) { 178 | $ret[] = new Book( $row["book_id"], 179 | $row["author_id"], 180 | $row["isbn"], 181 | $row["book_type"], 182 | $row["title"], 183 | $row["yr"], 184 | $row["available"] == null ? null : new \DateTimeImmutable($row["available"]), 185 | $row["tags"]); 186 | } 187 | return $ret; 188 | } 189 | 190 | /** 191 | * @throws Exception 192 | */ 193 | public function createAuthor(string $name): int|string { 194 | $params = [ 195 | $name, 196 | ]; 197 | $types = [ 198 | ParameterType::STRING, 199 | ]; 200 | $this->connection->executeQuery(createAuthor, $params, $types); 201 | 202 | return $this->connection->lastInsertId(); 203 | } 204 | 205 | /** 206 | * @throws Exception 207 | */ 208 | public function createBook( 209 | int $authorId, 210 | string $isbn, 211 | string $bookType, 212 | string $uuidToBin, 213 | int $yr, 214 | \DateTimeImmutable $available, 215 | string $tags): int|string { 216 | $params = [ 217 | $authorId, 218 | $isbn, 219 | $bookType, 220 | $uuidToBin, 221 | $yr, 222 | $available, 223 | $tags, 224 | ]; 225 | $types = [ 226 | ParameterType::INTEGER, 227 | ParameterType::STRING, 228 | ParameterType::STRING, 229 | ParameterType::STRING, 230 | ParameterType::INTEGER, 231 | Types::DATE_IMMUTABLE, 232 | ParameterType::STRING, 233 | ]; 234 | $this->connection->executeQuery(createBook, $params, $types); 235 | 236 | return $this->connection->lastInsertId(); 237 | } 238 | 239 | /** 240 | * @throws Exception 241 | */ 242 | public function deleteAuthorBeforeYear(int $yr, int $authorId): void 243 | { 244 | $params = [ 245 | $yr, 246 | $authorId, 247 | ]; 248 | $types = [ 249 | ParameterType::INTEGER, 250 | ParameterType::INTEGER, 251 | ]; 252 | $this->connection->executeQuery(deleteAuthorBeforeYear, $params, $types); 253 | } 254 | 255 | /** 256 | * @throws Exception 257 | */ 258 | public function deleteBook(int $bookId): void 259 | { 260 | $params = [ 261 | $bookId, 262 | ]; 263 | $types = [ 264 | ParameterType::INTEGER, 265 | ]; 266 | $this->connection->executeQuery(deleteBook, $params, $types); 267 | } 268 | 269 | /** 270 | * @throws Exception 271 | */ 272 | public function getAuthor(int $authorId): ?Author 273 | { 274 | $params = [ 275 | $authorId, 276 | ]; 277 | $types = [ 278 | ParameterType::INTEGER, 279 | ]; 280 | $query = $this->connection->executeQuery(getAuthor, $params, $types); 281 | $results = $query->fetchAllAssociative(); 282 | /** 283 | * @var $ret array 284 | */ 285 | $ret = []; 286 | if(count($results) != 1){ 287 | throw new \Exception("NOT 1 ROW RETURNED"); 288 | } 289 | foreach ($results as $row) { 290 | $ret[] = new Author( $row["author_id"], 291 | $row["name"]); 292 | } 293 | 294 | return $ret[0]; 295 | } 296 | 297 | /** 298 | * @throws Exception 299 | */ 300 | public function getBook(int $bookId): ?Book 301 | { 302 | $params = [ 303 | $bookId, 304 | ]; 305 | $types = [ 306 | ParameterType::INTEGER, 307 | ]; 308 | $query = $this->connection->executeQuery(getBook, $params, $types); 309 | $results = $query->fetchAllAssociative(); 310 | /** 311 | * @var $ret array 312 | */ 313 | $ret = []; 314 | if(count($results) != 1){ 315 | throw new \Exception("NOT 1 ROW RETURNED"); 316 | } 317 | foreach ($results as $row) { 318 | $ret[] = new Book( $row["book_id"], 319 | $row["author_id"], 320 | $row["isbn"], 321 | $row["book_type"], 322 | $row["title"], 323 | $row["yr"], 324 | $row["available"] == null ? null : new \DateTimeImmutable($row["available"]), 325 | $row["tags"]); 326 | } 327 | 328 | return $ret[0]; 329 | } 330 | 331 | /** 332 | * @throws Exception 333 | */ 334 | public function updateBook( 335 | string $title, 336 | string $tags, 337 | int $bookId): void 338 | { 339 | $params = [ 340 | $title, 341 | $tags, 342 | $bookId, 343 | ]; 344 | $types = [ 345 | ParameterType::STRING, 346 | ParameterType::STRING, 347 | ParameterType::INTEGER, 348 | ]; 349 | $this->connection->executeQuery(updateBook, $params, $types); 350 | } 351 | 352 | /** 353 | * @throws Exception 354 | */ 355 | public function updateBookISBN( 356 | string $title, 357 | string $tags, 358 | string $isbn, 359 | int $bookId): void 360 | { 361 | $params = [ 362 | $title, 363 | $tags, 364 | $isbn, 365 | $bookId, 366 | ]; 367 | $types = [ 368 | ParameterType::STRING, 369 | ParameterType::STRING, 370 | ParameterType::STRING, 371 | ParameterType::INTEGER, 372 | ]; 373 | $this->connection->executeQuery(updateBookISBN, $params, $types); 374 | } 375 | 376 | } 377 | 378 | -------------------------------------------------------------------------------- /examples/go.sum: -------------------------------------------------------------------------------- 1 | cel.dev/expr v0.18.0 h1:CJ6drgk+Hf96lkLikr4rFf19WrU0BOWEihyZnI2TAzo= 2 | cel.dev/expr v0.18.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw= 3 | filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= 4 | filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= 5 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 6 | github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ= 7 | github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw= 8 | github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= 9 | github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 10 | github.com/cubicdaiya/gonp v1.0.4 h1:ky2uIAJh81WiLcGKBVD5R7KsM/36W6IqqTy6Bo6rGws= 11 | github.com/cubicdaiya/gonp v1.0.4/go.mod h1:iWGuP/7+JVTn02OWhRemVbMmG1DOUnmrGTYYACpOI0I= 12 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 13 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 14 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 15 | github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= 16 | github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= 17 | github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= 18 | github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= 19 | github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= 20 | github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= 21 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 22 | github.com/google/cel-go v0.22.1 h1:AfVXx3chM2qwoSbM7Da8g8hX8OVSkBFwX+rz2+PcK40= 23 | github.com/google/cel-go v0.22.1/go.mod h1:BuznPXXfQDpXKWQ9sPW3TzlAJN5zzFe+i9tIs0yC4s8= 24 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 25 | github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= 26 | github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 27 | github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= 28 | github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= 29 | github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= 30 | github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= 31 | github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= 32 | github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= 33 | github.com/jackc/pgx/v5 v5.7.2 h1:mLoDLV6sonKlvjIEsV56SkWNCnuNv531l94GaIzO+XI= 34 | github.com/jackc/pgx/v5 v5.7.2/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ= 35 | github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= 36 | github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= 37 | github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= 38 | github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= 39 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 40 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 41 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 42 | github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 43 | github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 44 | github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= 45 | github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= 46 | github.com/pganalyze/pg_query_go/v5 v5.1.0 h1:MlxQqHZnvA3cbRQYyIrjxEjzo560P6MyTgtlaf3pmXg= 47 | github.com/pganalyze/pg_query_go/v5 v5.1.0/go.mod h1:FsglvxidZsVN+Ltw3Ai6nTgPVcK2BPukH3jCDEqc1Ug= 48 | github.com/pingcap/errors v0.11.0/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= 49 | github.com/pingcap/errors v0.11.5-0.20240311024730-e056997136bb h1:3pSi4EDG6hg0orE1ndHkXvX6Qdq2cZn8gAPir8ymKZk= 50 | github.com/pingcap/errors v0.11.5-0.20240311024730-e056997136bb/go.mod h1:X2r9ueLEUZgtx2cIogM0v4Zj5uvvzhuuiu7Pn8HzMPg= 51 | github.com/pingcap/failpoint v0.0.0-20240528011301-b51a646c7c86 h1:tdMsjOqUR7YXHoBitzdebTvOjs/swniBTOLy5XiMtuE= 52 | github.com/pingcap/failpoint v0.0.0-20240528011301-b51a646c7c86/go.mod h1:exzhVYca3WRtd6gclGNErRWb1qEgff3LYta0LvRmON4= 53 | github.com/pingcap/log v1.1.0 h1:ELiPxACz7vdo1qAvvaWJg1NrYFoY6gqAh/+Uo6aXdD8= 54 | github.com/pingcap/log v1.1.0/go.mod h1:DWQW5jICDR7UJh4HtxXSM20Churx4CQL0fwL/SoOSA4= 55 | github.com/pingcap/tidb/pkg/parser v0.0.0-20241203170126-9812d85d0d25 h1:sAHMshrilTiR9ue2SktI/tVVT2gB4kNaQaY5pbs0YQQ= 56 | github.com/pingcap/tidb/pkg/parser v0.0.0-20241203170126-9812d85d0d25/go.mod h1:Hju1TEWZvrctQKbztTRwXH7rd41Yq0Pgmq4PrEKcq7o= 57 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 58 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 59 | github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= 60 | github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= 61 | github.com/riza-io/grpc-go v0.2.0 h1:2HxQKFVE7VuYstcJ8zqpN84VnAoJ4dCL6YFhJewNcHQ= 62 | github.com/riza-io/grpc-go v0.2.0/go.mod h1:2bDvR9KkKC3KhtlSHfR3dAXjUMT86kg4UfWFyVGWqi8= 63 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 64 | github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= 65 | github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= 66 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 67 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 68 | github.com/sqlc-dev/sqlc v1.28.0 h1:2QB4X22pKNpKMyb8dRLnqZwMXW6S+ZCyYCpa+3/ICcI= 69 | github.com/sqlc-dev/sqlc v1.28.0/go.mod h1:x6wDsOHH60dTX3ES9sUUxRVaROg5aFB3l3nkkjyuK1A= 70 | github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU= 71 | github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= 72 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 73 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 74 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 75 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 76 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 77 | github.com/tetratelabs/wazero v1.8.2 h1:yIgLR/b2bN31bjxwXHD8a3d+BogigR952csSDdLYEv4= 78 | github.com/tetratelabs/wazero v1.8.2/go.mod h1:yAI0XTsMBhREkM/YDAK/zNou3GoiAce1P6+rp/wQhjs= 79 | github.com/wasilibs/go-pgquery v0.0.0-20240606042535-c0843d6592cc h1:Hgim1Xgk1+viV7p0aZh9OOrMRfG+E4mGA+JsI2uB0+k= 80 | github.com/wasilibs/go-pgquery v0.0.0-20240606042535-c0843d6592cc/go.mod h1:ah6UfXIl/oA0K3SbourB/UHggVJOBXwPZ2XudDmmFac= 81 | github.com/wasilibs/wazero-helpers v0.0.0-20240604052452-61d7981e9a38 h1:RBu75fhabyxyGJ2zhkoNuRyObBMhVeMoXqmeaPTg2CQ= 82 | github.com/wasilibs/wazero-helpers v0.0.0-20240604052452-61d7981e9a38/go.mod h1:Z80JvMwvze8KUlVQIdw9L7OSskZJ1yxlpi4AQhoQe4s= 83 | go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= 84 | go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= 85 | go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= 86 | go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= 87 | go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= 88 | go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= 89 | go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= 90 | go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= 91 | go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= 92 | go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= 93 | go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= 94 | go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= 95 | go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= 96 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 97 | golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= 98 | golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= 99 | golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= 100 | golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= 101 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 102 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 103 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 104 | golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= 105 | golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= 106 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 107 | golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= 108 | golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 109 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 110 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 111 | golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= 112 | golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 113 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 114 | golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= 115 | golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= 116 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 117 | golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 118 | golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 119 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 120 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 121 | google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53 h1:fVoAXEKA4+yufmbdVYv+SE73+cPZbbbe8paLsHfkK+U= 122 | google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53/go.mod h1:riSXTwQ4+nqmPGtobMFyW5FqVAmIs0St6VPp4Ug7CE4= 123 | google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 h1:X58yt85/IXCx0Y3ZwN6sEIKZzQtDEYaBWrDvErdXrRE= 124 | google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= 125 | google.golang.org/grpc v1.69.4 h1:MF5TftSMkd8GLw/m0KM6V8CMOCY6NZ1NQDPGFgbTt4A= 126 | google.golang.org/grpc v1.69.4/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= 127 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 128 | google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 129 | google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU= 130 | google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= 131 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 132 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 133 | gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= 134 | gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= 135 | gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= 136 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 137 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 138 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 139 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 140 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 141 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 142 | modernc.org/libc v1.55.3 h1:AzcW1mhlPNrRtjS5sS+eW2ISCgSOLLNyFzRh/V3Qj/U= 143 | modernc.org/libc v1.55.3/go.mod h1:qFXepLhz+JjFThQ4kzwzOjA/y/artDeg+pcYnY+Q83w= 144 | modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= 145 | modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= 146 | modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E= 147 | modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU= 148 | modernc.org/sqlite v1.34.5 h1:Bb6SR13/fjp15jt70CL4f18JIN7p7dnMExd+UFnF15g= 149 | modernc.org/sqlite v1.34.5/go.mod h1:YLuNmX9NKs8wRNK2ko1LW1NGYcc9FkBO69JOt1AR9JE= 150 | -------------------------------------------------------------------------------- /.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 29 | 30 | $PROJECT_DIR$/symfony-example/composer.json 31 | 32 | 33 | 34 | 35 | 37 | 38 | 41 | 42 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | { 99 | "associatedIndex": 6 100 | } 101 | 102 | 103 | 107 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 169 | 170 | 171 | 172 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 202 | 203 | 204 | 216 | 217 | 218 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 1742498464560 247 | 256 | 257 | 264 | 265 | 272 | 275 | 276 | 278 | 279 | 280 | 282 | 283 | true 284 | 285 | --------------------------------------------------------------------------------