├── .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 |
5 |
6 |
11 |
12 |
13 |
14 |
15 |
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 |
59 |
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 |
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 | $PROJECT_DIR$/symfony-example/composer.json
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
41 |
42 |
43 |
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 |
104 |
105 |
106 |
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 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 | 1742498464560
247 |
248 |
249 | 1742498464560
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 | 1742506065475
259 |
260 |
261 |
262 | 1742506065475
263 |
264 |
265 |
266 | 1742506070552
267 |
268 |
269 |
270 | 1742506070552
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 | true
284 |
285 |
--------------------------------------------------------------------------------