Skip to content

Commit c020c8f

Browse files
committed
change loader, sequence, handle syntax
1 parent 0c98181 commit c020c8f

File tree

7 files changed

+479
-175
lines changed

7 files changed

+479
-175
lines changed

.github/workflows/test-migrations.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ jobs:
247247
working-directory: taco
248248
env:
249249
OPENTACO_QUERY_BACKEND: sqlite
250-
OPENTACO_SQLITE_PATH: ./test.db
250+
OPENTACO_SQLITE_PATH: test.db
251251
OPENTACO_AUTH_DISABLE: true
252252
run: |
253253
# Run binary and capture output

go.work.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1679,6 +1679,7 @@ golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 h1:4+4C/Iv2U4fMZBiMCc98MG
16791679
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
16801680
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
16811681
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
1682+
golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg=
16821683
golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ=
16831684
golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
16841685
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
@@ -1743,6 +1744,7 @@ golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c
17431744
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
17441745
golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ=
17451746
golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
1747+
golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0=
17461748
golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw=
17471749
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
17481750
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY=

taco/internal/atlas_loader.go

Lines changed: 109 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@ package main
44

55
import (
66
"fmt"
7-
"io"
7+
"log"
88
"os"
9+
"strings"
910

10-
"ariga.io/atlas-provider-gorm/gormschema"
1111
"github.com/diggerhq/digger/opentaco/internal/query/types"
12+
"gorm.io/driver/sqlite"
13+
"gorm.io/gorm"
14+
"gorm.io/gorm/logger"
1215
)
1316

1417
func main() {
@@ -18,11 +21,111 @@ func main() {
1821
dialect = os.Args[1]
1922
}
2023

21-
stmts, err := gormschema.New(dialect).Load(types.DefaultModels...)
24+
var db *gorm.DB
25+
var err error
26+
27+
// Create an in-memory database for schema generation
28+
switch dialect {
29+
case "postgres":
30+
// Use SQLite in postgres mode for schema generation since we just need the structure
31+
db, err = gorm.Open(sqlite.Open("file::memory:?cache=shared"), &gorm.Config{
32+
Logger: logger.Default.LogMode(logger.Silent),
33+
})
34+
case "mysql":
35+
db, err = gorm.Open(sqlite.Open("file::memory:?cache=shared"), &gorm.Config{
36+
Logger: logger.Default.LogMode(logger.Silent),
37+
})
38+
case "sqlite":
39+
db, err = gorm.Open(sqlite.Open("file::memory:?cache=shared"), &gorm.Config{
40+
Logger: logger.Default.LogMode(logger.Silent),
41+
})
42+
default:
43+
log.Fatalf("Unknown dialect: %s", dialect)
44+
}
45+
46+
if err != nil {
47+
log.Fatalf("Failed to open in-memory database: %v", err)
48+
}
49+
50+
// Auto-migrate to generate schema
51+
err = db.AutoMigrate(types.DefaultModels...)
52+
if err != nil {
53+
log.Fatalf("Failed to auto-migrate: %v", err)
54+
}
55+
56+
// Get raw SQL connection
57+
sqlDB, err := db.DB()
58+
if err != nil {
59+
log.Fatalf("Failed to get sql.DB: %v", err)
60+
}
61+
62+
// Query sqlite_master to get CREATE statements in creation order (rootpage preserves order)
63+
rows, err := sqlDB.Query("SELECT sql FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY rootpage")
64+
if err != nil {
65+
log.Fatalf("Failed to query schema: %v", err)
66+
}
67+
defer rows.Close()
68+
69+
var statements []string
70+
for rows.Next() {
71+
var sql string
72+
if err := rows.Scan(&sql); err != nil {
73+
log.Fatalf("Failed to scan row: %v", err)
74+
}
75+
if sql != "" {
76+
statements = append(statements, adaptSQL(sql, dialect))
77+
}
78+
}
79+
80+
// Also get indexes
81+
rows, err = sqlDB.Query("SELECT sql FROM sqlite_master WHERE type='index' AND name NOT LIKE 'sqlite_%' ORDER BY rootpage")
2282
if err != nil {
23-
fmt.Fprintf(os.Stderr, "Error loading schema for %s: %v\n", dialect, err)
24-
os.Exit(1)
83+
log.Fatalf("Failed to query indexes: %v", err)
2584
}
26-
io.WriteString(os.Stdout, stmts)
85+
defer rows.Close()
86+
87+
for rows.Next() {
88+
var sql string
89+
if err := rows.Scan(&sql); err != nil {
90+
log.Fatalf("Failed to scan row: %v", err)
91+
}
92+
if sql != "" {
93+
statements = append(statements, adaptSQL(sql, dialect))
94+
}
95+
}
96+
97+
// Output all statements
98+
fmt.Println(strings.Join(statements, ";\n") + ";")
2799
}
28100

101+
// adaptSQL adapts SQLite SQL to target dialect
102+
func adaptSQL(sql, dialect string) string {
103+
switch dialect {
104+
case "postgres":
105+
// PostgreSQL uses double quotes for identifiers, single quotes for strings
106+
sql = strings.ReplaceAll(sql, "`", "\"")
107+
sql = strings.ReplaceAll(sql, "AUTOINCREMENT", "")
108+
sql = strings.ReplaceAll(sql, "datetime", "timestamptz")
109+
sql = strings.ReplaceAll(sql, "numeric", "boolean")
110+
sql = strings.ReplaceAll(sql, "integer", "int")
111+
// Fix DEFAULT clause - PostgreSQL uses single quotes for string literals
112+
sql = strings.ReplaceAll(sql, "DEFAULT \"allow\"", "DEFAULT 'allow'")
113+
sql = strings.ReplaceAll(sql, "DEFAULT \"\"", "DEFAULT ''")
114+
case "mysql":
115+
// MySQL uses backticks (already correct from SQLite)
116+
sql = strings.ReplaceAll(sql, "AUTOINCREMENT", "AUTO_INCREMENT")
117+
sql = strings.ReplaceAll(sql, "timestamptz", "datetime")
118+
sql = strings.ReplaceAll(sql, "numeric", "tinyint(1)")
119+
// MySQL has limitations with TEXT (no DEFAULT, no index without key length)
120+
// Convert most text fields to varchar(255), keep only truly large fields as text
121+
sql = strings.ReplaceAll(sql, " text NOT NULL DEFAULT", " varchar(255) NOT NULL DEFAULT")
122+
sql = strings.ReplaceAll(sql, " text DEFAULT", " varchar(255) DEFAULT")
123+
sql = strings.ReplaceAll(sql, " text NOT NULL", " varchar(255) NOT NULL")
124+
sql = strings.ReplaceAll(sql, " text,", " text,") // Keep text for description, resource_patterns
125+
sql = strings.ReplaceAll(sql, "`action` varchar(255)", "`action` varchar(128)") // Smaller for indexed fields
126+
sql = strings.ReplaceAll(sql, "`effect` varchar(255) NOT NULL DEFAULT", "`effect` varchar(8) NOT NULL DEFAULT")
127+
case "sqlite":
128+
// No adaptation needed
129+
}
130+
return sql
131+
}
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,99 @@
1+
-- Create "unit_tags" table
2+
CREATE TABLE `unit_tags` (
3+
`unit_id` varchar(36) NOT NULL,
4+
`tag_id` varchar(36) NOT NULL,
5+
PRIMARY KEY (`unit_id`, `tag_id`),
6+
INDEX `idx_unit_tags_tag_id` (`tag_id`),
7+
INDEX `idx_unit_tags_unit_id` (`unit_id`)
8+
) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
19
-- Create "permissions" table
210
CREATE TABLE `permissions` (
311
`id` varchar(36) NOT NULL,
412
`org_id` varchar(36) NULL,
513
`name` varchar(255) NOT NULL,
6-
`description` longtext NULL,
7-
`created_by` longtext NULL,
8-
`created_at` datetime(3) NULL,
14+
`description` text NULL,
15+
`created_by` text NULL,
16+
`created_at` datetime NULL,
917
PRIMARY KEY (`id`),
1018
INDEX `idx_permissions_name` (`name`),
1119
INDEX `idx_permissions_org_id` (`org_id`)
1220
) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
21+
-- Create "role_permissions" table
22+
CREATE TABLE `role_permissions` (
23+
`role_id` varchar(36) NOT NULL,
24+
`permission_id` varchar(36) NOT NULL,
25+
PRIMARY KEY (`role_id`, `permission_id`),
26+
INDEX `idx_role_permissions_permission_id` (`permission_id`),
27+
INDEX `idx_role_permissions_role_id` (`role_id`)
28+
) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
29+
-- Create "roles" table
30+
CREATE TABLE `roles` (
31+
`id` varchar(36) NOT NULL,
32+
`org_id` varchar(36) NULL,
33+
`name` varchar(255) NOT NULL,
34+
`description` text NULL,
35+
`created_at` datetime NULL,
36+
`created_by` text NULL,
37+
PRIMARY KEY (`id`),
38+
INDEX `idx_roles_name` (`name`),
39+
INDEX `idx_roles_org_id` (`org_id`)
40+
) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
41+
-- Create "tags" table
42+
CREATE TABLE `tags` (
43+
`id` varchar(36) NOT NULL,
44+
`org_id` varchar(36) NULL,
45+
`name` varchar(255) NOT NULL,
46+
PRIMARY KEY (`id`),
47+
INDEX `idx_tags_name` (`name`),
48+
INDEX `idx_tags_org_id` (`org_id`)
49+
) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
1350
-- Create "organizations" table
1451
CREATE TABLE `organizations` (
1552
`id` varchar(36) NOT NULL,
1653
`name` varchar(255) NOT NULL,
1754
`display_name` varchar(255) NOT NULL,
1855
`created_by` varchar(255) NOT NULL,
19-
`created_at` datetime(3) NULL,
20-
`updated_at` datetime(3) NULL,
56+
`created_at` datetime NULL,
57+
`updated_at` datetime NULL,
2158
PRIMARY KEY (`id`),
2259
UNIQUE INDEX `idx_organizations_name` (`name`)
2360
) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
24-
-- Create "roles" table
25-
CREATE TABLE `roles` (
61+
-- Create "units" table
62+
CREATE TABLE `units` (
2663
`id` varchar(36) NOT NULL,
2764
`org_id` varchar(36) NULL,
2865
`name` varchar(255) NOT NULL,
29-
`description` longtext NULL,
30-
`created_at` datetime(3) NULL,
31-
`created_by` longtext NULL,
66+
`size` int NULL DEFAULT 0,
67+
`updated_at` datetime NULL,
68+
`locked` bool NULL DEFAULT 0,
69+
`lock_id` varchar(255) NULL DEFAULT "",
70+
`lock_who` varchar(255) NULL DEFAULT "",
71+
`lock_created` datetime NULL,
3272
PRIMARY KEY (`id`),
33-
INDEX `idx_roles_name` (`name`),
34-
INDEX `idx_roles_org_id` (`org_id`)
73+
INDEX `idx_units_name` (`name`),
74+
INDEX `idx_units_org_id` (`org_id`)
3575
) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
36-
-- Create "role_permissions" table
37-
CREATE TABLE `role_permissions` (
76+
-- Create "user_roles" table
77+
CREATE TABLE `user_roles` (
78+
`user_id` varchar(36) NOT NULL,
3879
`role_id` varchar(36) NOT NULL,
39-
`permission_id` varchar(36) NOT NULL,
40-
PRIMARY KEY (`role_id`, `permission_id`),
41-
INDEX `idx_role_permissions_permission_id` (`permission_id`),
42-
INDEX `idx_role_permissions_role_id` (`role_id`),
43-
CONSTRAINT `fk_role_permissions_permission` FOREIGN KEY (`permission_id`) REFERENCES `permissions` (`id`) ON UPDATE CASCADE ON DELETE CASCADE,
44-
CONSTRAINT `fk_role_permissions_role` FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`) ON UPDATE CASCADE ON DELETE CASCADE
80+
`org_id` varchar(36) NOT NULL,
81+
PRIMARY KEY (`user_id`, `role_id`, `org_id`),
82+
INDEX `idx_user_roles_org_id` (`org_id`),
83+
INDEX `idx_user_roles_role_id` (`role_id`),
84+
INDEX `idx_user_roles_user_id` (`user_id`)
85+
) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
86+
-- Create "users" table
87+
CREATE TABLE `users` (
88+
`id` varchar(36) NOT NULL,
89+
`subject` varchar(255) NOT NULL,
90+
`email` varchar(255) NOT NULL,
91+
`created_at` datetime NULL,
92+
`updated_at` datetime NULL,
93+
`version` int NULL,
94+
PRIMARY KEY (`id`),
95+
UNIQUE INDEX `idx_users_email` (`email`),
96+
UNIQUE INDEX `idx_users_subject` (`subject`)
4597
) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
4698
-- Create "rules" table
4799
CREATE TABLE `rules` (
@@ -85,61 +137,3 @@ CREATE TABLE `rule_units` (
85137
INDEX `idx_rule_units_unit_id` (`unit_id`),
86138
CONSTRAINT `fk_rules_unit_targets` FOREIGN KEY (`rule_id`) REFERENCES `rules` (`id`) ON UPDATE NO ACTION ON DELETE CASCADE
87139
) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
88-
-- Create "tags" table
89-
CREATE TABLE `tags` (
90-
`id` varchar(36) NOT NULL,
91-
`org_id` varchar(36) NULL,
92-
`name` varchar(255) NOT NULL,
93-
PRIMARY KEY (`id`),
94-
INDEX `idx_tags_name` (`name`),
95-
INDEX `idx_tags_org_id` (`org_id`)
96-
) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
97-
-- Create "units" table
98-
CREATE TABLE `units` (
99-
`id` varchar(36) NOT NULL,
100-
`org_id` varchar(36) NULL,
101-
`name` varchar(255) NOT NULL,
102-
`size` bigint NULL DEFAULT 0,
103-
`updated_at` datetime(3) NULL,
104-
`locked` bool NULL DEFAULT 0,
105-
`lock_id` varchar(191) NULL DEFAULT "",
106-
`lock_who` varchar(191) NULL DEFAULT "",
107-
`lock_created` datetime(3) NULL,
108-
PRIMARY KEY (`id`),
109-
INDEX `idx_units_name` (`name`),
110-
INDEX `idx_units_org_id` (`org_id`)
111-
) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
112-
-- Create "unit_tags" table
113-
CREATE TABLE `unit_tags` (
114-
`unit_id` varchar(36) NOT NULL,
115-
`tag_id` varchar(36) NOT NULL,
116-
PRIMARY KEY (`unit_id`, `tag_id`),
117-
INDEX `idx_unit_tags_tag_id` (`tag_id`),
118-
INDEX `idx_unit_tags_unit_id` (`unit_id`),
119-
CONSTRAINT `fk_unit_tags_tag` FOREIGN KEY (`tag_id`) REFERENCES `tags` (`id`) ON UPDATE CASCADE ON DELETE CASCADE,
120-
CONSTRAINT `fk_unit_tags_unit` FOREIGN KEY (`unit_id`) REFERENCES `units` (`id`) ON UPDATE CASCADE ON DELETE CASCADE
121-
) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
122-
-- Create "users" table
123-
CREATE TABLE `users` (
124-
`id` varchar(36) NOT NULL,
125-
`subject` varchar(255) NOT NULL,
126-
`email` varchar(255) NOT NULL,
127-
`created_at` datetime(3) NULL,
128-
`updated_at` datetime(3) NULL,
129-
`version` bigint NULL,
130-
PRIMARY KEY (`id`),
131-
UNIQUE INDEX `idx_users_email` (`email`),
132-
UNIQUE INDEX `idx_users_subject` (`subject`)
133-
) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
134-
-- Create "user_roles" table
135-
CREATE TABLE `user_roles` (
136-
`user_id` varchar(36) NOT NULL,
137-
`role_id` varchar(36) NOT NULL,
138-
`org_id` varchar(36) NOT NULL,
139-
PRIMARY KEY (`user_id`, `role_id`, `org_id`),
140-
INDEX `idx_user_roles_org_id` (`org_id`),
141-
INDEX `idx_user_roles_role_id` (`role_id`),
142-
INDEX `idx_user_roles_user_id` (`user_id`),
143-
CONSTRAINT `fk_user_roles_role` FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`) ON UPDATE CASCADE ON DELETE CASCADE,
144-
CONSTRAINT `fk_user_roles_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON UPDATE CASCADE ON DELETE CASCADE
145-
) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci;

0 commit comments

Comments
 (0)