historiographer 4.4.2 → 4.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/DEVELOPMENT.md +124 -0
- data/Gemfile +2 -0
- data/README.md +16 -1
- data/Rakefile +68 -0
- data/VERSION +1 -1
- data/bin/console +10 -0
- data/bin/setup +15 -0
- data/bin/test +5 -0
- data/bin/test-all +10 -0
- data/bin/test-rails +5 -0
- data/historiographer.gemspec +52 -14
- data/lib/historiographer/history.rb +72 -37
- data/lib/historiographer.rb +5 -0
- data/spec/combustion_helper.rb +34 -0
- data/spec/db/migrate/20250826000000_create_test_users.rb +8 -0
- data/spec/db/migrate/20250826000001_create_test_user_histories.rb +18 -0
- data/spec/db/migrate/20250826000002_create_test_websites.rb +9 -0
- data/spec/db/migrate/20250826000003_create_test_website_histories.rb +19 -0
- data/spec/db/migrate/20250827000000_create_templates.rb +9 -0
- data/spec/db/migrate/20250827000001_create_template_histories.rb +9 -0
- data/spec/db/migrate/20250827000002_create_websites.rb +9 -0
- data/spec/db/migrate/20250827000003_create_website_histories.rb +9 -0
- data/spec/db/migrate/20250827000004_create_template_files.rb +15 -0
- data/spec/db/migrate/20250827000005_create_template_file_histories.rb +9 -0
- data/spec/db/migrate/20250827000006_create_website_files.rb +15 -0
- data/spec/db/migrate/20250827000007_create_website_file_histories.rb +9 -0
- data/spec/db/migrate/20250827000008_create_code_files_view.rb +62 -0
- data/spec/db/schema.rb +170 -1
- data/spec/examples.txt +71 -0
- data/spec/historiographer_spec.rb +164 -0
- data/spec/integration/historiographer_safe_integration_spec.rb +154 -0
- data/spec/internal/app/models/application_record.rb +5 -0
- data/spec/internal/app/models/deploy.rb +5 -0
- data/spec/internal/app/models/user.rb +4 -0
- data/spec/internal/app/models/website.rb +5 -0
- data/spec/internal/app/models/website_history.rb +7 -0
- data/spec/internal/config/database.yml +9 -0
- data/spec/internal/config/routes.rb +2 -0
- data/spec/internal/db/schema.rb +48 -0
- data/spec/internal/log/development.log +0 -0
- data/spec/internal/log/test.log +1479 -0
- data/spec/models/code_file.rb +16 -0
- data/spec/models/template.rb +6 -0
- data/spec/models/template_file.rb +5 -0
- data/spec/models/template_file_history.rb +3 -0
- data/spec/models/template_history.rb +3 -0
- data/spec/models/test_user.rb +4 -0
- data/spec/models/test_user_history.rb +3 -0
- data/spec/models/test_website.rb +4 -0
- data/spec/models/test_website_history.rb +3 -0
- data/spec/models/website.rb +7 -0
- data/spec/models/website_file.rb +5 -0
- data/spec/models/website_file_history.rb +3 -0
- data/spec/models/website_history.rb +3 -0
- data/spec/rails_integration/historiographer_rails_integration_spec.rb +106 -0
- data/spec/view_backed_model_spec.rb +166 -0
- metadata +55 -13
- data/.document +0 -5
- data/.rspec +0 -1
- data/.ruby-version +0 -1
- data/.standalone_migrations +0 -6
- data/Gemfile.lock +0 -341
- data/historiographer-4.1.12.gem +0 -0
- data/historiographer-4.1.13.gem +0 -0
- data/historiographer-4.1.14.gem +0 -0
- data/historiographer-4.3.0.gem +0 -0
- data/spec/foreign_key_spec.rb +0 -189
@@ -0,0 +1,18 @@
|
|
1
|
+
class CreateTestUserHistories < ActiveRecord::Migration[7.0]
|
2
|
+
def change
|
3
|
+
create_table :test_user_histories do |t|
|
4
|
+
t.integer :test_user_id, null: false
|
5
|
+
t.string :name
|
6
|
+
t.timestamps
|
7
|
+
t.datetime :history_started_at, null: false
|
8
|
+
t.datetime :history_ended_at
|
9
|
+
t.integer :history_user_id
|
10
|
+
t.string :snapshot_id
|
11
|
+
|
12
|
+
t.index :test_user_id
|
13
|
+
t.index :history_started_at
|
14
|
+
t.index :history_ended_at
|
15
|
+
t.index :snapshot_id
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class CreateTestWebsiteHistories < ActiveRecord::Migration[7.0]
|
2
|
+
def change
|
3
|
+
create_table :test_website_histories do |t|
|
4
|
+
t.integer :test_website_id, null: false
|
5
|
+
t.string :name
|
6
|
+
t.integer :user_id
|
7
|
+
t.timestamps
|
8
|
+
t.datetime :history_started_at, null: false
|
9
|
+
t.datetime :history_ended_at
|
10
|
+
t.integer :history_user_id
|
11
|
+
t.string :snapshot_id
|
12
|
+
|
13
|
+
t.index :test_website_id
|
14
|
+
t.index :history_started_at
|
15
|
+
t.index :history_ended_at
|
16
|
+
t.index :snapshot_id
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class CreateTemplateFiles < ActiveRecord::Migration[7.0]
|
2
|
+
def change
|
3
|
+
create_table :template_files do |t|
|
4
|
+
t.references :template, foreign_key: true, null: false
|
5
|
+
t.string :path, null: false
|
6
|
+
t.text :content
|
7
|
+
t.tsvector :content_tsv
|
8
|
+
t.string :shasum
|
9
|
+
t.integer :file_specification_id
|
10
|
+
t.timestamps
|
11
|
+
end
|
12
|
+
|
13
|
+
add_index :template_files, [:template_id, :path], unique: true
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class CreateWebsiteFiles < ActiveRecord::Migration[7.0]
|
2
|
+
def change
|
3
|
+
create_table :website_files do |t|
|
4
|
+
t.references :website, foreign_key: true, null: false
|
5
|
+
t.string :path, null: false
|
6
|
+
t.text :content
|
7
|
+
t.tsvector :content_tsv
|
8
|
+
t.string :shasum
|
9
|
+
t.integer :file_specification_id
|
10
|
+
t.timestamps
|
11
|
+
end
|
12
|
+
|
13
|
+
add_index :website_files, [:website_id, :path], unique: true
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
class CreateCodeFilesView < ActiveRecord::Migration[7.0]
|
2
|
+
def up
|
3
|
+
execute <<-SQL
|
4
|
+
CREATE OR REPLACE VIEW code_files AS
|
5
|
+
WITH merged_files AS (
|
6
|
+
-- Get all website files
|
7
|
+
SELECT
|
8
|
+
wf.website_id,
|
9
|
+
wf.path,
|
10
|
+
wf.content,
|
11
|
+
wf.content_tsv,
|
12
|
+
wf.shasum,
|
13
|
+
wf.file_specification_id,
|
14
|
+
wf.created_at,
|
15
|
+
wf.updated_at,
|
16
|
+
'WebsiteFile' AS source_type,
|
17
|
+
wf.id AS source_id
|
18
|
+
FROM website_files wf
|
19
|
+
|
20
|
+
UNION ALL
|
21
|
+
|
22
|
+
-- Get template files that don't have a matching website file
|
23
|
+
SELECT
|
24
|
+
w.id AS website_id,
|
25
|
+
tf.path,
|
26
|
+
tf.content,
|
27
|
+
tf.content_tsv,
|
28
|
+
tf.shasum,
|
29
|
+
tf.file_specification_id,
|
30
|
+
tf.created_at,
|
31
|
+
tf.updated_at,
|
32
|
+
'TemplateFile' AS source_type,
|
33
|
+
tf.id AS source_id
|
34
|
+
FROM template_files tf
|
35
|
+
INNER JOIN websites w ON w.template_id = tf.template_id
|
36
|
+
WHERE NOT EXISTS (
|
37
|
+
SELECT 1
|
38
|
+
FROM website_files wf2
|
39
|
+
WHERE wf2.website_id = w.id
|
40
|
+
AND wf2.path = tf.path
|
41
|
+
)
|
42
|
+
)
|
43
|
+
SELECT
|
44
|
+
website_id,
|
45
|
+
path,
|
46
|
+
content,
|
47
|
+
content_tsv,
|
48
|
+
shasum,
|
49
|
+
file_specification_id,
|
50
|
+
source_type,
|
51
|
+
source_id,
|
52
|
+
created_at,
|
53
|
+
updated_at
|
54
|
+
FROM merged_files
|
55
|
+
ORDER BY website_id, path;
|
56
|
+
SQL
|
57
|
+
end
|
58
|
+
|
59
|
+
def down
|
60
|
+
execute "DROP VIEW IF EXISTS code_files;"
|
61
|
+
end
|
62
|
+
end
|
data/spec/db/schema.rb
CHANGED
@@ -10,7 +10,7 @@
|
|
10
10
|
#
|
11
11
|
# It's strongly recommended that you check this file into your version control system.
|
12
12
|
|
13
|
-
ActiveRecord::Schema[7.1].define(version:
|
13
|
+
ActiveRecord::Schema[7.1].define(version: 2025_08_27_000008) do
|
14
14
|
# These are extensions that must be enabled in order to support this database
|
15
15
|
enable_extension "plpgsql"
|
16
16
|
|
@@ -299,6 +299,66 @@ ActiveRecord::Schema[7.1].define(version: 2025_08_25_000000) do
|
|
299
299
|
t.index ["live_at"], name: "index_silent_posts_on_live_at"
|
300
300
|
end
|
301
301
|
|
302
|
+
create_table "template_file_histories", force: :cascade do |t|
|
303
|
+
t.integer "template_file_id", null: false
|
304
|
+
t.integer "template_id", null: false
|
305
|
+
t.string "path", null: false
|
306
|
+
t.text "content"
|
307
|
+
t.tsvector "content_tsv"
|
308
|
+
t.string "shasum"
|
309
|
+
t.integer "file_specification_id"
|
310
|
+
t.datetime "created_at", null: false
|
311
|
+
t.datetime "updated_at", null: false
|
312
|
+
t.datetime "history_started_at", null: false
|
313
|
+
t.datetime "history_ended_at"
|
314
|
+
t.integer "history_user_id"
|
315
|
+
t.string "snapshot_id"
|
316
|
+
t.index ["history_ended_at"], name: "index_template_file_histories_on_history_ended_at"
|
317
|
+
t.index ["history_started_at"], name: "index_template_file_histories_on_history_started_at"
|
318
|
+
t.index ["history_user_id"], name: "index_template_file_histories_on_history_user_id"
|
319
|
+
t.index ["snapshot_id"], name: "index_template_file_histories_on_snapshot_id"
|
320
|
+
t.index ["template_file_id"], name: "index_template_file_histories_on_template_file_id"
|
321
|
+
t.index ["template_id", "path"], name: "index_template_file_histories_on_template_id_and_path"
|
322
|
+
t.index ["template_id"], name: "index_template_file_histories_on_template_id"
|
323
|
+
end
|
324
|
+
|
325
|
+
create_table "template_files", force: :cascade do |t|
|
326
|
+
t.bigint "template_id", null: false
|
327
|
+
t.string "path", null: false
|
328
|
+
t.text "content"
|
329
|
+
t.tsvector "content_tsv"
|
330
|
+
t.string "shasum"
|
331
|
+
t.integer "file_specification_id"
|
332
|
+
t.datetime "created_at", null: false
|
333
|
+
t.datetime "updated_at", null: false
|
334
|
+
t.index ["template_id", "path"], name: "index_template_files_on_template_id_and_path", unique: true
|
335
|
+
t.index ["template_id"], name: "index_template_files_on_template_id"
|
336
|
+
end
|
337
|
+
|
338
|
+
create_table "template_histories", force: :cascade do |t|
|
339
|
+
t.integer "template_id", null: false
|
340
|
+
t.string "name", null: false
|
341
|
+
t.text "description"
|
342
|
+
t.datetime "created_at", null: false
|
343
|
+
t.datetime "updated_at", null: false
|
344
|
+
t.datetime "history_started_at", null: false
|
345
|
+
t.datetime "history_ended_at"
|
346
|
+
t.integer "history_user_id"
|
347
|
+
t.string "snapshot_id"
|
348
|
+
t.index ["history_ended_at"], name: "index_template_histories_on_history_ended_at"
|
349
|
+
t.index ["history_started_at"], name: "index_template_histories_on_history_started_at"
|
350
|
+
t.index ["history_user_id"], name: "index_template_histories_on_history_user_id"
|
351
|
+
t.index ["snapshot_id"], name: "index_template_histories_on_snapshot_id"
|
352
|
+
t.index ["template_id"], name: "index_template_histories_on_template_id"
|
353
|
+
end
|
354
|
+
|
355
|
+
create_table "templates", force: :cascade do |t|
|
356
|
+
t.string "name", null: false
|
357
|
+
t.text "description"
|
358
|
+
t.datetime "created_at", null: false
|
359
|
+
t.datetime "updated_at", null: false
|
360
|
+
end
|
361
|
+
|
302
362
|
create_table "test_article_histories", force: :cascade do |t|
|
303
363
|
t.integer "test_article_id", null: false
|
304
364
|
t.string "title"
|
@@ -345,6 +405,50 @@ ActiveRecord::Schema[7.1].define(version: 2025_08_25_000000) do
|
|
345
405
|
t.index ["test_category_id"], name: "index_test_category_histories_on_test_category_id"
|
346
406
|
end
|
347
407
|
|
408
|
+
create_table "test_user_histories", force: :cascade do |t|
|
409
|
+
t.integer "test_user_id", null: false
|
410
|
+
t.string "name"
|
411
|
+
t.datetime "created_at", null: false
|
412
|
+
t.datetime "updated_at", null: false
|
413
|
+
t.datetime "history_started_at", null: false
|
414
|
+
t.datetime "history_ended_at"
|
415
|
+
t.integer "history_user_id"
|
416
|
+
t.string "snapshot_id"
|
417
|
+
t.index ["history_ended_at"], name: "index_test_user_histories_on_history_ended_at"
|
418
|
+
t.index ["history_started_at"], name: "index_test_user_histories_on_history_started_at"
|
419
|
+
t.index ["snapshot_id"], name: "index_test_user_histories_on_snapshot_id"
|
420
|
+
t.index ["test_user_id"], name: "index_test_user_histories_on_test_user_id"
|
421
|
+
end
|
422
|
+
|
423
|
+
create_table "test_users", force: :cascade do |t|
|
424
|
+
t.string "name"
|
425
|
+
t.datetime "created_at", null: false
|
426
|
+
t.datetime "updated_at", null: false
|
427
|
+
end
|
428
|
+
|
429
|
+
create_table "test_website_histories", force: :cascade do |t|
|
430
|
+
t.integer "test_website_id", null: false
|
431
|
+
t.string "name"
|
432
|
+
t.integer "user_id"
|
433
|
+
t.datetime "created_at", null: false
|
434
|
+
t.datetime "updated_at", null: false
|
435
|
+
t.datetime "history_started_at", null: false
|
436
|
+
t.datetime "history_ended_at"
|
437
|
+
t.integer "history_user_id"
|
438
|
+
t.string "snapshot_id"
|
439
|
+
t.index ["history_ended_at"], name: "index_test_website_histories_on_history_ended_at"
|
440
|
+
t.index ["history_started_at"], name: "index_test_website_histories_on_history_started_at"
|
441
|
+
t.index ["snapshot_id"], name: "index_test_website_histories_on_snapshot_id"
|
442
|
+
t.index ["test_website_id"], name: "index_test_website_histories_on_test_website_id"
|
443
|
+
end
|
444
|
+
|
445
|
+
create_table "test_websites", force: :cascade do |t|
|
446
|
+
t.string "name"
|
447
|
+
t.integer "user_id"
|
448
|
+
t.datetime "created_at", null: false
|
449
|
+
t.datetime "updated_at", null: false
|
450
|
+
end
|
451
|
+
|
348
452
|
create_table "thing_with_compound_index_histories", force: :cascade do |t|
|
349
453
|
t.integer "thing_with_compound_index_id", null: false
|
350
454
|
t.string "key"
|
@@ -375,4 +479,69 @@ ActiveRecord::Schema[7.1].define(version: 2025_08_25_000000) do
|
|
375
479
|
t.string "name"
|
376
480
|
end
|
377
481
|
|
482
|
+
create_table "website_file_histories", force: :cascade do |t|
|
483
|
+
t.integer "website_file_id", null: false
|
484
|
+
t.integer "website_id", null: false
|
485
|
+
t.string "path", null: false
|
486
|
+
t.text "content"
|
487
|
+
t.tsvector "content_tsv"
|
488
|
+
t.string "shasum"
|
489
|
+
t.integer "file_specification_id"
|
490
|
+
t.datetime "created_at", null: false
|
491
|
+
t.datetime "updated_at", null: false
|
492
|
+
t.datetime "history_started_at", null: false
|
493
|
+
t.datetime "history_ended_at"
|
494
|
+
t.integer "history_user_id"
|
495
|
+
t.string "snapshot_id"
|
496
|
+
t.index ["history_ended_at"], name: "index_website_file_histories_on_history_ended_at"
|
497
|
+
t.index ["history_started_at"], name: "index_website_file_histories_on_history_started_at"
|
498
|
+
t.index ["history_user_id"], name: "index_website_file_histories_on_history_user_id"
|
499
|
+
t.index ["snapshot_id"], name: "index_website_file_histories_on_snapshot_id"
|
500
|
+
t.index ["website_file_id"], name: "index_website_file_histories_on_website_file_id"
|
501
|
+
t.index ["website_id", "path"], name: "index_website_file_histories_on_website_id_and_path"
|
502
|
+
t.index ["website_id"], name: "index_website_file_histories_on_website_id"
|
503
|
+
end
|
504
|
+
|
505
|
+
create_table "website_files", force: :cascade do |t|
|
506
|
+
t.bigint "website_id", null: false
|
507
|
+
t.string "path", null: false
|
508
|
+
t.text "content"
|
509
|
+
t.tsvector "content_tsv"
|
510
|
+
t.string "shasum"
|
511
|
+
t.integer "file_specification_id"
|
512
|
+
t.datetime "created_at", null: false
|
513
|
+
t.datetime "updated_at", null: false
|
514
|
+
t.index ["website_id", "path"], name: "index_website_files_on_website_id_and_path", unique: true
|
515
|
+
t.index ["website_id"], name: "index_website_files_on_website_id"
|
516
|
+
end
|
517
|
+
|
518
|
+
create_table "website_histories", force: :cascade do |t|
|
519
|
+
t.integer "website_id", null: false
|
520
|
+
t.string "domain", null: false
|
521
|
+
t.integer "template_id"
|
522
|
+
t.datetime "created_at", null: false
|
523
|
+
t.datetime "updated_at", null: false
|
524
|
+
t.datetime "history_started_at", null: false
|
525
|
+
t.datetime "history_ended_at"
|
526
|
+
t.integer "history_user_id"
|
527
|
+
t.string "snapshot_id"
|
528
|
+
t.index ["history_ended_at"], name: "index_website_histories_on_history_ended_at"
|
529
|
+
t.index ["history_started_at"], name: "index_website_histories_on_history_started_at"
|
530
|
+
t.index ["history_user_id"], name: "index_website_histories_on_history_user_id"
|
531
|
+
t.index ["snapshot_id"], name: "index_website_histories_on_snapshot_id"
|
532
|
+
t.index ["template_id"], name: "index_website_histories_on_template_id"
|
533
|
+
t.index ["website_id"], name: "index_website_histories_on_website_id"
|
534
|
+
end
|
535
|
+
|
536
|
+
create_table "websites", force: :cascade do |t|
|
537
|
+
t.string "domain", null: false
|
538
|
+
t.bigint "template_id"
|
539
|
+
t.datetime "created_at", null: false
|
540
|
+
t.datetime "updated_at", null: false
|
541
|
+
t.index ["template_id"], name: "index_websites_on_template_id"
|
542
|
+
end
|
543
|
+
|
544
|
+
add_foreign_key "template_files", "templates"
|
545
|
+
add_foreign_key "website_files", "websites"
|
546
|
+
add_foreign_key "websites", "templates"
|
378
547
|
end
|
data/spec/examples.txt
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
example_id | status | run_time |
|
2
|
+
------------------------------------------------------------------ | ------ | --------------- |
|
3
|
+
./spec/historiographer_spec.rb[1:1:1] | passed | 0.06528 seconds |
|
4
|
+
./spec/historiographer_spec.rb[1:1:2] | passed | 0.06876 seconds |
|
5
|
+
./spec/historiographer_spec.rb[1:1:3] | passed | 0.06676 seconds |
|
6
|
+
./spec/historiographer_spec.rb[1:2:1] | passed | 0.07069 seconds |
|
7
|
+
./spec/historiographer_spec.rb[1:2:2] | passed | 0.05746 seconds |
|
8
|
+
./spec/historiographer_spec.rb[1:2:3:1:1] | passed | 0.09942 seconds |
|
9
|
+
./spec/historiographer_spec.rb[1:2:3:1:2] | passed | 0.09532 seconds |
|
10
|
+
./spec/historiographer_spec.rb[1:2:3:2:1] | passed | 0.0666 seconds |
|
11
|
+
./spec/historiographer_spec.rb[1:2:3:2:2] | passed | 0.09223 seconds |
|
12
|
+
./spec/historiographer_spec.rb[1:2:3:2:3] | passed | 0.16142 seconds |
|
13
|
+
./spec/historiographer_spec.rb[1:2:3:3:1] | passed | 0.09003 seconds |
|
14
|
+
./spec/historiographer_spec.rb[1:2:3:3:2] | passed | 0.0727 seconds |
|
15
|
+
./spec/historiographer_spec.rb[1:2:4:1] | passed | 0.07277 seconds |
|
16
|
+
./spec/historiographer_spec.rb[1:2:4:2] | passed | 0.07295 seconds |
|
17
|
+
./spec/historiographer_spec.rb[1:2:4:3] | passed | 0.06818 seconds |
|
18
|
+
./spec/historiographer_spec.rb[1:2:5:1] | passed | 0.07794 seconds |
|
19
|
+
./spec/historiographer_spec.rb[1:2:5:2] | passed | 0.06574 seconds |
|
20
|
+
./spec/historiographer_spec.rb[1:2:5:3] | passed | 0.07246 seconds |
|
21
|
+
./spec/historiographer_spec.rb[1:2:6] | passed | 0.05671 seconds |
|
22
|
+
./spec/historiographer_spec.rb[1:2:7] | passed | 0.06192 seconds |
|
23
|
+
./spec/historiographer_spec.rb[1:2:8] | passed | 0.06312 seconds |
|
24
|
+
./spec/historiographer_spec.rb[1:3:1] | passed | 0.08252 seconds |
|
25
|
+
./spec/historiographer_spec.rb[1:4:1] | passed | 0.08901 seconds |
|
26
|
+
./spec/historiographer_spec.rb[1:5:1] | passed | 0.06204 seconds |
|
27
|
+
./spec/historiographer_spec.rb[1:5:2] | passed | 0.06017 seconds |
|
28
|
+
./spec/historiographer_spec.rb[1:6:1] | passed | 0.06542 seconds |
|
29
|
+
./spec/historiographer_spec.rb[1:6:2] | passed | 0.07392 seconds |
|
30
|
+
./spec/historiographer_spec.rb[1:7:1] | passed | 0.08007 seconds |
|
31
|
+
./spec/historiographer_spec.rb[1:7:2] | passed | 0.06545 seconds |
|
32
|
+
./spec/historiographer_spec.rb[1:7:3] | passed | 0.06212 seconds |
|
33
|
+
./spec/historiographer_spec.rb[1:7:4] | passed | 0.06293 seconds |
|
34
|
+
./spec/historiographer_spec.rb[1:7:5] | passed | 0.06288 seconds |
|
35
|
+
./spec/historiographer_spec.rb[1:8:1] | passed | 0.062 seconds |
|
36
|
+
./spec/historiographer_spec.rb[1:9:1] | passed | 0.09362 seconds |
|
37
|
+
./spec/historiographer_spec.rb[1:10:1] | passed | 0.05997 seconds |
|
38
|
+
./spec/historiographer_spec.rb[1:11:1] | passed | 0.07282 seconds |
|
39
|
+
./spec/historiographer_spec.rb[1:11:2] | passed | 0.06606 seconds |
|
40
|
+
./spec/historiographer_spec.rb[1:11:3] | passed | 0.06809 seconds |
|
41
|
+
./spec/historiographer_spec.rb[1:11:4] | passed | 0.07018 seconds |
|
42
|
+
./spec/historiographer_spec.rb[1:12:1] | passed | 0.08426 seconds |
|
43
|
+
./spec/historiographer_spec.rb[1:12:2] | passed | 0.06852 seconds |
|
44
|
+
./spec/historiographer_spec.rb[1:12:3] | passed | 0.10016 seconds |
|
45
|
+
./spec/historiographer_spec.rb[1:12:4] | passed | 0.09182 seconds |
|
46
|
+
./spec/historiographer_spec.rb[1:12:5] | passed | 0.08378 seconds |
|
47
|
+
./spec/historiographer_spec.rb[1:12:6] | passed | 0.11921 seconds |
|
48
|
+
./spec/historiographer_spec.rb[1:13:1] | passed | 0.11958 seconds |
|
49
|
+
./spec/historiographer_spec.rb[1:14:1] | passed | 0.05717 seconds |
|
50
|
+
./spec/historiographer_spec.rb[1:14:2] | passed | 0.07805 seconds |
|
51
|
+
./spec/historiographer_spec.rb[1:14:3] | passed | 0.06426 seconds |
|
52
|
+
./spec/historiographer_spec.rb[1:14:4] | passed | 0.06178 seconds |
|
53
|
+
./spec/historiographer_spec.rb[1:15:1] | passed | 0.06755 seconds |
|
54
|
+
./spec/historiographer_spec.rb[1:15:2] | passed | 0.08706 seconds |
|
55
|
+
./spec/historiographer_spec.rb[1:16:1] | passed | 0.06589 seconds |
|
56
|
+
./spec/historiographer_spec.rb[1:16:2] | passed | 0.04756 seconds |
|
57
|
+
./spec/historiographer_spec.rb[1:16:3] | passed | 0.04635 seconds |
|
58
|
+
./spec/historiographer_spec.rb[1:16:4] | passed | 0.07578 seconds |
|
59
|
+
./spec/historiographer_spec.rb[1:17:1:1] | passed | 0.06365 seconds |
|
60
|
+
./spec/historiographer_spec.rb[1:17:1:2] | passed | 0.10348 seconds |
|
61
|
+
./spec/historiographer_spec.rb[1:17:2:1] | passed | 0.06393 seconds |
|
62
|
+
./spec/integration/historiographer_safe_integration_spec.rb[1:1:1] | passed | 0.06664 seconds |
|
63
|
+
./spec/integration/historiographer_safe_integration_spec.rb[1:1:2] | passed | 0.07357 seconds |
|
64
|
+
./spec/integration/historiographer_safe_integration_spec.rb[1:1:3] | passed | 0.05953 seconds |
|
65
|
+
./spec/view_backed_model_spec.rb[1:1:1] | passed | 0.06878 seconds |
|
66
|
+
./spec/view_backed_model_spec.rb[1:1:2] | passed | 0.08949 seconds |
|
67
|
+
./spec/view_backed_model_spec.rb[1:1:3:1] | passed | 0.11878 seconds |
|
68
|
+
./spec/view_backed_model_spec.rb[1:1:3:2] | passed | 0.1122 seconds |
|
69
|
+
./spec/view_backed_model_spec.rb[1:1:3:3] | passed | 0.10204 seconds |
|
70
|
+
./spec/view_backed_model_spec.rb[1:1:3:4] | passed | 0.11072 seconds |
|
71
|
+
./spec/view_backed_model_spec.rb[1:2:1] | passed | 0.07444 seconds |
|
@@ -1071,4 +1071,168 @@ describe Historiographer do
|
|
1071
1071
|
expect { article.snapshot }.to_not raise_error
|
1072
1072
|
end
|
1073
1073
|
end
|
1074
|
+
|
1075
|
+
describe 'Foreign key handling' do
|
1076
|
+
before(:all) do
|
1077
|
+
# Ensure test tables exist
|
1078
|
+
unless ActiveRecord::Base.connection.table_exists?(:test_users)
|
1079
|
+
ActiveRecord::Base.connection.create_table :test_users do |t|
|
1080
|
+
t.string :name
|
1081
|
+
t.timestamps
|
1082
|
+
end
|
1083
|
+
end
|
1084
|
+
|
1085
|
+
unless ActiveRecord::Base.connection.table_exists?(:test_user_histories)
|
1086
|
+
ActiveRecord::Base.connection.create_table :test_user_histories do |t|
|
1087
|
+
t.integer :test_user_id, null: false
|
1088
|
+
t.string :name
|
1089
|
+
t.timestamps
|
1090
|
+
t.datetime :history_started_at, null: false
|
1091
|
+
t.datetime :history_ended_at
|
1092
|
+
t.integer :history_user_id
|
1093
|
+
t.string :snapshot_id
|
1094
|
+
|
1095
|
+
t.index :test_user_id
|
1096
|
+
t.index :history_started_at
|
1097
|
+
t.index :history_ended_at
|
1098
|
+
t.index :snapshot_id
|
1099
|
+
end
|
1100
|
+
end
|
1101
|
+
|
1102
|
+
unless ActiveRecord::Base.connection.table_exists?(:test_websites)
|
1103
|
+
ActiveRecord::Base.connection.create_table :test_websites do |t|
|
1104
|
+
t.string :name
|
1105
|
+
t.integer :user_id
|
1106
|
+
t.timestamps
|
1107
|
+
end
|
1108
|
+
end
|
1109
|
+
|
1110
|
+
unless ActiveRecord::Base.connection.table_exists?(:test_website_histories)
|
1111
|
+
ActiveRecord::Base.connection.create_table :test_website_histories do |t|
|
1112
|
+
t.integer :test_website_id, null: false
|
1113
|
+
t.string :name
|
1114
|
+
t.integer :user_id
|
1115
|
+
t.timestamps
|
1116
|
+
t.datetime :history_started_at, null: false
|
1117
|
+
t.datetime :history_ended_at
|
1118
|
+
t.integer :history_user_id
|
1119
|
+
t.string :snapshot_id
|
1120
|
+
|
1121
|
+
t.index :test_website_id
|
1122
|
+
t.index :history_started_at
|
1123
|
+
t.index :history_ended_at
|
1124
|
+
t.index :snapshot_id
|
1125
|
+
end
|
1126
|
+
end
|
1127
|
+
end
|
1128
|
+
|
1129
|
+
describe 'belongs_to associations on history models' do
|
1130
|
+
it 'does not raise error about wrong column when accessing belongs_to associations' do
|
1131
|
+
# This is the core issue: when a history model has a belongs_to association,
|
1132
|
+
# it should not use the foreign key as the primary key for lookups
|
1133
|
+
|
1134
|
+
# Create a user
|
1135
|
+
user = TestUser.create!(name: 'Test User', history_user_id: 1)
|
1136
|
+
|
1137
|
+
# Create a website belonging to the user
|
1138
|
+
website = TestWebsite.create!(
|
1139
|
+
name: 'Test Website',
|
1140
|
+
user_id: user.id,
|
1141
|
+
history_user_id: 1
|
1142
|
+
)
|
1143
|
+
|
1144
|
+
# Get the website history
|
1145
|
+
website_history = TestWebsiteHistory.last
|
1146
|
+
|
1147
|
+
# The history should have the correct user_id
|
1148
|
+
expect(website_history.user_id).to eq(user.id)
|
1149
|
+
|
1150
|
+
# The belongs_to association should work without errors
|
1151
|
+
# Previously this would fail with "column users.user_id does not exist"
|
1152
|
+
# because it was using primary_key: :user_id instead of the default :id
|
1153
|
+
expect { website_history.user }.not_to raise_error
|
1154
|
+
end
|
1155
|
+
|
1156
|
+
it 'allows direct creation of history records with foreign keys' do
|
1157
|
+
user = TestUser.create!(name: 'Another User', history_user_id: 1)
|
1158
|
+
|
1159
|
+
# Create history attributes like in the original error case
|
1160
|
+
attrs = {
|
1161
|
+
"name" => "test.example",
|
1162
|
+
"user_id" => user.id,
|
1163
|
+
"created_at" => Time.now,
|
1164
|
+
"updated_at" => Time.now,
|
1165
|
+
"test_website_id" => 100,
|
1166
|
+
"history_started_at" => Time.now,
|
1167
|
+
"history_user_id" => 1,
|
1168
|
+
"snapshot_id" => SecureRandom.uuid
|
1169
|
+
}
|
1170
|
+
|
1171
|
+
# This should not raise an error about test_users.user_id not existing
|
1172
|
+
# The original bug was that it would look for test_users.user_id instead of test_users.id
|
1173
|
+
expect { TestWebsiteHistory.create!(attrs) }.not_to raise_error
|
1174
|
+
|
1175
|
+
history = TestWebsiteHistory.last
|
1176
|
+
expect(history.user_id).to eq(user.id)
|
1177
|
+
end
|
1178
|
+
end
|
1179
|
+
|
1180
|
+
describe 'snapshot associations with history models' do
|
1181
|
+
it 'correctly filters associations by snapshot_id when using custom association methods' do
|
1182
|
+
# First create regular history records
|
1183
|
+
user = TestUser.create!(name: 'User One', history_user_id: 1)
|
1184
|
+
website = TestWebsite.create!(
|
1185
|
+
name: 'Website One',
|
1186
|
+
user_id: user.id,
|
1187
|
+
history_user_id: 1
|
1188
|
+
)
|
1189
|
+
|
1190
|
+
# Check that regular histories were created
|
1191
|
+
expect(TestUserHistory.count).to eq(1)
|
1192
|
+
expect(TestWebsiteHistory.count).to eq(1)
|
1193
|
+
|
1194
|
+
# Now create snapshot histories directly (simulating what snapshot would do)
|
1195
|
+
snapshot_id = SecureRandom.uuid
|
1196
|
+
|
1197
|
+
# Create user history with snapshot
|
1198
|
+
user_snapshot = TestUserHistory.create!(
|
1199
|
+
test_user_id: user.id,
|
1200
|
+
name: user.name,
|
1201
|
+
created_at: user.created_at,
|
1202
|
+
updated_at: user.updated_at,
|
1203
|
+
history_started_at: Time.now,
|
1204
|
+
history_user_id: 1,
|
1205
|
+
snapshot_id: snapshot_id
|
1206
|
+
)
|
1207
|
+
|
1208
|
+
# Create website history with snapshot
|
1209
|
+
website_snapshot = TestWebsiteHistory.create!(
|
1210
|
+
test_website_id: website.id,
|
1211
|
+
name: website.name,
|
1212
|
+
user_id: user.id,
|
1213
|
+
created_at: website.created_at,
|
1214
|
+
updated_at: website.updated_at,
|
1215
|
+
history_started_at: Time.now,
|
1216
|
+
history_user_id: 1,
|
1217
|
+
snapshot_id: snapshot_id
|
1218
|
+
)
|
1219
|
+
|
1220
|
+
# Now test that the association filtering works
|
1221
|
+
# The website history's user association should find the user history with the same snapshot_id
|
1222
|
+
user_from_association = website_snapshot.user
|
1223
|
+
|
1224
|
+
# Since user association points to history when snapshots are involved,
|
1225
|
+
# it should return the TestUserHistory with matching snapshot_id
|
1226
|
+
if user_from_association.is_a?(TestUserHistory)
|
1227
|
+
expect(user_from_association.snapshot_id).to eq(snapshot_id)
|
1228
|
+
expect(user_from_association.name).to eq('User One')
|
1229
|
+
else
|
1230
|
+
# If it returns the regular TestUser (non-history), that's also acceptable
|
1231
|
+
# as long as it doesn't error
|
1232
|
+
expect(user_from_association).to be_a(TestUser)
|
1233
|
+
expect(user_from_association.name).to eq('User One')
|
1234
|
+
end
|
1235
|
+
end
|
1236
|
+
end
|
1237
|
+
end
|
1074
1238
|
end
|