Remove partitions from the schema cache
breaking: Embedding, OpenApi and other features related to the schema cache are no longer allowed on partitions.
This commit is contained in:
@@ -122,10 +122,10 @@ spec actualPgVersion = do
|
||||
|
||||
when (actualPgVersion >= pgVersion110) $
|
||||
it "should not throw and return location header for partitioned tables when selecting without PK" $
|
||||
request methodPost "/partitioned_a" [("Prefer", "return=headers-only")]
|
||||
[json|{"id":5,"name":"first"}|] `shouldRespondWith` ""
|
||||
request methodPost "/car_models" [("Prefer", "return=headers-only")]
|
||||
[json|{"name":"Enzo","year":2021}|] `shouldRespondWith` ""
|
||||
{ matchStatus = 201
|
||||
, matchHeaders = [ "Location" <:> "/partitioned_a?id=eq.5&name=eq.first"
|
||||
, matchHeaders = [ "Location" <:> "/car_models?name=eq.Enzo&year=eq.2021"
|
||||
, "Content-Range" <:> "*/*" ]
|
||||
}
|
||||
|
||||
|
||||
@@ -204,11 +204,11 @@ spec actualPgVersion = describe "OpenAPI" $ do
|
||||
it "includes partitioned table properties" $ do
|
||||
r <- simpleBody <$> get "/"
|
||||
|
||||
let method s = key "paths" . key "/partitioned_a" . key s
|
||||
let method s = key "paths" . key "/car_models" . key s
|
||||
getSummary = r ^? method "get" . key "summary"
|
||||
getDescription = r ^? method "get" . key "description"
|
||||
getParameterId = r ^? method "get" . key "parameters" . nth 0 . key "$ref"
|
||||
getParameterName = r ^? method "get" . key "parameters" . nth 1 . key "$ref"
|
||||
getParameterName = r ^? method "get" . key "parameters" . nth 0 . key "$ref"
|
||||
getParameterYear = r ^? method "get" . key "parameters" . nth 1 . key "$ref"
|
||||
getParameterRef = r ^? method "get" . key "parameters" . nth 2 . key "$ref"
|
||||
|
||||
liftIO $ do
|
||||
@@ -217,12 +217,12 @@ spec actualPgVersion = describe "OpenAPI" $ do
|
||||
|
||||
getDescription `shouldBe` Just "A test for partitioned tables"
|
||||
|
||||
getParameterId `shouldBe` Just "#/parameters/rowFilter.partitioned_a.id"
|
||||
getParameterName `shouldBe` Just "#/parameters/rowFilter.car_models.name"
|
||||
|
||||
getParameterName `shouldBe` Just "#/parameters/rowFilter.partitioned_a.name"
|
||||
getParameterYear `shouldBe` Just "#/parameters/rowFilter.car_models.year"
|
||||
|
||||
when (actualPgVersion >= pgVersion110) $
|
||||
getParameterRef `shouldBe` Just "#/parameters/rowFilter.partitioned_a.id_ref"
|
||||
getParameterRef `shouldBe` Just "#/parameters/rowFilter.car_models.car_brand_name"
|
||||
|
||||
describe "Materialized view" $
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ spec actualPgVersion = describe "Allow header" $ do
|
||||
when (actualPgVersion >= pgVersion100) $
|
||||
context "a partitioned table" $ do
|
||||
it "includes read/write verbs for writeable partitioned tables" $ do
|
||||
r <- request methodOptions "/partitioned_a" [] ""
|
||||
r <- request methodOptions "/car_models" [] ""
|
||||
liftIO $
|
||||
simpleHeaders r `shouldSatisfy`
|
||||
matchHeader "Allow" (
|
||||
|
||||
+59
-41
@@ -399,78 +399,96 @@ spec actualPgVersion = do
|
||||
when (actualPgVersion >= pgVersion110) $ do
|
||||
describe "partitioned tables embedding" $ do
|
||||
it "can request a table as parent from a partitioned table" $
|
||||
get "/partitioned_a?id=in.(1,2)&select=id,name,reference_from_partitioned(id)&order=id.asc" `shouldRespondWith`
|
||||
get "/car_models?name=in.(DeLorean,Murcielago)&select=name,year,car_brands(name)&order=name.asc" `shouldRespondWith`
|
||||
[json|
|
||||
[{"id":1,"name":"first","reference_from_partitioned":{"id":1}},
|
||||
{"id":2,"name":"first","reference_from_partitioned":null}] |]
|
||||
[{"name":"DeLorean","year":1981,"car_brands":{"name":"DMC"}},
|
||||
{"name":"Murcielago","year":2001,"car_brands":{"name":"Lamborghini"}}] |]
|
||||
{ matchHeaders = [matchContentTypeJson] }
|
||||
|
||||
it "can request partitioned tables as children from a table" $
|
||||
get "/reference_from_partitioned?select=id,partitioned_a(id,name)&order=id.asc" `shouldRespondWith`
|
||||
get "/car_brands?select=name,car_models(name,year)&order=name.asc&car_models.order=name.asc" `shouldRespondWith`
|
||||
[json|
|
||||
[{"id":1,"partitioned_a":[{"id":1,"name":"first"}]},
|
||||
{"id":2,"partitioned_a":[]}] |]
|
||||
[{"name":"DMC","car_models":[{"name":"DeLorean","year":1981}]},
|
||||
{"name":"Ferrari","car_models":[{"name":"F310-B","year":1997}]},
|
||||
{"name":"Lamborghini","car_models":[{"name":"Murcielago","year":2001},{"name":"Veneno","year":2013}]}] |]
|
||||
{ matchHeaders = [matchContentTypeJson] }
|
||||
|
||||
when (actualPgVersion >= pgVersion121) $ do
|
||||
it "can request tables as children from a partitioned table" $
|
||||
get "/partitioned_a?id=in.(1,2)&select=id,name,reference_to_partitioned(id)&order=id.asc" `shouldRespondWith`
|
||||
get "/car_models?name=in.(DeLorean,F310-B)&select=name,year,car_racers(name)&order=name.asc" `shouldRespondWith`
|
||||
[json|
|
||||
[{"id":1,"name":"first","reference_to_partitioned":[]},
|
||||
{"id":2,"name":"first","reference_to_partitioned":[{"id":2}]}] |]
|
||||
[{"name":"DeLorean","year":1981,"car_racers":[]},
|
||||
{"name":"F310-B","year":1997,"car_racers":[{"name":"Michael Schumacher"}]}] |]
|
||||
{ matchHeaders = [matchContentTypeJson] }
|
||||
|
||||
it "can request a partitioned table as parent from a table" $
|
||||
get "/reference_to_partitioned?select=id,partitioned_a(id,name)&order=id.asc" `shouldRespondWith`
|
||||
get "/car_racers?select=name,car_models(name,year)&order=name.asc" `shouldRespondWith`
|
||||
[json|
|
||||
[{"id":1,"partitioned_a":null},
|
||||
{"id":2,"partitioned_a":{"id":2,"name":"first"}}] |]
|
||||
[{"name":"Alain Prost","car_models":null},
|
||||
{"name":"Michael Schumacher","car_models":{"name":"F310-B","year":1997}}] |]
|
||||
{ matchHeaders = [matchContentTypeJson] }
|
||||
|
||||
it "can request partitioned tables as children from a partitioned table" $
|
||||
get "/partitioned_a?id=in.(1,2,4)&select=id,name,partitioned_b(id,name)&order=id.asc" `shouldRespondWith`
|
||||
get "/car_models?name=in.(DeLorean,Murcielago,Veneno)&select=name,year,car_model_sales(date,quantity)&order=name.asc" `shouldRespondWith`
|
||||
[json|
|
||||
[{"id":1,"name":"first","partitioned_b":[]},
|
||||
{"id":2,"name":"first","partitioned_b":[{"id":2,"name":"first_b"}]},
|
||||
{"id":4,"name":"second","partitioned_b":[{"id":4,"name":"second_b"}]}] |]
|
||||
[{"name":"DeLorean","year":1981,"car_model_sales":[{"date":"2021-01-14","quantity":7},{"date":"2021-01-15","quantity":9}]},
|
||||
{"name":"Murcielago","year":2001,"car_model_sales":[{"date":"2021-02-11","quantity":1},{"date":"2021-02-12","quantity":3}]},
|
||||
{"name":"Veneno","year":2013,"car_model_sales":[]}] |]
|
||||
{ matchHeaders = [matchContentTypeJson] }
|
||||
|
||||
it "can request a partitioned table as parent from a partitioned table" $ do
|
||||
get "/partitioned_b?id=in.(2,4)&select=id,name,partitioned_a(id,name)&order=id.asc" `shouldRespondWith`
|
||||
get "/car_model_sales?date=in.(2021-01-15,2021-02-11)&select=date,quantity,car_models(name,year)&order=date.asc" `shouldRespondWith`
|
||||
[json|
|
||||
[{"id":2,"name":"first_b","partitioned_a":{"id":2,"name":"first"}},
|
||||
{"id":4,"name":"second_b","partitioned_a":{"id":4,"name":"second"}}] |]
|
||||
[{"date":"2021-01-15","quantity":9,"car_models":{"name":"DeLorean","year":1981}},
|
||||
{"date":"2021-02-11","quantity":1,"car_models":{"name":"Murcielago","year":2001}}] |]
|
||||
{ matchHeaders = [matchContentTypeJson] }
|
||||
|
||||
it "can request partitions as children from a partitioned table" $
|
||||
get "/partitioned_a?id=in.(1,2,4)&select=id,name,first_partition_b(id)&order=id.asc" `shouldRespondWith`
|
||||
it "can request many to many relationships between partitioned tables ignoring the intermediate table partitions" $
|
||||
get "/car_models?select=name,year,car_dealers(name,city)&order=name.asc&limit=4" `shouldRespondWith`
|
||||
[json|
|
||||
[{"id":1,"name":"first","first_partition_b":[]},
|
||||
{"id":2,"name":"first","first_partition_b":[{"id":2}]},
|
||||
{"id":4,"name":"second","first_partition_b":[]}] |]
|
||||
{ matchHeaders = [matchContentTypeJson] }
|
||||
[{"name":"DeLorean","year":1981,"car_dealers":[{"name":"Springfield Cars S.A.","city":"Springfield"}]},
|
||||
{"name":"F310-B","year":1997,"car_dealers":[]},
|
||||
{"name":"Murcielago","year":2001,"car_dealers":[{"name":"The Best Deals S.A.","city":"Franklin"}]},
|
||||
{"name":"Veneno","year":2013,"car_dealers":[]}] |]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = [matchContentTypeJson]
|
||||
}
|
||||
|
||||
it "can request a partitioned table as parent from a partition" $
|
||||
get "/first_partition_b?select=id,name,partitioned_a(id,name)&order=id.asc" `shouldRespondWith`
|
||||
it "cannot request partitions as children from a partitioned table" $
|
||||
get "/car_models?id=in.(1,2,4)&select=id,name,car_model_sales_202101(id)&order=id.asc" `shouldRespondWith`
|
||||
[json|
|
||||
[{"id":1,"name":"first_b","partitioned_a":null},
|
||||
{"id":2,"name":"first_b","partitioned_a":{"id":2,"name":"first"}}] |]
|
||||
{ matchHeaders = [matchContentTypeJson] }
|
||||
{"hint":"If a new foreign key between these entities was created in the database, try reloading the schema cache.",
|
||||
"message":"Could not find a relationship between car_models and car_model_sales_202101 in the schema cache"} |]
|
||||
{ matchStatus = 400
|
||||
, matchHeaders = [matchContentTypeJson]
|
||||
}
|
||||
|
||||
it "can request a partition as parent from a partitioned table" $
|
||||
get "/partitioned_b?id=in.(1,3,4)&select=id,name,second_partition_a(id,name)&order=id.asc" `shouldRespondWith`
|
||||
it "cannot request a partitioned table as parent from a partition" $
|
||||
get "/car_model_sales_202101?select=id,name,car_models(id,name)&order=id.asc" `shouldRespondWith`
|
||||
[json|
|
||||
[{"id":1,"name":"first_b","second_partition_a":null},
|
||||
{"id":3,"name":"second_b","second_partition_a":null},
|
||||
{"id":4,"name":"second_b","second_partition_a":{"id":4,"name":"second"}}] |]
|
||||
{ matchHeaders = [matchContentTypeJson] }
|
||||
{"hint":"If a new foreign key between these entities was created in the database, try reloading the schema cache.",
|
||||
"message":"Could not find a relationship between car_model_sales_202101 and car_models in the schema cache"} |]
|
||||
{ matchStatus = 400
|
||||
, matchHeaders = [matchContentTypeJson]
|
||||
}
|
||||
|
||||
it "can request partitioned tables as children from a partition" $
|
||||
get "/second_partition_a?select=id,name,partitioned_b(id,name)&order=id.asc" `shouldRespondWith`
|
||||
it "cannot request a partition as parent from a partitioned table" $
|
||||
get "/car_model_sales?id=in.(1,3,4)&select=id,name,car_models_default(id,name)&order=id.asc" `shouldRespondWith`
|
||||
[json|
|
||||
[{"id":3,"name":"second","partitioned_b":[]},
|
||||
{"id":4,"name":"second","partitioned_b":[{"id":4,"name":"second_b"}]}] |]
|
||||
{ matchHeaders = [matchContentTypeJson] }
|
||||
{"hint":"If a new foreign key between these entities was created in the database, try reloading the schema cache.",
|
||||
"message":"Could not find a relationship between car_model_sales and car_models_default in the schema cache"} |]
|
||||
{ matchStatus = 400
|
||||
, matchHeaders = [matchContentTypeJson]
|
||||
}
|
||||
|
||||
it "cannot request partitioned tables as children from a partition" $
|
||||
get "/car_models_default?select=id,name,car_model_sales(id,name)&order=id.asc" `shouldRespondWith`
|
||||
[json|
|
||||
{"hint":"If a new foreign key between these entities was created in the database, try reloading the schema cache.",
|
||||
"message":"Could not find a relationship between car_models_default and car_model_sales in the schema cache"} |]
|
||||
{ matchStatus = 400
|
||||
, matchHeaders = [matchContentTypeJson]
|
||||
}
|
||||
|
||||
describe "view embedding" $ do
|
||||
it "can detect fk relations through views to tables in the public schema" $
|
||||
|
||||
+18
-18
@@ -47,13 +47,13 @@ spec actualPgVersion =
|
||||
|
||||
when (actualPgVersion >= pgVersion110) $
|
||||
it "INSERTs and UPDATEs rows on composite pk conflict for partitioned tables" $
|
||||
request methodPost "/partitioned_a" [("Prefer", "return=representation"), ("Prefer", "resolution=merge-duplicates")]
|
||||
request methodPost "/car_models" [("Prefer", "return=representation"), ("Prefer", "resolution=merge-duplicates")]
|
||||
[json| [
|
||||
{ "id": 4, "name": "second", "id_ref": 2},
|
||||
{ "id": 6, "name": "first", "id_ref": 1 }
|
||||
{ "name": "Murcielago", "year": 2001, "car_brand_name": null},
|
||||
{ "name": "Roma", "year": 2021, "car_brand_name": "Ferrari" }
|
||||
]|] `shouldRespondWith` [json| [
|
||||
{ "id": 4, "name": "second", "id_ref": 2 },
|
||||
{ "id": 6, "name": "first", "id_ref": 1 }
|
||||
{ "name": "Murcielago", "year": 2001, "car_brand_name": null},
|
||||
{ "name": "Roma", "year": 2021, "car_brand_name": "Ferrari" }
|
||||
]|]
|
||||
{ matchStatus = 201
|
||||
, matchHeaders = ["Preference-Applied" <:> "resolution=merge-duplicates", matchContentTypeJson]
|
||||
@@ -117,12 +117,12 @@ spec actualPgVersion =
|
||||
|
||||
when (actualPgVersion >= pgVersion110) $
|
||||
it "INSERTs and ignores rows on composite pk conflict for partitioned tables" $
|
||||
request methodPost "/partitioned_a" [("Prefer", "return=representation"), ("Prefer", "resolution=ignore-duplicates")]
|
||||
request methodPost "/car_models" [("Prefer", "return=representation"), ("Prefer", "resolution=ignore-duplicates")]
|
||||
[json| [
|
||||
{ "id": 4, "name": "second", "id_ref": 1 },
|
||||
{ "id": 7, "name": "second", "id_ref": 2 }
|
||||
{ "name": "Murcielago", "year": 2001, "car_brand_name": "Ferrari" },
|
||||
{ "name": "Huracán", "year": 2021, "car_brand_name": "Lamborghini" }
|
||||
]|] `shouldRespondWith` [json| [
|
||||
{ "id": 7, "name": "second", "id_ref": 2 }
|
||||
{ "name": "Huracán", "year": 2021, "car_brand_name": "Lamborghini" }
|
||||
]|]
|
||||
{ matchStatus = 201
|
||||
, matchHeaders = ["Preference-Applied" <:> "resolution=ignore-duplicates", matchContentTypeJson]
|
||||
@@ -296,15 +296,15 @@ spec actualPgVersion =
|
||||
when (actualPgVersion >= pgVersion110) $
|
||||
it "succeeds on a partitioned table with composite pk" $ do
|
||||
-- assert that the next request will indeed be an insert
|
||||
get "/partitioned_a?id=eq.8&name=eq.first"
|
||||
get "/car_models?name=eq.Supra&year=eq.2021"
|
||||
`shouldRespondWith`
|
||||
[json|[]|]
|
||||
|
||||
request methodPut "/partitioned_a?id=eq.8&name=eq.first"
|
||||
request methodPut "/car_models?name=eq.Supra&year=eq.2021"
|
||||
[("Prefer", "return=representation")]
|
||||
[json| [ { "id": 8, "name": "first" } ]|]
|
||||
[json| [ { "name": "Supra", "year": 2021 } ]|]
|
||||
`shouldRespondWith`
|
||||
[json| [ { "id": 8, "name": "first", "id_ref": null } ]|]
|
||||
[json| [ { "name": "Supra", "year": 2021, "car_brand_name": null } ]|]
|
||||
|
||||
it "succeeds if the table has only PK cols and no other cols" $ do
|
||||
-- assert that the next request will indeed be an insert
|
||||
@@ -360,15 +360,15 @@ spec actualPgVersion =
|
||||
when (actualPgVersion >= pgVersion110) $
|
||||
it "succeeds on a partitioned table with composite pk" $ do
|
||||
-- assert that the next request will indeed be an update
|
||||
get "/partitioned_a?id=eq.2&name=eq.first"
|
||||
get "/car_models?name=eq.DeLorean&year=eq.1981"
|
||||
`shouldRespondWith`
|
||||
[json| [ { "id": 2, "name": "first", "id_ref": null } ]|]
|
||||
[json| [ { "name": "DeLorean", "year": 1981, "car_brand_name": "DMC" } ]|]
|
||||
|
||||
request methodPut "/partitioned_a?id=eq.2&name=eq.first"
|
||||
request methodPut "/car_models?name=eq.DeLorean&year=eq.1981"
|
||||
[("Prefer", "return=representation")]
|
||||
[json| [ { "id": 2, "name": "first", "id_ref": 1 } ]|]
|
||||
[json| [ { "name": "DeLorean", "year": 1981, "car_brand_name": null } ]|]
|
||||
`shouldRespondWith`
|
||||
[json| [ { "id": 2, "name": "first", "id_ref": 1 } ]|]
|
||||
[json| [ { "name": "DeLorean", "year": 1981, "car_brand_name": null } ]|]
|
||||
|
||||
it "succeeds if the table has only PK cols and no other cols" $ do
|
||||
-- assert that the next request will indeed be an update
|
||||
|
||||
Reference in New Issue
Block a user