Skip to content

Commit 8dd3cf7

Browse files
committed
Fix non-deterministic output in JSON import
1 parent 17cafb1 commit 8dd3cf7

File tree

4 files changed

+145
-135
lines changed

4 files changed

+145
-135
lines changed

examples/input.roundtrip.sqlon

Lines changed: 38 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,35 @@
1+
@table settings_color_duotone
2+
@cols colors:text,name:text,slug:text
3+
["[\"#02285b\",\"#ffffff\"]","Primary and White","primary-and-white"]
4+
15
@table settings_color_gradients
26
@cols gradient:text,name:text,slug:text
37
["linear-gradient(0deg, #e1236c 0%, #02285b 100%)","Primary to Secondary","primary-secondary"]
48

59
@table settings_color_palette
6-
@cols slug:text,name:text,color:text
7-
["primary","Primary","#02285b"]
8-
["secondary","Secondary","#e1236c"]
9-
["tertiary","Tertiary","#ffa500"]
10-
["black","Black","#000"]
11-
["white","White","#fff"]
12-
["grey","grey","#eee"]
10+
@cols color:text,name:text,slug:text
11+
["#02285b","Primary","primary"]
12+
["#e1236c","Secondary","secondary"]
13+
["#ffa500","Tertiary","tertiary"]
14+
["#000","Black","black"]
15+
["#fff","White","white"]
16+
["#eee","grey","grey"]
1317

14-
@table settings_color_duotone
15-
@cols name:text,slug:text,colors:text
16-
["Primary and White","primary-and-white","[\"#02285b\",\"#ffffff\"]"]
18+
@table settings_shadow_presets
19+
@cols name:text,shadow:text,slug:text
20+
["Faint","0 2px 4px rgb(10, 10, 10, 0.1)","faint"]
21+
["Light","0 0 10px rgb(10, 10, 10, 0.1)","light"]
22+
["Solid","6px 6px 0 currentColor","solid"]
23+
24+
@table settings_spacing_spacingSizes
25+
@cols name:text,size:text,slug:text
26+
["Extra small","0.5rem","filter-xs"]
27+
["Small","1rem","filter-sm"]
28+
["Medium","clamp(1rem, 0.825rem + 0.675vw, 1.5rem)","filter-md"]
29+
["Large","clamp(1.5rem, 1.325rem + 0.675vw, 2rem)","filter-lg"]
30+
["X-Large","clamp(1.5rem, 1.151rem + 1.349vw, 2.5rem)","filter-xl"]
31+
["XXL","clamp(2rem, 1.476rem + 2.024vw, 3.5rem)","filter-xxl"]
32+
["Huge","clamp(2rem, 0.953rem + 4.047vw, 5rem)","filter-huge"]
1733

1834
@table settings_spacing_units
1935
@cols value:text
@@ -24,37 +40,21 @@
2440
["vh"]
2541
["vw"]
2642

27-
@table settings_spacing_spacingSizes
28-
@cols slug:text,name:text,size:text
29-
["filter-xs","Extra small","0.5rem"]
30-
["filter-sm","Small","1rem"]
31-
["filter-md","Medium","clamp(1rem, 0.825rem + 0.675vw, 1.5rem)"]
32-
["filter-lg","Large","clamp(1.5rem, 1.325rem + 0.675vw, 2rem)"]
33-
["filter-xl","X-Large","clamp(1.5rem, 1.151rem + 1.349vw, 2.5rem)"]
34-
["filter-xxl","XXL","clamp(2rem, 1.476rem + 2.024vw, 3.5rem)"]
35-
["filter-huge","Huge","clamp(2rem, 0.953rem + 4.047vw, 5rem)"]
36-
37-
@table templateParts
38-
@cols area:text,name:text,title:text
39-
["footer","cpt-post","News Post - Footer"]
40-
41-
@table settings_shadow_presets
42-
@cols name:text,shadow:text,slug:text
43-
["Faint","0 2px 4px rgb(10, 10, 10, 0.1)","faint"]
44-
["Light","0 0 10px rgb(10, 10, 10, 0.1)","light"]
45-
["Solid","6px 6px 0 currentColor","solid"]
46-
4743
@table settings_typography_fontFamilies
4844
@cols fontFace:text,fontFamily:text,name:text,slug:text
4945
["[{\"fontFamily\":\"Arial\",\"fontStyle\":\"normal\",\"fontWeight\":\"400\",\"src\":[]},{\"fontFamily\":\"Arial\",\"fontStyle\":\"italic\",\"fontWeight\":\"400\",\"src\":[]}]","Arial","Arial","arial-font"]
5046
[null,"Times","Times","times-font"]
5147

5248
@table settings_typography_fontSizes
53-
@cols size:text,slug:text,name:text
54-
["12px","filter-xs","Extra small"]
55-
["16px","filter-sm","Small"]
56-
["20px","filter-base","Base"]
57-
["24px","filter-md","Medium"]
58-
["32px","filter-lg","Large"]
59-
["48px","filter-xl","X-Large"]
60-
["64px","filter-xxl","XXL"]
49+
@cols name:text,size:text,slug:text
50+
["Extra small","12px","filter-xs"]
51+
["Small","16px","filter-sm"]
52+
["Base","20px","filter-base"]
53+
["Medium","24px","filter-md"]
54+
["Large","32px","filter-lg"]
55+
["X-Large","48px","filter-xl"]
56+
["XXL","64px","filter-xxl"]
57+
58+
@table templateParts
59+
@cols area:text,name:text,title:text
60+
["footer","cpt-post","News Post - Footer"]

examples/input.sqlite.sql

Lines changed: 50 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
CREATE TABLE "settings_color_duotone" (
2+
"colors" TEXT,
3+
"name" TEXT,
4+
"slug" TEXT
5+
);
6+
INSERT INTO "settings_color_duotone" ("colors", "name", "slug") VALUES ('["#02285b","#ffffff"]', 'Primary and White', 'primary-and-white');
7+
18
CREATE TABLE "settings_color_gradients" (
29
"gradient" TEXT,
310
"name" TEXT,
@@ -6,23 +13,38 @@ CREATE TABLE "settings_color_gradients" (
613
INSERT INTO "settings_color_gradients" ("gradient", "name", "slug") VALUES ('linear-gradient(0deg, #e1236c 0%, #02285b 100%)', 'Primary to Secondary', 'primary-secondary');
714

815
CREATE TABLE "settings_color_palette" (
9-
"slug" TEXT,
16+
"color" TEXT,
1017
"name" TEXT,
11-
"color" TEXT
18+
"slug" TEXT
1219
);
13-
INSERT INTO "settings_color_palette" ("slug", "name", "color") VALUES ('primary', 'Primary', '#02285b');
14-
INSERT INTO "settings_color_palette" ("slug", "name", "color") VALUES ('secondary', 'Secondary', '#e1236c');
15-
INSERT INTO "settings_color_palette" ("slug", "name", "color") VALUES ('tertiary', 'Tertiary', '#ffa500');
16-
INSERT INTO "settings_color_palette" ("slug", "name", "color") VALUES ('black', 'Black', '#000');
17-
INSERT INTO "settings_color_palette" ("slug", "name", "color") VALUES ('white', 'White', '#fff');
18-
INSERT INTO "settings_color_palette" ("slug", "name", "color") VALUES ('grey', 'grey', '#eee');
20+
INSERT INTO "settings_color_palette" ("color", "name", "slug") VALUES ('#02285b', 'Primary', 'primary');
21+
INSERT INTO "settings_color_palette" ("color", "name", "slug") VALUES ('#e1236c', 'Secondary', 'secondary');
22+
INSERT INTO "settings_color_palette" ("color", "name", "slug") VALUES ('#ffa500', 'Tertiary', 'tertiary');
23+
INSERT INTO "settings_color_palette" ("color", "name", "slug") VALUES ('#000', 'Black', 'black');
24+
INSERT INTO "settings_color_palette" ("color", "name", "slug") VALUES ('#fff', 'White', 'white');
25+
INSERT INTO "settings_color_palette" ("color", "name", "slug") VALUES ('#eee', 'grey', 'grey');
1926

20-
CREATE TABLE "settings_color_duotone" (
27+
CREATE TABLE "settings_shadow_presets" (
28+
"name" TEXT,
29+
"shadow" TEXT,
30+
"slug" TEXT
31+
);
32+
INSERT INTO "settings_shadow_presets" ("name", "shadow", "slug") VALUES ('Faint', '0 2px 4px rgb(10, 10, 10, 0.1)', 'faint');
33+
INSERT INTO "settings_shadow_presets" ("name", "shadow", "slug") VALUES ('Light', '0 0 10px rgb(10, 10, 10, 0.1)', 'light');
34+
INSERT INTO "settings_shadow_presets" ("name", "shadow", "slug") VALUES ('Solid', '6px 6px 0 currentColor', 'solid');
35+
36+
CREATE TABLE "settings_spacing_spacingSizes" (
2137
"name" TEXT,
22-
"slug" TEXT,
23-
"colors" TEXT
38+
"size" TEXT,
39+
"slug" TEXT
2440
);
25-
INSERT INTO "settings_color_duotone" ("name", "slug", "colors") VALUES ('Primary and White', 'primary-and-white', '["#02285b","#ffffff"]');
41+
INSERT INTO "settings_spacing_spacingSizes" ("name", "size", "slug") VALUES ('Extra small', '0.5rem', 'filter-xs');
42+
INSERT INTO "settings_spacing_spacingSizes" ("name", "size", "slug") VALUES ('Small', '1rem', 'filter-sm');
43+
INSERT INTO "settings_spacing_spacingSizes" ("name", "size", "slug") VALUES ('Medium', 'clamp(1rem, 0.825rem + 0.675vw, 1.5rem)', 'filter-md');
44+
INSERT INTO "settings_spacing_spacingSizes" ("name", "size", "slug") VALUES ('Large', 'clamp(1.5rem, 1.325rem + 0.675vw, 2rem)', 'filter-lg');
45+
INSERT INTO "settings_spacing_spacingSizes" ("name", "size", "slug") VALUES ('X-Large', 'clamp(1.5rem, 1.151rem + 1.349vw, 2.5rem)', 'filter-xl');
46+
INSERT INTO "settings_spacing_spacingSizes" ("name", "size", "slug") VALUES ('XXL', 'clamp(2rem, 1.476rem + 2.024vw, 3.5rem)', 'filter-xxl');
47+
INSERT INTO "settings_spacing_spacingSizes" ("name", "size", "slug") VALUES ('Huge', 'clamp(2rem, 0.953rem + 4.047vw, 5rem)', 'filter-huge');
2648

2749
CREATE TABLE "settings_spacing_units" (
2850
"value" TEXT
@@ -34,35 +56,6 @@ INSERT INTO "settings_spacing_units" ("value") VALUES ('rem');
3456
INSERT INTO "settings_spacing_units" ("value") VALUES ('vh');
3557
INSERT INTO "settings_spacing_units" ("value") VALUES ('vw');
3658

37-
CREATE TABLE "settings_spacing_spacingSizes" (
38-
"slug" TEXT,
39-
"name" TEXT,
40-
"size" TEXT
41-
);
42-
INSERT INTO "settings_spacing_spacingSizes" ("slug", "name", "size") VALUES ('filter-xs', 'Extra small', '0.5rem');
43-
INSERT INTO "settings_spacing_spacingSizes" ("slug", "name", "size") VALUES ('filter-sm', 'Small', '1rem');
44-
INSERT INTO "settings_spacing_spacingSizes" ("slug", "name", "size") VALUES ('filter-md', 'Medium', 'clamp(1rem, 0.825rem + 0.675vw, 1.5rem)');
45-
INSERT INTO "settings_spacing_spacingSizes" ("slug", "name", "size") VALUES ('filter-lg', 'Large', 'clamp(1.5rem, 1.325rem + 0.675vw, 2rem)');
46-
INSERT INTO "settings_spacing_spacingSizes" ("slug", "name", "size") VALUES ('filter-xl', 'X-Large', 'clamp(1.5rem, 1.151rem + 1.349vw, 2.5rem)');
47-
INSERT INTO "settings_spacing_spacingSizes" ("slug", "name", "size") VALUES ('filter-xxl', 'XXL', 'clamp(2rem, 1.476rem + 2.024vw, 3.5rem)');
48-
INSERT INTO "settings_spacing_spacingSizes" ("slug", "name", "size") VALUES ('filter-huge', 'Huge', 'clamp(2rem, 0.953rem + 4.047vw, 5rem)');
49-
50-
CREATE TABLE "templateParts" (
51-
"area" TEXT,
52-
"name" TEXT,
53-
"title" TEXT
54-
);
55-
INSERT INTO "templateParts" ("area", "name", "title") VALUES ('footer', 'cpt-post', 'News Post - Footer');
56-
57-
CREATE TABLE "settings_shadow_presets" (
58-
"name" TEXT,
59-
"shadow" TEXT,
60-
"slug" TEXT
61-
);
62-
INSERT INTO "settings_shadow_presets" ("name", "shadow", "slug") VALUES ('Faint', '0 2px 4px rgb(10, 10, 10, 0.1)', 'faint');
63-
INSERT INTO "settings_shadow_presets" ("name", "shadow", "slug") VALUES ('Light', '0 0 10px rgb(10, 10, 10, 0.1)', 'light');
64-
INSERT INTO "settings_shadow_presets" ("name", "shadow", "slug") VALUES ('Solid', '6px 6px 0 currentColor', 'solid');
65-
6659
CREATE TABLE "settings_typography_fontFamilies" (
6760
"fontFace" TEXT,
6861
"fontFamily" TEXT,
@@ -73,14 +66,21 @@ INSERT INTO "settings_typography_fontFamilies" ("fontFace", "fontFamily", "name"
7366
INSERT INTO "settings_typography_fontFamilies" ("fontFace", "fontFamily", "name", "slug") VALUES (NULL, 'Times', 'Times', 'times-font');
7467

7568
CREATE TABLE "settings_typography_fontSizes" (
69+
"name" TEXT,
7670
"size" TEXT,
77-
"slug" TEXT,
78-
"name" TEXT
71+
"slug" TEXT
72+
);
73+
INSERT INTO "settings_typography_fontSizes" ("name", "size", "slug") VALUES ('Extra small', '12px', 'filter-xs');
74+
INSERT INTO "settings_typography_fontSizes" ("name", "size", "slug") VALUES ('Small', '16px', 'filter-sm');
75+
INSERT INTO "settings_typography_fontSizes" ("name", "size", "slug") VALUES ('Base', '20px', 'filter-base');
76+
INSERT INTO "settings_typography_fontSizes" ("name", "size", "slug") VALUES ('Medium', '24px', 'filter-md');
77+
INSERT INTO "settings_typography_fontSizes" ("name", "size", "slug") VALUES ('Large', '32px', 'filter-lg');
78+
INSERT INTO "settings_typography_fontSizes" ("name", "size", "slug") VALUES ('X-Large', '48px', 'filter-xl');
79+
INSERT INTO "settings_typography_fontSizes" ("name", "size", "slug") VALUES ('XXL', '64px', 'filter-xxl');
80+
81+
CREATE TABLE "templateParts" (
82+
"area" TEXT,
83+
"name" TEXT,
84+
"title" TEXT
7985
);
80-
INSERT INTO "settings_typography_fontSizes" ("size", "slug", "name") VALUES ('12px', 'filter-xs', 'Extra small');
81-
INSERT INTO "settings_typography_fontSizes" ("size", "slug", "name") VALUES ('16px', 'filter-sm', 'Small');
82-
INSERT INTO "settings_typography_fontSizes" ("size", "slug", "name") VALUES ('20px', 'filter-base', 'Base');
83-
INSERT INTO "settings_typography_fontSizes" ("size", "slug", "name") VALUES ('24px', 'filter-md', 'Medium');
84-
INSERT INTO "settings_typography_fontSizes" ("size", "slug", "name") VALUES ('32px', 'filter-lg', 'Large');
85-
INSERT INTO "settings_typography_fontSizes" ("size", "slug", "name") VALUES ('48px', 'filter-xl', 'X-Large');
86-
INSERT INTO "settings_typography_fontSizes" ("size", "slug", "name") VALUES ('64px', 'filter-xxl', 'XXL');
86+
INSERT INTO "templateParts" ("area", "name", "title") VALUES ('footer', 'cpt-post', 'News Post - Footer');

examples/input.sqlon

Lines changed: 38 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,35 @@
1+
@table settings_color_duotone
2+
@cols colors:text,name:text,slug:text
3+
["[\"#02285b\",\"#ffffff\"]","Primary and White","primary-and-white"]
4+
15
@table settings_color_gradients
26
@cols gradient:text,name:text,slug:text
37
["linear-gradient(0deg, #e1236c 0%, #02285b 100%)","Primary to Secondary","primary-secondary"]
48

59
@table settings_color_palette
6-
@cols slug:text,name:text,color:text
7-
["primary","Primary","#02285b"]
8-
["secondary","Secondary","#e1236c"]
9-
["tertiary","Tertiary","#ffa500"]
10-
["black","Black","#000"]
11-
["white","White","#fff"]
12-
["grey","grey","#eee"]
10+
@cols color:text,name:text,slug:text
11+
["#02285b","Primary","primary"]
12+
["#e1236c","Secondary","secondary"]
13+
["#ffa500","Tertiary","tertiary"]
14+
["#000","Black","black"]
15+
["#fff","White","white"]
16+
["#eee","grey","grey"]
1317

14-
@table settings_color_duotone
15-
@cols name:text,slug:text,colors:text
16-
["Primary and White","primary-and-white","[\"#02285b\",\"#ffffff\"]"]
18+
@table settings_shadow_presets
19+
@cols name:text,shadow:text,slug:text
20+
["Faint","0 2px 4px rgb(10, 10, 10, 0.1)","faint"]
21+
["Light","0 0 10px rgb(10, 10, 10, 0.1)","light"]
22+
["Solid","6px 6px 0 currentColor","solid"]
23+
24+
@table settings_spacing_spacingSizes
25+
@cols name:text,size:text,slug:text
26+
["Extra small","0.5rem","filter-xs"]
27+
["Small","1rem","filter-sm"]
28+
["Medium","clamp(1rem, 0.825rem + 0.675vw, 1.5rem)","filter-md"]
29+
["Large","clamp(1.5rem, 1.325rem + 0.675vw, 2rem)","filter-lg"]
30+
["X-Large","clamp(1.5rem, 1.151rem + 1.349vw, 2.5rem)","filter-xl"]
31+
["XXL","clamp(2rem, 1.476rem + 2.024vw, 3.5rem)","filter-xxl"]
32+
["Huge","clamp(2rem, 0.953rem + 4.047vw, 5rem)","filter-huge"]
1733

1834
@table settings_spacing_units
1935
@cols value:text
@@ -24,37 +40,21 @@
2440
["vh"]
2541
["vw"]
2642

27-
@table settings_spacing_spacingSizes
28-
@cols slug:text,name:text,size:text
29-
["filter-xs","Extra small","0.5rem"]
30-
["filter-sm","Small","1rem"]
31-
["filter-md","Medium","clamp(1rem, 0.825rem + 0.675vw, 1.5rem)"]
32-
["filter-lg","Large","clamp(1.5rem, 1.325rem + 0.675vw, 2rem)"]
33-
["filter-xl","X-Large","clamp(1.5rem, 1.151rem + 1.349vw, 2.5rem)"]
34-
["filter-xxl","XXL","clamp(2rem, 1.476rem + 2.024vw, 3.5rem)"]
35-
["filter-huge","Huge","clamp(2rem, 0.953rem + 4.047vw, 5rem)"]
36-
37-
@table templateParts
38-
@cols area:text,name:text,title:text
39-
["footer","cpt-post","News Post - Footer"]
40-
41-
@table settings_shadow_presets
42-
@cols name:text,shadow:text,slug:text
43-
["Faint","0 2px 4px rgb(10, 10, 10, 0.1)","faint"]
44-
["Light","0 0 10px rgb(10, 10, 10, 0.1)","light"]
45-
["Solid","6px 6px 0 currentColor","solid"]
46-
4743
@table settings_typography_fontFamilies
4844
@cols fontFace:text,fontFamily:text,name:text,slug:text
4945
["[{\"fontFamily\":\"Arial\",\"fontStyle\":\"normal\",\"fontWeight\":\"400\",\"src\":[]},{\"fontFamily\":\"Arial\",\"fontStyle\":\"italic\",\"fontWeight\":\"400\",\"src\":[]}]","Arial","Arial","arial-font"]
5046
[null,"Times","Times","times-font"]
5147

5248
@table settings_typography_fontSizes
53-
@cols size:text,slug:text,name:text
54-
["12px","filter-xs","Extra small"]
55-
["16px","filter-sm","Small"]
56-
["20px","filter-base","Base"]
57-
["24px","filter-md","Medium"]
58-
["32px","filter-lg","Large"]
59-
["48px","filter-xl","X-Large"]
60-
["64px","filter-xxl","XXL"]
49+
@cols name:text,size:text,slug:text
50+
["Extra small","12px","filter-xs"]
51+
["Small","16px","filter-sm"]
52+
["Base","20px","filter-base"]
53+
["Medium","24px","filter-md"]
54+
["Large","32px","filter-lg"]
55+
["X-Large","48px","filter-xl"]
56+
["XXL","64px","filter-xxl"]
57+
58+
@table templateParts
59+
@cols area:text,name:text,title:text
60+
["footer","cpt-post","News Post - Footer"]

internal/format/json/import.go

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"encoding/json"
55
"fmt"
66
"io"
7+
"sort"
78
"strconv"
89

910
"sqlon/internal/model"
@@ -26,9 +27,22 @@ func Import(r io.Reader) (*model.Database, error) {
2627
return nil, err
2728
}
2829

29-
// Convert map to slice
30+
// Convert map to slice and sort by table name for deterministic output
3031
db.Tables = make([]*model.Table, 0, len(normalizer.tables))
31-
for _, table := range normalizer.tables {
32+
tableNames := make([]string, 0, len(normalizer.tables))
33+
for name := range normalizer.tables {
34+
tableNames = append(tableNames, name)
35+
}
36+
37+
// Sort table names for deterministic order
38+
sort.Strings(tableNames)
39+
40+
for _, name := range tableNames {
41+
table := normalizer.tables[name]
42+
// Sort columns by name for deterministic order
43+
sort.Slice(table.Columns, func(i, j int) bool {
44+
return table.Columns[i].Name < table.Columns[j].Name
45+
})
3246
db.Tables = append(db.Tables, table)
3347
}
3448

@@ -147,16 +161,12 @@ func (n *normalizer) createTableFromArray(tableName string, arr []interface{}) e
147161
func (n *normalizer) inferColumns(obj map[string]interface{}) []model.Column {
148162
columns := make([]model.Column, 0, len(obj))
149163

150-
// Use a map to preserve order while avoiding duplicates
151-
seen := make(map[string]bool)
164+
// Collect all keys and sort for deterministic order
152165
keys := make([]string, 0, len(obj))
153-
154166
for key := range obj {
155-
if !seen[key] {
156-
seen[key] = true
157-
keys = append(keys, key)
158-
}
167+
keys = append(keys, key)
159168
}
169+
sort.Strings(keys)
160170

161171
for _, key := range keys {
162172
val := obj[key]

0 commit comments

Comments
 (0)