diff --git a/README.md b/README.md index 4acfdf9..465fd09 100644 --- a/README.md +++ b/README.md @@ -198,10 +198,13 @@ stmt := SELECT( INNER_JOIN(FilmCategory, FilmCategory.FilmID.EQ(Film.FilmID)). INNER_JOIN(Category, Category.CategoryID.EQ(FilmCategory.CategoryID)), ).WHERE( - Language.Name.EQ(Char(20)("English")). - AND(Category.Name.NOT_EQ(Text("Action"))). - AND(Film.Length.GT(Int32(180))). - AND(Film.Rating.NOT_EQ(enum.MpaaRating.R)), + AND( + Language.Name.EQ(Char(20)("English")), // string columns Language.Name and Category.Name can be compared only with string expression + Category.Name.NOT_EQ(Text("Action")), + Film.Length.GT(Int32(180)), // Film.Length is integer column and can be compared only with integer expression + Film.Rating.NOT_EQ(enum.MpaaRating.R), + String("Trailers").EQ(ANY(Film.SpecialFeatures)), // type safety is also enforced on array element types + ), ).ORDER_BY( Actor.ActorID.ASC(), Film.FilmID.ASC(), @@ -212,7 +215,8 @@ stmt := SELECT( Note that every column has a type. String columns, such as `Language.Name` and `Category.Name` can only be compared with string columns and expressions. Similarity, `Actor.ActorID`, `FilmActor.ActorID`, `Film.Length` are integer columns -and can only be compared with integer columns and expressions. +and can only be compared with integer columns and expressions. The same type safety rules apply to arrays and their +element types. __How to Get a Parametrized SQL Query from the Statement?__ ```go @@ -244,7 +248,6 @@ SELECT actor.actor_id AS "actor.actor_id", film.fulltext AS "film.fulltext", language.language_id AS "language.language_id", language.name AS "language.name", - language.last_update AS "language.last_update", category.category_id AS "category.category_id", category.name AS "category.name", category.last_update AS "category.last_update" @@ -254,11 +257,18 @@ FROM dvds.actor INNER JOIN dvds.language ON (language.language_id = film.language_id) INNER JOIN dvds.film_category ON (film_category.film_id = film.film_id) INNER JOIN dvds.category ON (category.category_id = film_category.category_id) -WHERE (((language.name = $1::char(20)) AND (category.name != $2::text)) AND (film.length > $3)) AND (film.rating != 'R') +WHERE ( + (language.name = $1::char(20)) + AND (category.name != $2::text) + AND (film.length > $3::integer) + AND (film.rating != 'R') + AND ($4::text = ANY(film.special_features)) + ) ORDER BY actor.actor_id ASC, film.film_id ASC; ``` + ```sh -[English Action 180] +[English Action 180 Trailers] ``` @@ -277,35 +287,40 @@ debugSql - this query string can be copy-pasted into sql editor and executed. ```sql SELECT actor.actor_id AS "actor.actor_id", - actor.first_name AS "actor.first_name", - actor.last_name AS "actor.last_name", - actor.last_update AS "actor.last_update", - film.film_id AS "film.film_id", - film.title AS "film.title", - film.description AS "film.description", - film.release_year AS "film.release_year", - film.language_id AS "film.language_id", - film.rental_duration AS "film.rental_duration", - film.rental_rate AS "film.rental_rate", - film.length AS "film.length", - film.replacement_cost AS "film.replacement_cost", - film.rating AS "film.rating", - film.last_update AS "film.last_update", - film.special_features AS "film.special_features", - film.fulltext AS "film.fulltext", - language.language_id AS "language.language_id", - language.name AS "language.name", - language.last_update AS "language.last_update", - category.category_id AS "category.category_id", - category.name AS "category.name", - category.last_update AS "category.last_update" + actor.first_name AS "actor.first_name", + actor.last_name AS "actor.last_name", + actor.last_update AS "actor.last_update", + film.film_id AS "film.film_id", + film.title AS "film.title", + film.description AS "film.description", + film.release_year AS "film.release_year", + film.language_id AS "film.language_id", + film.rental_duration AS "film.rental_duration", + film.rental_rate AS "film.rental_rate", + film.length AS "film.length", + film.replacement_cost AS "film.replacement_cost", + film.rating AS "film.rating", + film.last_update AS "film.last_update", + film.special_features AS "film.special_features", + film.fulltext AS "film.fulltext", + language.language_id AS "language.language_id", + language.name AS "language.name", + category.category_id AS "category.category_id", + category.name AS "category.name", + category.last_update AS "category.last_update" FROM dvds.actor - INNER JOIN dvds.film_actor ON (actor.actor_id = film_actor.actor_id) - INNER JOIN dvds.film ON (film.film_id = film_actor.film_id) - INNER JOIN dvds.language ON (language.language_id = film.language_id) - INNER JOIN dvds.film_category ON (film_category.film_id = film.film_id) - INNER JOIN dvds.category ON (category.category_id = film_category.category_id) -WHERE (((language.name = 'English'::char(20)) AND (category.name != 'Action'::text)) AND (film.length > 180)) AND (film.rating != 'R') + INNER JOIN dvds.film_actor ON (actor.actor_id = film_actor.actor_id) + INNER JOIN dvds.film ON (film.film_id = film_actor.film_id) + INNER JOIN dvds.language ON (language.language_id = film.language_id) + INNER JOIN dvds.film_category ON (film_category.film_id = film.film_id) + INNER JOIN dvds.category ON (category.category_id = film_category.category_id) +WHERE ( + (language.name = 'English'::char(20)) + AND (category.name != 'Action'::text) + AND (film.length > 180::integer) + AND (film.rating != 'R') + AND ('Trailers'::text = ANY(film.special_features)) + ) ORDER BY actor.actor_id ASC, film.film_id ASC; ``` @@ -355,8 +370,8 @@ __And that's it.__ The `dest` variable now contains a list of all actors (each with a list of films they acted in). Each film includes information about its language and a list of categories it belongs to. This list is filtered to include only -films longer than 180 minutes, where the film language is 'English', and -the film category is not 'Action'. +films longer than 180 minutes, where the film language is 'English', +the film category is not 'Action' and 'Trailers' are one of the film's special features. > [!Tip] > It is recommended to enable **Strict Scan** on application startup, especially when destination contains @@ -370,82 +385,88 @@ fmt.Println(string(jsonText)) ```js [ - { - "ActorID": 1, - "FirstName": "Penelope", - "LastName": "Guiness", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 499, - "Title": "King Evolution", - "Description": "A Action-Packed Tale of a Boy And a Lumberjack who must Chase a Madman in A Baloon", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 3, - "RentalRate": 4.99, - "Length": 184, - "ReplacementCost": 24.99, - "Rating": "NC-17", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Deleted Scenes\",\"Behind the Scenes\"}", - "Fulltext": "'action':5 'action-pack':4 'baloon':21 'boy':10 'chase':16 'evolut':2 'king':1 'lumberjack':13 'madman':18 'must':15 'pack':6 'tale':7", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 8, - "Name": "Family", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, - { - "ActorID": 3, - "FirstName": "Ed", - "LastName": "Chase", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 996, - "Title": "Young Language", - "Description": "A Unbelieveable Yarn of a Boat And a Database Administrator who must Meet a Boy in The First Manned Space Station", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 0.99, - "Length": 183, - "ReplacementCost": 9.99, - "Rating": "G", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Behind the Scenes\"}", - "Fulltext": "'administr':12 'boat':8 'boy':17 'databas':11 'first':20 'languag':2 'man':21 'meet':15 'must':14 'space':22 'station':23 'unbeliev':4 'yarn':5 'young':1", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 6, - "Name": "Documentary", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, - //...(125 more items) + { + "ActorID": 1, + "FirstName": "Penelope", + "LastName": "Guiness", + "LastUpdate": "2013-05-26T14:47:57.62Z", + "Films": [ + { + "FilmID": 499, + "Title": "King Evolution", + "Description": "A Action-Packed Tale of a Boy And a Lumberjack who must Chase a Madman in A Baloon", + "ReleaseYear": 2006, + "LanguageID": 1, + "RentalDuration": 3, + "RentalRate": 4.99, + "Length": 184, + "ReplacementCost": 24.99, + "Rating": "NC-17", + "LastUpdate": "2013-05-26T14:50:58.951Z", + "SpecialFeatures": [ + "Trailers", + "Deleted Scenes", + "Behind the Scenes" + ], + "Fulltext": "'action':5 'action-pack':4 'baloon':21 'boy':10 'chase':16 'evolut':2 'king':1 'lumberjack':13 'madman':18 'must':15 'pack':6 'tale':7", + "Language": { + "LanguageID": 1, + "Name": "English ", + "LastUpdate": "0001-01-01T00:00:00Z" + }, + "Categories": [ + { + "CategoryID": 8, + "Name": "Family", + "LastUpdate": "2006-02-15T09:46:27Z" + } + ] + } + ] + }, + { + "ActorID": 3, + "FirstName": "Ed", + "LastName": "Chase", + "LastUpdate": "2013-05-26T14:47:57.62Z", + "Films": [ + { + "FilmID": 996, + "Title": "Young Language", + "Description": "A Unbelieveable Yarn of a Boat And a Database Administrator who must Meet a Boy in The First Manned Space Station", + "ReleaseYear": 2006, + "LanguageID": 1, + "RentalDuration": 6, + "RentalRate": 0.99, + "Length": 183, + "ReplacementCost": 9.99, + "Rating": "G", + "LastUpdate": "2013-05-26T14:50:58.951Z", + "SpecialFeatures": [ + "Trailers", + "Behind the Scenes" + ], + "Fulltext": "'administr':12 'boat':8 'boy':17 'databas':11 'first':20 'languag':2 'man':21 'meet':15 'must':14 'space':22 'station':23 'unbeliev':4 'yarn':5 'young':1", + "Language": { + "LanguageID": 1, + "Name": "English ", + "LastUpdate": "0001-01-01T00:00:00Z" + }, + "Categories": [ + { + "CategoryID": 6, + "Name": "Documentary", + "LastUpdate": "2006-02-15T09:46:27Z" + } + ] + } + ] + }, + //...(125 more items) ] ``` -What if, we also want to have list of films per category and actors per category, where films are longer than 180 minutes, film language is 'English' -and film category is not 'Action'. +What if, we also want to have a list of films per category and actors per category, with the same search conditions. In that case we can reuse above statement `stmt`, and just change our destination: ```go @@ -464,88 +485,71 @@ handleError(err) ```js [ - { - "CategoryID": 8, - "Name": "Family", - "LastUpdate": "2006-02-15T09:46:27Z", - "Films": [ - { - "FilmID": 499, - "Title": "King Evolution", - "Description": "A Action-Packed Tale of a Boy And a Lumberjack who must Chase a Madman in A Baloon", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 3, - "RentalRate": 4.99, - "Length": 184, - "ReplacementCost": 24.99, - "Rating": "NC-17", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Deleted Scenes\",\"Behind the Scenes\"}", - "Fulltext": "'action':5 'action-pack':4 'baloon':21 'boy':10 'chase':16 'evolut':2 'king':1 'lumberjack':13 'madman':18 'must':15 'pack':6 'tale':7" - }, - { - "FilmID": 50, - "Title": "Baked Cleopatra", - "Description": "A Stunning Drama of a Forensic Psychologist And a Husband who must Overcome a Waitress in A Monastery", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 3, - "RentalRate": 2.99, - "Length": 182, - "ReplacementCost": 20.99, - "Rating": "G", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries,\"Behind the Scenes\"}", - "Fulltext": "'bake':1 'cleopatra':2 'drama':5 'forens':8 'husband':12 'monasteri':20 'must':14 'overcom':15 'psychologist':9 'stun':4 'waitress':17" - } - ], - "Actors": [ - { - "ActorID": 1, - "FirstName": "Penelope", - "LastName": "Guiness", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 20, - "FirstName": "Lucille", - "LastName": "Tracy", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 36, - "FirstName": "Burt", - "LastName": "Dukakis", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 70, - "FirstName": "Michelle", - "LastName": "Mcconaughey", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 118, - "FirstName": "Cuba", - "LastName": "Allen", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 187, - "FirstName": "Renee", - "LastName": "Ball", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 198, - "FirstName": "Mary", - "LastName": "Keitel", - "LastUpdate": "2013-05-26T14:47:57.62Z" - } - ] - }, - //... + { + "CategoryID": 8, + "Name": "Family", + "LastUpdate": "2006-02-15T09:46:27Z", + "Films": [ + { + "FilmID": 499, + "Title": "King Evolution", + "Description": "A Action-Packed Tale of a Boy And a Lumberjack who must Chase a Madman in A Baloon", + "ReleaseYear": 2006, + "LanguageID": 1, + "RentalDuration": 3, + "RentalRate": 4.99, + "Length": 184, + "ReplacementCost": 24.99, + "Rating": "NC-17", + "LastUpdate": "2013-05-26T14:50:58.951Z", + "SpecialFeatures": [ + "Trailers", + "Deleted Scenes", + "Behind the Scenes" + ], + "Fulltext": "'action':5 'action-pack':4 'baloon':21 'boy':10 'chase':16 'evolut':2 'king':1 'lumberjack':13 'madman':18 'must':15 'pack':6 'tale':7" + } + ], + "Actors": [ + { + "ActorID": 1, + "FirstName": "Penelope", + "LastName": "Guiness", + "LastUpdate": "2013-05-26T14:47:57.62Z" + }, + { + "ActorID": 20, + "FirstName": "Lucille", + "LastName": "Tracy", + "LastUpdate": "2013-05-26T14:47:57.62Z" + }, + { + "ActorID": 36, + "FirstName": "Burt", + "LastName": "Dukakis", + "LastUpdate": "2013-05-26T14:47:57.62Z" + }, + { + "ActorID": 118, + "FirstName": "Cuba", + "LastName": "Allen", + "LastUpdate": "2013-05-26T14:47:57.62Z" + }, + { + "ActorID": 187, + "FirstName": "Renee", + "LastName": "Ball", + "LastUpdate": "2013-05-26T14:47:57.62Z" + }, + { + "ActorID": 198, + "FirstName": "Mary", + "LastName": "Keitel", + "LastUpdate": "2013-05-26T14:47:57.62Z" + } + ] + }, + // ... ] ``` diff --git a/examples/quick-start/.gen/jetdb/dvds/model/film.go b/examples/quick-start/.gen/jetdb/dvds/model/film.go index 04a1ae5..79c39df 100644 --- a/examples/quick-start/.gen/jetdb/dvds/model/film.go +++ b/examples/quick-start/.gen/jetdb/dvds/model/film.go @@ -8,6 +8,7 @@ package model import ( + "github.com/lib/pq" "time" ) @@ -23,6 +24,6 @@ type Film struct { ReplacementCost float64 Rating *MpaaRating LastUpdate time.Time - SpecialFeatures *string + SpecialFeatures *pq.StringArray Fulltext string } diff --git a/examples/quick-start/.gen/jetdb/dvds/model/mpaa_rating.go b/examples/quick-start/.gen/jetdb/dvds/model/mpaa_rating.go index bdb613a..77cffb1 100644 --- a/examples/quick-start/.gen/jetdb/dvds/model/mpaa_rating.go +++ b/examples/quick-start/.gen/jetdb/dvds/model/mpaa_rating.go @@ -19,6 +19,14 @@ const ( MpaaRating_Nc17 MpaaRating = "NC-17" ) +var MpaaRatingAllValues = []MpaaRating{ + MpaaRating_G, + MpaaRating_Pg, + MpaaRating_Pg13, + MpaaRating_R, + MpaaRating_Nc17, +} + func (e *MpaaRating) Scan(value interface{}) error { var enumValue string switch val := value.(type) { diff --git a/examples/quick-start/.gen/jetdb/dvds/table/actor.go b/examples/quick-start/.gen/jetdb/dvds/table/actor.go index 37e0f85..a35fafe 100644 --- a/examples/quick-start/.gen/jetdb/dvds/table/actor.go +++ b/examples/quick-start/.gen/jetdb/dvds/table/actor.go @@ -16,7 +16,7 @@ var Actor = newActorTable("dvds", "actor", "") type actorTable struct { postgres.Table - //Columns + // Columns ActorID postgres.ColumnInteger FirstName postgres.ColumnString LastName postgres.ColumnString @@ -24,6 +24,7 @@ type actorTable struct { AllColumns postgres.ColumnList MutableColumns postgres.ColumnList + DefaultColumns postgres.ColumnList } type ActorTable struct { @@ -67,6 +68,7 @@ func newActorTableImpl(schemaName, tableName, alias string) actorTable { LastUpdateColumn = postgres.TimestampColumn("last_update") allColumns = postgres.ColumnList{ActorIDColumn, FirstNameColumn, LastNameColumn, LastUpdateColumn} mutableColumns = postgres.ColumnList{FirstNameColumn, LastNameColumn, LastUpdateColumn} + defaultColumns = postgres.ColumnList{ActorIDColumn} ) return actorTable{ @@ -80,5 +82,6 @@ func newActorTableImpl(schemaName, tableName, alias string) actorTable { AllColumns: allColumns, MutableColumns: mutableColumns, + DefaultColumns: defaultColumns, } } diff --git a/examples/quick-start/.gen/jetdb/dvds/table/category.go b/examples/quick-start/.gen/jetdb/dvds/table/category.go index 87beb46..b277b97 100644 --- a/examples/quick-start/.gen/jetdb/dvds/table/category.go +++ b/examples/quick-start/.gen/jetdb/dvds/table/category.go @@ -16,13 +16,14 @@ var Category = newCategoryTable("dvds", "category", "") type categoryTable struct { postgres.Table - //Columns + // Columns CategoryID postgres.ColumnInteger Name postgres.ColumnString LastUpdate postgres.ColumnTimestamp AllColumns postgres.ColumnList MutableColumns postgres.ColumnList + DefaultColumns postgres.ColumnList } type CategoryTable struct { @@ -65,6 +66,7 @@ func newCategoryTableImpl(schemaName, tableName, alias string) categoryTable { LastUpdateColumn = postgres.TimestampColumn("last_update") allColumns = postgres.ColumnList{CategoryIDColumn, NameColumn, LastUpdateColumn} mutableColumns = postgres.ColumnList{NameColumn, LastUpdateColumn} + defaultColumns = postgres.ColumnList{CategoryIDColumn, LastUpdateColumn} ) return categoryTable{ @@ -77,5 +79,6 @@ func newCategoryTableImpl(schemaName, tableName, alias string) categoryTable { AllColumns: allColumns, MutableColumns: mutableColumns, + DefaultColumns: defaultColumns, } } diff --git a/examples/quick-start/.gen/jetdb/dvds/table/film.go b/examples/quick-start/.gen/jetdb/dvds/table/film.go index 4636408..ce22348 100644 --- a/examples/quick-start/.gen/jetdb/dvds/table/film.go +++ b/examples/quick-start/.gen/jetdb/dvds/table/film.go @@ -16,7 +16,7 @@ var Film = newFilmTable("dvds", "film", "") type filmTable struct { postgres.Table - //Columns + // Columns FilmID postgres.ColumnInteger Title postgres.ColumnString Description postgres.ColumnString @@ -28,11 +28,12 @@ type filmTable struct { ReplacementCost postgres.ColumnFloat Rating postgres.ColumnString LastUpdate postgres.ColumnTimestamp - SpecialFeatures postgres.ColumnString + SpecialFeatures postgres.ColumnStringArray Fulltext postgres.ColumnString AllColumns postgres.ColumnList MutableColumns postgres.ColumnList + DefaultColumns postgres.ColumnList } type FilmTable struct { @@ -81,10 +82,11 @@ func newFilmTableImpl(schemaName, tableName, alias string) filmTable { ReplacementCostColumn = postgres.FloatColumn("replacement_cost") RatingColumn = postgres.StringColumn("rating") LastUpdateColumn = postgres.TimestampColumn("last_update") - SpecialFeaturesColumn = postgres.StringColumn("special_features") + SpecialFeaturesColumn = postgres.StringArrayColumn("special_features") FulltextColumn = postgres.StringColumn("fulltext") allColumns = postgres.ColumnList{FilmIDColumn, TitleColumn, DescriptionColumn, ReleaseYearColumn, LanguageIDColumn, RentalDurationColumn, RentalRateColumn, LengthColumn, ReplacementCostColumn, RatingColumn, LastUpdateColumn, SpecialFeaturesColumn, FulltextColumn} mutableColumns = postgres.ColumnList{TitleColumn, DescriptionColumn, ReleaseYearColumn, LanguageIDColumn, RentalDurationColumn, RentalRateColumn, LengthColumn, ReplacementCostColumn, RatingColumn, LastUpdateColumn, SpecialFeaturesColumn, FulltextColumn} + defaultColumns = postgres.ColumnList{FilmIDColumn, RentalDurationColumn, RentalRateColumn, ReplacementCostColumn, RatingColumn, LastUpdateColumn} ) return filmTable{ @@ -107,5 +109,6 @@ func newFilmTableImpl(schemaName, tableName, alias string) filmTable { AllColumns: allColumns, MutableColumns: mutableColumns, + DefaultColumns: defaultColumns, } } diff --git a/examples/quick-start/.gen/jetdb/dvds/table/film_actor.go b/examples/quick-start/.gen/jetdb/dvds/table/film_actor.go index 7fe60c3..7d8d560 100644 --- a/examples/quick-start/.gen/jetdb/dvds/table/film_actor.go +++ b/examples/quick-start/.gen/jetdb/dvds/table/film_actor.go @@ -16,13 +16,14 @@ var FilmActor = newFilmActorTable("dvds", "film_actor", "") type filmActorTable struct { postgres.Table - //Columns + // Columns ActorID postgres.ColumnInteger FilmID postgres.ColumnInteger LastUpdate postgres.ColumnTimestamp AllColumns postgres.ColumnList MutableColumns postgres.ColumnList + DefaultColumns postgres.ColumnList } type FilmActorTable struct { @@ -65,6 +66,7 @@ func newFilmActorTableImpl(schemaName, tableName, alias string) filmActorTable { LastUpdateColumn = postgres.TimestampColumn("last_update") allColumns = postgres.ColumnList{ActorIDColumn, FilmIDColumn, LastUpdateColumn} mutableColumns = postgres.ColumnList{LastUpdateColumn} + defaultColumns = postgres.ColumnList{LastUpdateColumn} ) return filmActorTable{ @@ -77,5 +79,6 @@ func newFilmActorTableImpl(schemaName, tableName, alias string) filmActorTable { AllColumns: allColumns, MutableColumns: mutableColumns, + DefaultColumns: defaultColumns, } } diff --git a/examples/quick-start/.gen/jetdb/dvds/table/film_category.go b/examples/quick-start/.gen/jetdb/dvds/table/film_category.go index fb3bfb6..08a469e 100644 --- a/examples/quick-start/.gen/jetdb/dvds/table/film_category.go +++ b/examples/quick-start/.gen/jetdb/dvds/table/film_category.go @@ -16,13 +16,14 @@ var FilmCategory = newFilmCategoryTable("dvds", "film_category", "") type filmCategoryTable struct { postgres.Table - //Columns + // Columns FilmID postgres.ColumnInteger CategoryID postgres.ColumnInteger LastUpdate postgres.ColumnTimestamp AllColumns postgres.ColumnList MutableColumns postgres.ColumnList + DefaultColumns postgres.ColumnList } type FilmCategoryTable struct { @@ -65,6 +66,7 @@ func newFilmCategoryTableImpl(schemaName, tableName, alias string) filmCategoryT LastUpdateColumn = postgres.TimestampColumn("last_update") allColumns = postgres.ColumnList{FilmIDColumn, CategoryIDColumn, LastUpdateColumn} mutableColumns = postgres.ColumnList{LastUpdateColumn} + defaultColumns = postgres.ColumnList{LastUpdateColumn} ) return filmCategoryTable{ @@ -77,5 +79,6 @@ func newFilmCategoryTableImpl(schemaName, tableName, alias string) filmCategoryT AllColumns: allColumns, MutableColumns: mutableColumns, + DefaultColumns: defaultColumns, } } diff --git a/examples/quick-start/.gen/jetdb/dvds/table/language.go b/examples/quick-start/.gen/jetdb/dvds/table/language.go index 24f037d..ba5492d 100644 --- a/examples/quick-start/.gen/jetdb/dvds/table/language.go +++ b/examples/quick-start/.gen/jetdb/dvds/table/language.go @@ -16,13 +16,14 @@ var Language = newLanguageTable("dvds", "language", "") type languageTable struct { postgres.Table - //Columns + // Columns LanguageID postgres.ColumnInteger Name postgres.ColumnString LastUpdate postgres.ColumnTimestamp AllColumns postgres.ColumnList MutableColumns postgres.ColumnList + DefaultColumns postgres.ColumnList } type LanguageTable struct { @@ -65,6 +66,7 @@ func newLanguageTableImpl(schemaName, tableName, alias string) languageTable { LastUpdateColumn = postgres.TimestampColumn("last_update") allColumns = postgres.ColumnList{LanguageIDColumn, NameColumn, LastUpdateColumn} mutableColumns = postgres.ColumnList{NameColumn, LastUpdateColumn} + defaultColumns = postgres.ColumnList{LanguageIDColumn, LastUpdateColumn} ) return languageTable{ @@ -77,5 +79,6 @@ func newLanguageTableImpl(schemaName, tableName, alias string) languageTable { AllColumns: allColumns, MutableColumns: mutableColumns, + DefaultColumns: defaultColumns, } } diff --git a/examples/quick-start/.gen/jetdb/dvds/view/actor_info.go b/examples/quick-start/.gen/jetdb/dvds/view/actor_info.go index 23f81aa..813548b 100644 --- a/examples/quick-start/.gen/jetdb/dvds/view/actor_info.go +++ b/examples/quick-start/.gen/jetdb/dvds/view/actor_info.go @@ -16,7 +16,7 @@ var ActorInfo = newActorInfoTable("dvds", "actor_info", "") type actorInfoTable struct { postgres.Table - //Columns + // Columns ActorID postgres.ColumnInteger FirstName postgres.ColumnString LastName postgres.ColumnString @@ -24,6 +24,7 @@ type actorInfoTable struct { AllColumns postgres.ColumnList MutableColumns postgres.ColumnList + DefaultColumns postgres.ColumnList } type ActorInfoTable struct { @@ -67,6 +68,7 @@ func newActorInfoTableImpl(schemaName, tableName, alias string) actorInfoTable { FilmInfoColumn = postgres.StringColumn("film_info") allColumns = postgres.ColumnList{ActorIDColumn, FirstNameColumn, LastNameColumn, FilmInfoColumn} mutableColumns = postgres.ColumnList{ActorIDColumn, FirstNameColumn, LastNameColumn, FilmInfoColumn} + defaultColumns = postgres.ColumnList{} ) return actorInfoTable{ @@ -80,5 +82,6 @@ func newActorInfoTableImpl(schemaName, tableName, alias string) actorInfoTable { AllColumns: allColumns, MutableColumns: mutableColumns, + DefaultColumns: defaultColumns, } } diff --git a/examples/quick-start/.gen/jetdb/dvds/view/customer_list.go b/examples/quick-start/.gen/jetdb/dvds/view/customer_list.go index cdf14ca..5c0d98e 100644 --- a/examples/quick-start/.gen/jetdb/dvds/view/customer_list.go +++ b/examples/quick-start/.gen/jetdb/dvds/view/customer_list.go @@ -16,7 +16,7 @@ var CustomerList = newCustomerListTable("dvds", "customer_list", "") type customerListTable struct { postgres.Table - //Columns + // Columns ID postgres.ColumnInteger Name postgres.ColumnString Address postgres.ColumnString @@ -29,6 +29,7 @@ type customerListTable struct { AllColumns postgres.ColumnList MutableColumns postgres.ColumnList + DefaultColumns postgres.ColumnList } type CustomerListTable struct { @@ -77,6 +78,7 @@ func newCustomerListTableImpl(schemaName, tableName, alias string) customerListT SidColumn = postgres.IntegerColumn("sid") allColumns = postgres.ColumnList{IDColumn, NameColumn, AddressColumn, ZipCodeColumn, PhoneColumn, CityColumn, CountryColumn, NotesColumn, SidColumn} mutableColumns = postgres.ColumnList{IDColumn, NameColumn, AddressColumn, ZipCodeColumn, PhoneColumn, CityColumn, CountryColumn, NotesColumn, SidColumn} + defaultColumns = postgres.ColumnList{} ) return customerListTable{ @@ -95,5 +97,6 @@ func newCustomerListTableImpl(schemaName, tableName, alias string) customerListT AllColumns: allColumns, MutableColumns: mutableColumns, + DefaultColumns: defaultColumns, } } diff --git a/examples/quick-start/README.md b/examples/quick-start/README.md index 018aec8..e6285f5 100644 --- a/examples/quick-start/README.md +++ b/examples/quick-start/README.md @@ -1,12 +1,12 @@ - -# Quick start example - -This package contains sample usage for Jet framework. - -Jet generated files of interest are in `./gen` folder. - -`quick-start.go` - contains code explained at main [README.md](../../README.md#quick-start), -with a difference of redirecting json output to files(`dest.json` and `dest2.json`) rather then to a -standard output. - -`./gen`, `dest.json` and `dest2.json` - added into git for presentation purposes. + +# Quick start example + +This package contains sample usage for Jet framework. + +Jet generated files of interest are in `./gen` folder. + +`quick-start.go` - contains code explained at main [README.md](../../README.md#quick-start), +with a difference of redirecting json output to files(`dest.json` and `dest2.json`) rather then to a +standard output. + +`./gen`, `dest.json` and `dest2.json` - added into git for presentation purposes. diff --git a/examples/quick-start/dest.json b/examples/quick-start/dest.json index 900760d..f169504 100644 --- a/examples/quick-start/dest.json +++ b/examples/quick-start/dest.json @@ -17,7 +17,11 @@ "ReplacementCost": 24.99, "Rating": "NC-17", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Deleted Scenes\",\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Deleted Scenes", + "Behind the Scenes" + ], "Fulltext": "'action':5 'action-pack':4 'baloon':21 'boy':10 'chase':16 'evolut':2 'king':1 'lumberjack':13 'madman':18 'must':15 'pack':6 'tale':7", "Language": { "LanguageID": 1, @@ -52,7 +56,10 @@ "ReplacementCost": 9.99, "Rating": "G", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Behind the Scenes" + ], "Fulltext": "'administr':12 'boat':8 'boy':17 'databas':11 'first':20 'languag':2 'man':21 'meet':15 'must':14 'space':22 'station':23 'unbeliev':4 'yarn':5 'young':1", "Language": { "LanguageID": 1, @@ -87,7 +94,10 @@ "ReplacementCost": 23.99, "Rating": "PG-13", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Behind the Scenes" + ], "Fulltext": "'georgia':20 'lacklustur':4 'monkey':17 'must':14 'pocus':2 'red':1 'redeem':15 'soviet':19 'squirrel':12 'sumo':8 'wrestler':9 'yarn':5", "Language": { "LanguageID": 1, @@ -104,103 +114,6 @@ } ] }, - { - "ActorID": 5, - "FirstName": "Johnny", - "LastName": "Lollobrigida", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 340, - "Title": "Frontier Cabin", - "Description": "A Emotional Story of a Madman And a Waitress who must Battle a Teacher in An Abandoned Fun House", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 4.99, - "Length": 183, - "ReplacementCost": 14.99, - "Rating": "PG-13", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries,\"Deleted Scenes\"}", - "Fulltext": "'abandon':19 'battl':14 'cabin':2 'emot':4 'frontier':1 'fun':20 'hous':21 'madman':8 'must':13 'stori':5 'teacher':16 'waitress':11", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 13, - "Name": "New", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - }, - { - "FilmID": 841, - "Title": "Star Operation", - "Description": "A Insightful Character Study of a Girl And a Car who must Pursue a Mad Cow in A Shark Tank", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 5, - "RentalRate": 2.99, - "Length": 181, - "ReplacementCost": 9.99, - "Rating": "PG", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries}", - "Fulltext": "'car':12 'charact':5 'cow':18 'girl':9 'insight':4 'mad':17 'must':14 'oper':2 'pursu':15 'shark':21 'star':1 'studi':6 'tank':22", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 15, - "Name": "Sports", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, - { - "ActorID": 9, - "FirstName": "Joe", - "LastName": "Swank", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 510, - "Title": "Lawless Vision", - "Description": "A Insightful Yarn of a Boy And a Sumo Wrestler who must Outgun a Car in The Outback", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 4.99, - "Length": 181, - "ReplacementCost": 29.99, - "Rating": "G", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\",\"Behind the Scenes\"}", - "Fulltext": "'boy':8 'car':17 'insight':4 'lawless':1 'must':14 'outback':20 'outgun':15 'sumo':11 'vision':2 'wrestler':12 'yarn':5", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 2, - "Name": "Animation", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, { "ActorID": 11, "FirstName": "Zero", @@ -219,7 +132,10 @@ "ReplacementCost": 12.99, "Rating": "G", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Deleted Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Deleted Scenes" + ], "Fulltext": "'compos':16 'drama':5 'epic':4 'feminist':8 'fool':2 'moonwalk':1 'must':13 'new':18 'orlean':19 'pioneer':11 'sink':14", "Language": { "LanguageID": 1, @@ -254,7 +170,10 @@ "ReplacementCost": 12.99, "Rating": "G", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Deleted Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Deleted Scenes" + ], "Fulltext": "'compos':16 'drama':5 'epic':4 'feminist':8 'fool':2 'moonwalk':1 'must':13 'new':18 'orlean':19 'pioneer':11 'sink':14", "Language": { "LanguageID": 1, @@ -271,109 +190,12 @@ } ] }, - { - "ActorID": 15, - "FirstName": "Cuba", - "LastName": "Olivier", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 886, - "Title": "Theory Mermaid", - "Description": "A Fateful Yarn of a Composer And a Monkey who must Vanquish a Womanizer in The First Manned Space Station", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 5, - "RentalRate": 0.99, - "Length": 184, - "ReplacementCost": 9.99, - "Rating": "PG-13", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\",\"Behind the Scenes\"}", - "Fulltext": "'compos':8 'fate':4 'first':19 'man':20 'mermaid':2 'monkey':11 'must':13 'space':21 'station':22 'theori':1 'vanquish':14 'woman':16 'yarn':5", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 2, - "Name": "Animation", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, - { - "ActorID": 16, - "FirstName": "Fred", - "LastName": "Costner", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 886, - "Title": "Theory Mermaid", - "Description": "A Fateful Yarn of a Composer And a Monkey who must Vanquish a Womanizer in The First Manned Space Station", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 5, - "RentalRate": 0.99, - "Length": 184, - "ReplacementCost": 9.99, - "Rating": "PG-13", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\",\"Behind the Scenes\"}", - "Fulltext": "'compos':8 'fate':4 'first':19 'man':20 'mermaid':2 'monkey':11 'must':13 'space':21 'station':22 'theori':1 'vanquish':14 'woman':16 'yarn':5", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 2, - "Name": "Animation", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, { "ActorID": 19, "FirstName": "Bob", "LastName": "Fawcett", "LastUpdate": "2013-05-26T14:47:57.62Z", "Films": [ - { - "FilmID": 182, - "Title": "Control Anthem", - "Description": "A Fateful Documentary of a Robot And a Student who must Battle a Cat in A Monastery", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 7, - "RentalRate": 4.99, - "Length": 185, - "ReplacementCost": 9.99, - "Rating": "G", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries}", - "Fulltext": "'anthem':2 'battl':14 'cat':16 'control':1 'documentari':5 'fate':4 'monasteri':19 'must':13 'robot':8 'student':11", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 5, - "Name": "Comedy", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - }, { "FilmID": 473, "Title": "Jacket Frisco", @@ -386,7 +208,11 @@ "ReplacementCost": 16.99, "Rating": "PG-13", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Deleted Scenes\",\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Deleted Scenes", + "Behind the Scenes" + ], "Fulltext": "'baloon':20 'chef':17 'conquer':14 'frisco':2 'husband':11 'insight':4 'jacket':1 'must':13 'pastri':16 'reflect':5 'woman':8", "Language": { "LanguageID": 1, @@ -400,33 +226,6 @@ "LastUpdate": "2006-02-15T09:46:27Z" } ] - }, - { - "FilmID": 510, - "Title": "Lawless Vision", - "Description": "A Insightful Yarn of a Boy And a Sumo Wrestler who must Outgun a Car in The Outback", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 4.99, - "Length": 181, - "ReplacementCost": 29.99, - "Rating": "G", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\",\"Behind the Scenes\"}", - "Fulltext": "'boy':8 'car':17 'insight':4 'lawless':1 'must':14 'outback':20 'outgun':15 'sumo':11 'vision':2 'wrestler':12 'yarn':5", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 2, - "Name": "Animation", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] } ] }, @@ -448,7 +247,11 @@ "ReplacementCost": 24.99, "Rating": "NC-17", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Deleted Scenes\",\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Deleted Scenes", + "Behind the Scenes" + ], "Fulltext": "'action':5 'action-pack':4 'baloon':21 'boy':10 'chase':16 'evolut':2 'king':1 'lumberjack':13 'madman':18 'must':15 'pack':6 'tale':7", "Language": { "LanguageID": 1, @@ -465,136 +268,12 @@ } ] }, - { - "ActorID": 22, - "FirstName": "Elvis", - "LastName": "Marx", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 349, - "Title": "Gangs Pride", - "Description": "A Taut Character Study of a Woman And a A Shark who must Confront a Frisbee in Berlin", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 4, - "RentalRate": 2.99, - "Length": 185, - "ReplacementCost": 27.99, - "Rating": "PG-13", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Behind the Scenes\"}", - "Fulltext": "'berlin':20 'charact':5 'confront':16 'frisbe':18 'gang':1 'must':15 'pride':2 'shark':13 'studi':6 'taut':4 'woman':9", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 2, - "Name": "Animation", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, - { - "ActorID": 23, - "FirstName": "Sandra", - "LastName": "Kilmer", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 435, - "Title": "Hotel Happiness", - "Description": "A Thrilling Yarn of a Pastry Chef And a A Shark who must Challenge a Mad Scientist in The Outback", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 4.99, - "Length": 181, - "ReplacementCost": 28.99, - "Rating": "PG-13", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Behind the Scenes\"}", - "Fulltext": "'challeng':16 'chef':9 'happi':2 'hotel':1 'mad':18 'must':15 'outback':22 'pastri':8 'scientist':19 'shark':13 'thrill':4 'yarn':5", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 9, - "Name": "Foreign", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - }, - { - "FilmID": 820, - "Title": "Sons Interview", - "Description": "A Taut Character Study of a Explorer And a Mad Cow who must Battle a Hunter in Ancient China", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 3, - "RentalRate": 2.99, - "Length": 184, - "ReplacementCost": 11.99, - "Rating": "NC-17", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries,\"Behind the Scenes\"}", - "Fulltext": "'ancient':20 'battl':16 'charact':5 'china':21 'cow':13 'explor':9 'hunter':18 'interview':2 'mad':12 'must':15 'son':1 'studi':6 'taut':4", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 2, - "Name": "Animation", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, { "ActorID": 26, "FirstName": "Rip", "LastName": "Crawford", "LastUpdate": "2013-05-26T14:47:57.62Z", "Films": [ - { - "FilmID": 340, - "Title": "Frontier Cabin", - "Description": "A Emotional Story of a Madman And a Waitress who must Battle a Teacher in An Abandoned Fun House", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 4.99, - "Length": 183, - "ReplacementCost": 14.99, - "Rating": "PG-13", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries,\"Deleted Scenes\"}", - "Fulltext": "'abandon':19 'battl':14 'cabin':2 'emot':4 'frontier':1 'fun':20 'hous':21 'madman':8 'must':13 'stori':5 'teacher':16 'waitress':11", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 13, - "Name": "New", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - }, { "FilmID": 821, "Title": "Sorority Queen", @@ -607,7 +286,10 @@ "ReplacementCost": 17.99, "Rating": "NC-17", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Deleted Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Deleted Scenes" + ], "Fulltext": "'boat':23 'compos':13 'display':7 'fast':5 'fast-pac':4 'fight':16 'forens':18 'jet':22 'must':15 'pace':6 'psychologist':19 'queen':2 'soror':1 'squirrel':10", "Language": { "LanguageID": 1, @@ -642,7 +324,10 @@ "ReplacementCost": 9.99, "Rating": "G", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Behind the Scenes" + ], "Fulltext": "'administr':12 'boat':8 'boy':17 'databas':11 'first':20 'languag':2 'man':21 'meet':15 'must':14 'space':22 'station':23 'unbeliev':4 'yarn':5 'young':1", "Language": { "LanguageID": 1, @@ -677,7 +362,10 @@ "ReplacementCost": 12.99, "Rating": "G", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Deleted Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Deleted Scenes" + ], "Fulltext": "'compos':16 'drama':5 'epic':4 'feminist':8 'fool':2 'moonwalk':1 'must':13 'new':18 'orlean':19 'pioneer':11 'sink':14", "Language": { "LanguageID": 1, @@ -691,33 +379,6 @@ "LastUpdate": "2006-02-15T09:46:27Z" } ] - }, - { - "FilmID": 973, - "Title": "Wife Turn", - "Description": "A Awe-Inspiring Epistle of a Teacher And a Feminist who must Confront a Pioneer in Ancient Japan", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 3, - "RentalRate": 4.99, - "Length": 183, - "ReplacementCost": 27.99, - "Rating": "NC-17", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\",\"Behind the Scenes\"}", - "Fulltext": "'ancient':20 'awe':5 'awe-inspir':4 'confront':16 'epistl':7 'feminist':13 'inspir':6 'japan':21 'must':15 'pioneer':18 'teacher':10 'turn':2 'wife':1", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 6, - "Name": "Documentary", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] } ] }, @@ -739,7 +400,11 @@ "ReplacementCost": 16.99, "Rating": "PG-13", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Deleted Scenes\",\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Deleted Scenes", + "Behind the Scenes" + ], "Fulltext": "'baloon':20 'chef':17 'conquer':14 'frisco':2 'husband':11 'insight':4 'jacket':1 'must':13 'pastri':16 'reflect':5 'woman':8", "Language": { "LanguageID": 1, @@ -756,41 +421,6 @@ } ] }, - { - "ActorID": 34, - "FirstName": "Audrey", - "LastName": "Olivier", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 182, - "Title": "Control Anthem", - "Description": "A Fateful Documentary of a Robot And a Student who must Battle a Cat in A Monastery", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 7, - "RentalRate": 4.99, - "Length": 185, - "ReplacementCost": 9.99, - "Rating": "G", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries}", - "Fulltext": "'anthem':2 'battl':14 'cat':16 'control':1 'documentari':5 'fate':4 'monasteri':19 'must':13 'robot':8 'student':11", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 5, - "Name": "Comedy", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, { "ActorID": 36, "FirstName": "Burt", @@ -809,7 +439,11 @@ "ReplacementCost": 24.99, "Rating": "NC-17", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Deleted Scenes\",\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Deleted Scenes", + "Behind the Scenes" + ], "Fulltext": "'action':5 'action-pack':4 'baloon':21 'boy':10 'chase':16 'evolut':2 'king':1 'lumberjack':13 'madman':18 'must':15 'pack':6 'tale':7", "Language": { "LanguageID": 1, @@ -826,41 +460,6 @@ } ] }, - { - "ActorID": 37, - "FirstName": "Val", - "LastName": "Bolger", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 467, - "Title": "Intrigue Worst", - "Description": "A Fanciful Character Study of a Explorer And a Mad Scientist who must Vanquish a Squirrel in A Jet Boat", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 0.99, - "Length": 181, - "ReplacementCost": 10.99, - "Rating": "G", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\"}", - "Fulltext": "'boat':22 'charact':5 'explor':9 'fanci':4 'intrigu':1 'jet':21 'mad':12 'must':15 'scientist':13 'squirrel':18 'studi':6 'vanquish':16 'worst':2", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 9, - "Name": "Foreign", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, { "ActorID": 40, "FirstName": "Johnny", @@ -879,7 +478,10 @@ "ReplacementCost": 10.99, "Rating": "G", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Behind the Scenes" + ], "Fulltext": "'amistad':2 'bore':4 'catch':1 'discov':14 'feminist':11 'lumberjack':8 'must':13 'nigeria':18 'reflect':5 'woman':16", "Language": { "LanguageID": 1, @@ -914,7 +516,10 @@ "ReplacementCost": 23.99, "Rating": "PG-13", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Behind the Scenes" + ], "Fulltext": "'georgia':20 'lacklustur':4 'monkey':17 'must':14 'pocus':2 'red':1 'redeem':15 'soviet':19 'squirrel':12 'sumo':8 'wrestler':9 'yarn':5", "Language": { "LanguageID": 1, @@ -949,7 +554,10 @@ "ReplacementCost": 27.99, "Rating": "PG-13", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,Commentaries}", + "SpecialFeatures": [ + "Trailers", + "Commentaries" + ], "Fulltext": "'abandon':21 'awe':5 'awe-inspir':4 'conquer':16 'conspiraci':1 'crocodil':18 'frisbe':13 'inspir':6 'mine':22 'must':15 'shaft':23 'spirit':2 'stori':7 'student':10", "Language": { "LanguageID": 1, @@ -966,68 +574,6 @@ } ] }, - { - "ActorID": 44, - "FirstName": "Nick", - "LastName": "Stallone", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 591, - "Title": "Monsoon Cause", - "Description": "A Astounding Tale of a Crocodile And a Car who must Outrace a Squirrel in A U-Boat", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 4.99, - "Length": 182, - "ReplacementCost": 20.99, - "Rating": "PG", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries,\"Behind the Scenes\"}", - "Fulltext": "'astound':4 'boat':21 'car':11 'caus':2 'crocodil':8 'monsoon':1 'must':13 'outrac':14 'squirrel':16 'tale':5 'u':20 'u-boat':19", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 10, - "Name": "Games", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - }, - { - "FilmID": 751, - "Title": "Runaway Tenenbaums", - "Description": "A Thoughtful Documentary of a Boat And a Man who must Meet a Boat in An Abandoned Fun House", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 0.99, - "Length": 181, - "ReplacementCost": 17.99, - "Rating": "NC-17", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries}", - "Fulltext": "'abandon':19 'boat':8,16 'documentari':5 'fun':20 'hous':21 'man':11 'meet':14 'must':13 'runaway':1 'tenenbaum':2 'thought':4", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 13, - "Name": "New", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, { "ActorID": 45, "FirstName": "Reese", @@ -1046,7 +592,10 @@ "ReplacementCost": 22.99, "Rating": "NC-17", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,Commentaries}", + "SpecialFeatures": [ + "Trailers", + "Commentaries" + ], "Fulltext": "'ancient':22 'break':2 'charact':7 'chef':20 'crystal':1 'explor':14 'face':17 'fast':5 'fast-pac':4 'feminist':11 'japan':23 'must':16 'pace':6 'pastri':19 'studi':8", "Language": { "LanguageID": 1, @@ -1060,332 +609,6 @@ "LastUpdate": "2006-02-15T09:46:27Z" } ] - }, - { - "FilmID": 467, - "Title": "Intrigue Worst", - "Description": "A Fanciful Character Study of a Explorer And a Mad Scientist who must Vanquish a Squirrel in A Jet Boat", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 0.99, - "Length": 181, - "ReplacementCost": 10.99, - "Rating": "G", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\"}", - "Fulltext": "'boat':22 'charact':5 'explor':9 'fanci':4 'intrigu':1 'jet':21 'mad':12 'must':15 'scientist':13 'squirrel':18 'studi':6 'vanquish':16 'worst':2", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 9, - "Name": "Foreign", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - }, - { - "FilmID": 767, - "Title": "Scalawag Duck", - "Description": "A Fateful Reflection of a Car And a Teacher who must Confront a Waitress in A Monastery", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 4.99, - "Length": 183, - "ReplacementCost": 13.99, - "Rating": "NC-17", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries,\"Behind the Scenes\"}", - "Fulltext": "'car':8 'confront':14 'duck':2 'fate':4 'monasteri':19 'must':13 'reflect':5 'scalawag':1 'teacher':11 'waitress':16", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 12, - "Name": "Music", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, - { - "ActorID": 46, - "FirstName": "Parker", - "LastName": "Goldberg", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 820, - "Title": "Sons Interview", - "Description": "A Taut Character Study of a Explorer And a Mad Cow who must Battle a Hunter in Ancient China", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 3, - "RentalRate": 2.99, - "Length": 184, - "ReplacementCost": 11.99, - "Rating": "NC-17", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries,\"Behind the Scenes\"}", - "Fulltext": "'ancient':20 'battl':16 'charact':5 'china':21 'cow':13 'explor':9 'hunter':18 'interview':2 'mad':12 'must':15 'son':1 'studi':6 'taut':4", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 2, - "Name": "Animation", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, - { - "ActorID": 47, - "FirstName": "Julia", - "LastName": "Barrymore", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 973, - "Title": "Wife Turn", - "Description": "A Awe-Inspiring Epistle of a Teacher And a Feminist who must Confront a Pioneer in Ancient Japan", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 3, - "RentalRate": 4.99, - "Length": 183, - "ReplacementCost": 27.99, - "Rating": "NC-17", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\",\"Behind the Scenes\"}", - "Fulltext": "'ancient':20 'awe':5 'awe-inspir':4 'confront':16 'epistl':7 'feminist':13 'inspir':6 'japan':21 'must':15 'pioneer':18 'teacher':10 'turn':2 'wife':1", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 6, - "Name": "Documentary", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, - { - "ActorID": 48, - "FirstName": "Frances", - "LastName": "Day-Lewis", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 349, - "Title": "Gangs Pride", - "Description": "A Taut Character Study of a Woman And a A Shark who must Confront a Frisbee in Berlin", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 4, - "RentalRate": 2.99, - "Length": 185, - "ReplacementCost": 27.99, - "Rating": "PG-13", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Behind the Scenes\"}", - "Fulltext": "'berlin':20 'charact':5 'confront':16 'frisbe':18 'gang':1 'must':15 'pride':2 'shark':13 'studi':6 'taut':4 'woman':9", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 2, - "Name": "Animation", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, - { - "ActorID": 50, - "FirstName": "Natalie", - "LastName": "Hopkins", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 591, - "Title": "Monsoon Cause", - "Description": "A Astounding Tale of a Crocodile And a Car who must Outrace a Squirrel in A U-Boat", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 4.99, - "Length": 182, - "ReplacementCost": 20.99, - "Rating": "PG", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries,\"Behind the Scenes\"}", - "Fulltext": "'astound':4 'boat':21 'car':11 'caus':2 'crocodil':8 'monsoon':1 'must':13 'outrac':14 'squirrel':16 'tale':5 'u':20 'u-boat':19", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 10, - "Name": "Games", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, - { - "ActorID": 54, - "FirstName": "Penelope", - "LastName": "Pinkett", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 510, - "Title": "Lawless Vision", - "Description": "A Insightful Yarn of a Boy And a Sumo Wrestler who must Outgun a Car in The Outback", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 4.99, - "Length": 181, - "ReplacementCost": 29.99, - "Rating": "G", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\",\"Behind the Scenes\"}", - "Fulltext": "'boy':8 'car':17 'insight':4 'lawless':1 'must':14 'outback':20 'outgun':15 'sumo':11 'vision':2 'wrestler':12 'yarn':5", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 2, - "Name": "Animation", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, - { - "ActorID": 55, - "FirstName": "Fay", - "LastName": "Kilmer", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 340, - "Title": "Frontier Cabin", - "Description": "A Emotional Story of a Madman And a Waitress who must Battle a Teacher in An Abandoned Fun House", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 4.99, - "Length": 183, - "ReplacementCost": 14.99, - "Rating": "PG-13", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries,\"Deleted Scenes\"}", - "Fulltext": "'abandon':19 'battl':14 'cabin':2 'emot':4 'frontier':1 'fun':20 'hous':21 'madman':8 'must':13 'stori':5 'teacher':16 'waitress':11", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 13, - "Name": "New", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, - { - "ActorID": 57, - "FirstName": "Jude", - "LastName": "Cruise", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 340, - "Title": "Frontier Cabin", - "Description": "A Emotional Story of a Madman And a Waitress who must Battle a Teacher in An Abandoned Fun House", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 4.99, - "Length": 183, - "ReplacementCost": 14.99, - "Rating": "PG-13", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries,\"Deleted Scenes\"}", - "Fulltext": "'abandon':19 'battl':14 'cabin':2 'emot':4 'frontier':1 'fun':20 'hous':21 'madman':8 'must':13 'stori':5 'teacher':16 'waitress':11", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 13, - "Name": "New", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - }, - { - "FilmID": 767, - "Title": "Scalawag Duck", - "Description": "A Fateful Reflection of a Car And a Teacher who must Confront a Waitress in A Monastery", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 4.99, - "Length": 183, - "ReplacementCost": 13.99, - "Rating": "NC-17", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries,\"Behind the Scenes\"}", - "Fulltext": "'car':8 'confront':14 'duck':2 'fate':4 'monasteri':19 'must':13 'reflect':5 'scalawag':1 'teacher':11 'waitress':16", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 12, - "Name": "Music", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] } ] }, @@ -1407,7 +630,10 @@ "ReplacementCost": 10.99, "Rating": "G", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Behind the Scenes" + ], "Fulltext": "'amistad':2 'bore':4 'catch':1 'discov':14 'feminist':11 'lumberjack':8 'must':13 'nigeria':18 'reflect':5 'woman':16", "Language": { "LanguageID": 1, @@ -1424,41 +650,6 @@ } ] }, - { - "ActorID": 61, - "FirstName": "Christian", - "LastName": "Neeson", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 767, - "Title": "Scalawag Duck", - "Description": "A Fateful Reflection of a Car And a Teacher who must Confront a Waitress in A Monastery", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 4.99, - "Length": 183, - "ReplacementCost": 13.99, - "Rating": "NC-17", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries,\"Behind the Scenes\"}", - "Fulltext": "'car':8 'confront':14 'duck':2 'fate':4 'monasteri':19 'must':13 'reflect':5 'scalawag':1 'teacher':11 'waitress':16", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 12, - "Name": "Music", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, { "ActorID": 62, "FirstName": "Jayne", @@ -1477,7 +668,10 @@ "ReplacementCost": 22.99, "Rating": "NC-17", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,Commentaries}", + "SpecialFeatures": [ + "Trailers", + "Commentaries" + ], "Fulltext": "'ancient':22 'break':2 'charact':7 'chef':20 'crystal':1 'explor':14 'face':17 'fast':5 'fast-pac':4 'feminist':11 'japan':23 'must':16 'pace':6 'pastri':19 'studi':8", "Language": { "LanguageID": 1, @@ -1491,33 +685,6 @@ "LastUpdate": "2006-02-15T09:46:27Z" } ] - }, - { - "FilmID": 719, - "Title": "Records Zorro", - "Description": "A Amazing Drama of a Mad Scientist And a Composer who must Build a Husband in The Outback", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 7, - "RentalRate": 4.99, - "Length": 182, - "ReplacementCost": 11.99, - "Rating": "PG", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Behind the Scenes\"}", - "Fulltext": "'amaz':4 'build':15 'compos':12 'drama':5 'husband':17 'mad':8 'must':14 'outback':20 'record':1 'scientist':9 'zorro':2", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 15, - "Name": "Sports", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] } ] }, @@ -1539,7 +706,10 @@ "ReplacementCost": 12.99, "Rating": "G", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Deleted Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Deleted Scenes" + ], "Fulltext": "'compos':16 'drama':5 'epic':4 'feminist':8 'fool':2 'moonwalk':1 'must':13 'new':18 'orlean':19 'pioneer':11 'sink':14", "Language": { "LanguageID": 1, @@ -1556,214 +726,12 @@ } ] }, - { - "ActorID": 68, - "FirstName": "Rip", - "LastName": "Winslet", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 435, - "Title": "Hotel Happiness", - "Description": "A Thrilling Yarn of a Pastry Chef And a A Shark who must Challenge a Mad Scientist in The Outback", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 4.99, - "Length": 181, - "ReplacementCost": 28.99, - "Rating": "PG-13", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Behind the Scenes\"}", - "Fulltext": "'challeng':16 'chef':9 'happi':2 'hotel':1 'mad':18 'must':15 'outback':22 'pastri':8 'scientist':19 'shark':13 'thrill':4 'yarn':5", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 9, - "Name": "Foreign", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, - { - "ActorID": 70, - "FirstName": "Michelle", - "LastName": "Mcconaughey", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 50, - "Title": "Baked Cleopatra", - "Description": "A Stunning Drama of a Forensic Psychologist And a Husband who must Overcome a Waitress in A Monastery", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 3, - "RentalRate": 2.99, - "Length": 182, - "ReplacementCost": 20.99, - "Rating": "G", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries,\"Behind the Scenes\"}", - "Fulltext": "'bake':1 'cleopatra':2 'drama':5 'forens':8 'husband':12 'monasteri':20 'must':14 'overcom':15 'psychologist':9 'stun':4 'waitress':17", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 8, - "Name": "Family", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, - { - "ActorID": 72, - "FirstName": "Sean", - "LastName": "Williams", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 609, - "Title": "Muscle Bright", - "Description": "A Stunning Panorama of a Sumo Wrestler And a Husband who must Redeem a Madman in Ancient India", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 7, - "RentalRate": 2.99, - "Length": 185, - "ReplacementCost": 23.99, - "Rating": "G", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\"}", - "Fulltext": "'ancient':19 'bright':2 'husband':12 'india':20 'madman':17 'muscl':1 'must':14 'panorama':5 'redeem':15 'stun':4 'sumo':8 'wrestler':9", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 16, - "Name": "Travel", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, - { - "ActorID": 73, - "FirstName": "Gary", - "LastName": "Penn", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 467, - "Title": "Intrigue Worst", - "Description": "A Fanciful Character Study of a Explorer And a Mad Scientist who must Vanquish a Squirrel in A Jet Boat", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 0.99, - "Length": 181, - "ReplacementCost": 10.99, - "Rating": "G", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\"}", - "Fulltext": "'boat':22 'charact':5 'explor':9 'fanci':4 'intrigu':1 'jet':21 'mad':12 'must':15 'scientist':13 'squirrel':18 'studi':6 'vanquish':16 'worst':2", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 9, - "Name": "Foreign", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, - { - "ActorID": 78, - "FirstName": "Groucho", - "LastName": "Sinatra", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 767, - "Title": "Scalawag Duck", - "Description": "A Fateful Reflection of a Car And a Teacher who must Confront a Waitress in A Monastery", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 4.99, - "Length": 183, - "ReplacementCost": 13.99, - "Rating": "NC-17", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries,\"Behind the Scenes\"}", - "Fulltext": "'car':8 'confront':14 'duck':2 'fate':4 'monasteri':19 'must':13 'reflect':5 'scalawag':1 'teacher':11 'waitress':16", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 12, - "Name": "Music", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, { "ActorID": 79, "FirstName": "Mae", "LastName": "Hoffman", "LastUpdate": "2013-05-26T14:47:57.62Z", "Films": [ - { - "FilmID": 141, - "Title": "Chicago North", - "Description": "A Fateful Yarn of a Mad Cow And a Waitress who must Battle a Student in California", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 4.99, - "Length": 185, - "ReplacementCost": 11.99, - "Rating": "PG-13", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\",\"Behind the Scenes\"}", - "Fulltext": "'battl':15 'california':19 'chicago':1 'cow':9 'fate':4 'mad':8 'must':14 'north':2 'student':17 'waitress':12 'yarn':5", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 10, - "Name": "Games", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - }, { "FilmID": 473, "Title": "Jacket Frisco", @@ -1776,7 +744,11 @@ "ReplacementCost": 16.99, "Rating": "PG-13", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Deleted Scenes\",\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Deleted Scenes", + "Behind the Scenes" + ], "Fulltext": "'baloon':20 'chef':17 'conquer':14 'frisco':2 'husband':11 'insight':4 'jacket':1 'must':13 'pastri':16 'reflect':5 'woman':8", "Language": { "LanguageID": 1, @@ -1793,68 +765,6 @@ } ] }, - { - "ActorID": 83, - "FirstName": "Ben", - "LastName": "Willis", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 340, - "Title": "Frontier Cabin", - "Description": "A Emotional Story of a Madman And a Waitress who must Battle a Teacher in An Abandoned Fun House", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 4.99, - "Length": 183, - "ReplacementCost": 14.99, - "Rating": "PG-13", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries,\"Deleted Scenes\"}", - "Fulltext": "'abandon':19 'battl':14 'cabin':2 'emot':4 'frontier':1 'fun':20 'hous':21 'madman':8 'must':13 'stori':5 'teacher':16 'waitress':11", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 13, - "Name": "New", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - }, - { - "FilmID": 719, - "Title": "Records Zorro", - "Description": "A Amazing Drama of a Mad Scientist And a Composer who must Build a Husband in The Outback", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 7, - "RentalRate": 4.99, - "Length": 182, - "ReplacementCost": 11.99, - "Rating": "PG", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Behind the Scenes\"}", - "Fulltext": "'amaz':4 'build':15 'compos':12 'drama':5 'husband':17 'mad':8 'must':14 'outback':20 'record':1 'scientist':9 'zorro':2", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 15, - "Name": "Sports", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, { "ActorID": 84, "FirstName": "James", @@ -1873,7 +783,10 @@ "ReplacementCost": 9.99, "Rating": "G", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Behind the Scenes" + ], "Fulltext": "'administr':12 'boat':8 'boy':17 'databas':11 'first':20 'languag':2 'man':21 'meet':15 'must':14 'space':22 'station':23 'unbeliev':4 'yarn':5 'young':1", "Language": { "LanguageID": 1, @@ -1890,41 +803,6 @@ } ] }, - { - "ActorID": 85, - "FirstName": "Minnie", - "LastName": "Zellweger", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 591, - "Title": "Monsoon Cause", - "Description": "A Astounding Tale of a Crocodile And a Car who must Outrace a Squirrel in A U-Boat", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 4.99, - "Length": 182, - "ReplacementCost": 20.99, - "Rating": "PG", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries,\"Behind the Scenes\"}", - "Fulltext": "'astound':4 'boat':21 'car':11 'caus':2 'crocodil':8 'monsoon':1 'must':13 'outrac':14 'squirrel':16 'tale':5 'u':20 'u-boat':19", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 10, - "Name": "Games", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, { "ActorID": 87, "FirstName": "Spencer", @@ -1943,7 +821,10 @@ "ReplacementCost": 23.99, "Rating": "PG-13", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Behind the Scenes" + ], "Fulltext": "'georgia':20 'lacklustur':4 'monkey':17 'must':14 'pocus':2 'red':1 'redeem':15 'soviet':19 'squirrel':12 'sumo':8 'wrestler':9 'yarn':5", "Language": { "LanguageID": 1, @@ -1978,7 +859,10 @@ "ReplacementCost": 10.99, "Rating": "G", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Behind the Scenes" + ], "Fulltext": "'amistad':2 'bore':4 'catch':1 'discov':14 'feminist':11 'lumberjack':8 'must':13 'nigeria':18 'reflect':5 'woman':16", "Language": { "LanguageID": 1, @@ -2001,33 +885,6 @@ "LastName": "Dench", "LastUpdate": "2013-05-26T14:47:57.62Z", "Films": [ - { - "FilmID": 182, - "Title": "Control Anthem", - "Description": "A Fateful Documentary of a Robot And a Student who must Battle a Cat in A Monastery", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 7, - "RentalRate": 4.99, - "Length": 185, - "ReplacementCost": 9.99, - "Rating": "G", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries}", - "Fulltext": "'anthem':2 'battl':14 'cat':16 'control':1 'documentari':5 'fate':4 'monasteri':19 'must':13 'robot':8 'student':11", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 5, - "Name": "Comedy", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - }, { "FilmID": 473, "Title": "Jacket Frisco", @@ -2040,7 +897,11 @@ "ReplacementCost": 16.99, "Rating": "PG-13", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Deleted Scenes\",\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Deleted Scenes", + "Behind the Scenes" + ], "Fulltext": "'baloon':20 'chef':17 'conquer':14 'frisco':2 'husband':11 'insight':4 'jacket':1 'must':13 'pastri':16 'reflect':5 'woman':8", "Language": { "LanguageID": 1, @@ -2075,7 +936,11 @@ "ReplacementCost": 16.99, "Rating": "PG-13", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Deleted Scenes\",\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Deleted Scenes", + "Behind the Scenes" + ], "Fulltext": "'baloon':20 'chef':17 'conquer':14 'frisco':2 'husband':11 'insight':4 'jacket':1 'must':13 'pastri':16 'reflect':5 'woman':8", "Language": { "LanguageID": 1, @@ -2110,7 +975,11 @@ "ReplacementCost": 16.99, "Rating": "PG-13", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Deleted Scenes\",\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Deleted Scenes", + "Behind the Scenes" + ], "Fulltext": "'baloon':20 'chef':17 'conquer':14 'frisco':2 'husband':11 'insight':4 'jacket':1 'must':13 'pastri':16 'reflect':5 'woman':8", "Language": { "LanguageID": 1, @@ -2145,7 +1014,11 @@ "ReplacementCost": 25.99, "Rating": "PG-13", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,Commentaries,\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Commentaries", + "Behind the Scenes" + ], "Fulltext": "'ancient':18 'battl':14 'boat':11 'china':19 'drama':5 'feminist':16 'must':13 'pond':1 'seattl':2 'stun':4 'teacher':8", "Language": { "LanguageID": 1, @@ -2180,7 +1053,10 @@ "ReplacementCost": 23.99, "Rating": "PG-13", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Behind the Scenes" + ], "Fulltext": "'georgia':20 'lacklustur':4 'monkey':17 'must':14 'pocus':2 'red':1 'redeem':15 'soviet':19 'squirrel':12 'sumo':8 'wrestler':9 'yarn':5", "Language": { "LanguageID": 1, @@ -2215,7 +1091,12 @@ "ReplacementCost": 22.99, "Rating": "NC-17", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,Commentaries,\"Deleted Scenes\",\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Commentaries", + "Deleted Scenes", + "Behind the Scenes" + ], "Fulltext": "'ancient':21 'car':10 'fast':5 'fast-pac':4 'japan':22 'kill':17 'mad':13 'must':16 'pace':6 'scientist':14 'searcher':1 'tale':7 'wait':2 'woman':19", "Language": { "LanguageID": 1, @@ -2229,68 +1110,6 @@ "LastUpdate": "2006-02-15T09:46:27Z" } ] - }, - { - "FilmID": 841, - "Title": "Star Operation", - "Description": "A Insightful Character Study of a Girl And a Car who must Pursue a Mad Cow in A Shark Tank", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 5, - "RentalRate": 2.99, - "Length": 181, - "ReplacementCost": 9.99, - "Rating": "PG", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries}", - "Fulltext": "'car':12 'charact':5 'cow':18 'girl':9 'insight':4 'mad':17 'must':14 'oper':2 'pursu':15 'shark':21 'star':1 'studi':6 'tank':22", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 15, - "Name": "Sports", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, - { - "ActorID": 103, - "FirstName": "Matthew", - "LastName": "Leigh", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 609, - "Title": "Muscle Bright", - "Description": "A Stunning Panorama of a Sumo Wrestler And a Husband who must Redeem a Madman in Ancient India", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 7, - "RentalRate": 2.99, - "Length": 185, - "ReplacementCost": 23.99, - "Rating": "G", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\"}", - "Fulltext": "'ancient':19 'bright':2 'husband':12 'india':20 'madman':17 'muscl':1 'must':14 'panorama':5 'redeem':15 'stun':4 'sumo':8 'wrestler':9", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 16, - "Name": "Travel", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] } ] }, @@ -2312,7 +1131,10 @@ "ReplacementCost": 22.99, "Rating": "NC-17", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,Commentaries}", + "SpecialFeatures": [ + "Trailers", + "Commentaries" + ], "Fulltext": "'ancient':22 'break':2 'charact':7 'chef':20 'crystal':1 'explor':14 'face':17 'fast':5 'fast-pac':4 'feminist':11 'japan':23 'must':16 'pace':6 'pastri':19 'studi':8", "Language": { "LanguageID": 1, @@ -2335,33 +1157,6 @@ "LastName": "Degeneres", "LastUpdate": "2013-05-26T14:47:57.62Z", "Films": [ - { - "FilmID": 467, - "Title": "Intrigue Worst", - "Description": "A Fanciful Character Study of a Explorer And a Mad Scientist who must Vanquish a Squirrel in A Jet Boat", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 0.99, - "Length": 181, - "ReplacementCost": 10.99, - "Rating": "G", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\"}", - "Fulltext": "'boat':22 'charact':5 'explor':9 'fanci':4 'intrigu':1 'jet':21 'mad':12 'must':15 'scientist':13 'squirrel':18 'studi':6 'vanquish':16 'worst':2", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 9, - "Name": "Foreign", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - }, { "FilmID": 774, "Title": "Searchers Wait", @@ -2374,7 +1169,12 @@ "ReplacementCost": 22.99, "Rating": "NC-17", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,Commentaries,\"Deleted Scenes\",\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Commentaries", + "Deleted Scenes", + "Behind the Scenes" + ], "Fulltext": "'ancient':21 'car':10 'fast':5 'fast-pac':4 'japan':22 'kill':17 'mad':13 'must':16 'pace':6 'scientist':14 'searcher':1 'tale':7 'wait':2 'woman':19", "Language": { "LanguageID": 1, @@ -2388,33 +1188,6 @@ "LastUpdate": "2006-02-15T09:46:27Z" } ] - }, - { - "FilmID": 973, - "Title": "Wife Turn", - "Description": "A Awe-Inspiring Epistle of a Teacher And a Feminist who must Confront a Pioneer in Ancient Japan", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 3, - "RentalRate": 4.99, - "Length": 183, - "ReplacementCost": 27.99, - "Rating": "NC-17", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\",\"Behind the Scenes\"}", - "Fulltext": "'ancient':20 'awe':5 'awe-inspir':4 'confront':16 'epistl':7 'feminist':13 'inspir':6 'japan':21 'must':15 'pioneer':18 'teacher':10 'turn':2 'wife':1", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 6, - "Name": "Documentary", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] } ] }, @@ -2436,7 +1209,10 @@ "ReplacementCost": 23.99, "Rating": "PG-13", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Behind the Scenes" + ], "Fulltext": "'georgia':20 'lacklustur':4 'monkey':17 'must':14 'pocus':2 'red':1 'redeem':15 'soviet':19 'squirrel':12 'sumo':8 'wrestler':9 'yarn':5", "Language": { "LanguageID": 1, @@ -2453,146 +1229,6 @@ } ] }, - { - "ActorID": 110, - "FirstName": "Susan", - "LastName": "Davis", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 435, - "Title": "Hotel Happiness", - "Description": "A Thrilling Yarn of a Pastry Chef And a A Shark who must Challenge a Mad Scientist in The Outback", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 4.99, - "Length": 181, - "ReplacementCost": 28.99, - "Rating": "PG-13", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Behind the Scenes\"}", - "Fulltext": "'challeng':16 'chef':9 'happi':2 'hotel':1 'mad':18 'must':15 'outback':22 'pastri':8 'scientist':19 'shark':13 'thrill':4 'yarn':5", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 9, - "Name": "Foreign", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, - { - "ActorID": 111, - "FirstName": "Cameron", - "LastName": "Zellweger", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 973, - "Title": "Wife Turn", - "Description": "A Awe-Inspiring Epistle of a Teacher And a Feminist who must Confront a Pioneer in Ancient Japan", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 3, - "RentalRate": 4.99, - "Length": 183, - "ReplacementCost": 27.99, - "Rating": "NC-17", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\",\"Behind the Scenes\"}", - "Fulltext": "'ancient':20 'awe':5 'awe-inspir':4 'confront':16 'epistl':7 'feminist':13 'inspir':6 'japan':21 'must':15 'pioneer':18 'teacher':10 'turn':2 'wife':1", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 6, - "Name": "Documentary", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, - { - "ActorID": 113, - "FirstName": "Morgan", - "LastName": "Hopkins", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 719, - "Title": "Records Zorro", - "Description": "A Amazing Drama of a Mad Scientist And a Composer who must Build a Husband in The Outback", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 7, - "RentalRate": 4.99, - "Length": 182, - "ReplacementCost": 11.99, - "Rating": "PG", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Behind the Scenes\"}", - "Fulltext": "'amaz':4 'build':15 'compos':12 'drama':5 'husband':17 'mad':8 'must':14 'outback':20 'record':1 'scientist':9 'zorro':2", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 15, - "Name": "Sports", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, - { - "ActorID": 114, - "FirstName": "Morgan", - "LastName": "Mcdormand", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 841, - "Title": "Star Operation", - "Description": "A Insightful Character Study of a Girl And a Car who must Pursue a Mad Cow in A Shark Tank", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 5, - "RentalRate": 2.99, - "Length": 181, - "ReplacementCost": 9.99, - "Rating": "PG", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries}", - "Fulltext": "'car':12 'charact':5 'cow':18 'girl':9 'insight':4 'mad':17 'must':14 'oper':2 'pursu':15 'shark':21 'star':1 'studi':6 'tank':22", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 15, - "Name": "Sports", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, { "ActorID": 116, "FirstName": "Dan", @@ -2611,7 +1247,10 @@ "ReplacementCost": 10.99, "Rating": "G", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Behind the Scenes" + ], "Fulltext": "'amistad':2 'bore':4 'catch':1 'discov':14 'feminist':11 'lumberjack':8 'must':13 'nigeria':18 'reflect':5 'woman':16", "Language": { "LanguageID": 1, @@ -2634,33 +1273,6 @@ "LastName": "Allen", "LastUpdate": "2013-05-26T14:47:57.62Z", "Films": [ - { - "FilmID": 141, - "Title": "Chicago North", - "Description": "A Fateful Yarn of a Mad Cow And a Waitress who must Battle a Student in California", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 4.99, - "Length": 185, - "ReplacementCost": 11.99, - "Rating": "PG-13", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\",\"Behind the Scenes\"}", - "Fulltext": "'battl':15 'california':19 'chicago':1 'cow':9 'fate':4 'mad':8 'must':14 'north':2 'student':17 'waitress':12 'yarn':5", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 10, - "Name": "Games", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - }, { "FilmID": 499, "Title": "King Evolution", @@ -2673,7 +1285,11 @@ "ReplacementCost": 24.99, "Rating": "NC-17", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Deleted Scenes\",\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Deleted Scenes", + "Behind the Scenes" + ], "Fulltext": "'action':5 'action-pack':4 'baloon':21 'boy':10 'chase':16 'evolut':2 'king':1 'lumberjack':13 'madman':18 'must':15 'pack':6 'tale':7", "Language": { "LanguageID": 1, @@ -2690,74 +1306,12 @@ } ] }, - { - "ActorID": 119, - "FirstName": "Warren", - "LastName": "Jackman", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 751, - "Title": "Runaway Tenenbaums", - "Description": "A Thoughtful Documentary of a Boat And a Man who must Meet a Boat in An Abandoned Fun House", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 0.99, - "Length": 181, - "ReplacementCost": 17.99, - "Rating": "NC-17", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries}", - "Fulltext": "'abandon':19 'boat':8,16 'documentari':5 'fun':20 'hous':21 'man':11 'meet':14 'must':13 'runaway':1 'tenenbaum':2 'thought':4", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 13, - "Name": "New", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, { "ActorID": 121, "FirstName": "Liza", "LastName": "Bergman", "LastUpdate": "2013-05-26T14:47:57.62Z", "Films": [ - { - "FilmID": 141, - "Title": "Chicago North", - "Description": "A Fateful Yarn of a Mad Cow And a Waitress who must Battle a Student in California", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 4.99, - "Length": 185, - "ReplacementCost": 11.99, - "Rating": "PG-13", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\",\"Behind the Scenes\"}", - "Fulltext": "'battl':15 'california':19 'chicago':1 'cow':9 'fate':4 'mad':8 'must':14 'north':2 'student':17 'waitress':12 'yarn':5", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 10, - "Name": "Games", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - }, { "FilmID": 198, "Title": "Crystal Breaking", @@ -2770,7 +1324,10 @@ "ReplacementCost": 22.99, "Rating": "NC-17", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,Commentaries}", + "SpecialFeatures": [ + "Trailers", + "Commentaries" + ], "Fulltext": "'ancient':22 'break':2 'charact':7 'chef':20 'crystal':1 'explor':14 'face':17 'fast':5 'fast-pac':4 'feminist':11 'japan':23 'must':16 'pace':6 'pastri':19 'studi':8", "Language": { "LanguageID": 1, @@ -2787,41 +1344,6 @@ } ] }, - { - "ActorID": 127, - "FirstName": "Kevin", - "LastName": "Garland", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 141, - "Title": "Chicago North", - "Description": "A Fateful Yarn of a Mad Cow And a Waitress who must Battle a Student in California", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 4.99, - "Length": 185, - "ReplacementCost": 11.99, - "Rating": "PG-13", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\",\"Behind the Scenes\"}", - "Fulltext": "'battl':15 'california':19 'chicago':1 'cow':9 'fate':4 'mad':8 'must':14 'north':2 'student':17 'waitress':12 'yarn':5", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 10, - "Name": "Games", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, { "ActorID": 128, "FirstName": "Cate", @@ -2840,7 +1362,12 @@ "ReplacementCost": 22.99, "Rating": "NC-17", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,Commentaries,\"Deleted Scenes\",\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Commentaries", + "Deleted Scenes", + "Behind the Scenes" + ], "Fulltext": "'ancient':21 'car':10 'fast':5 'fast-pac':4 'japan':22 'kill':17 'mad':13 'must':16 'pace':6 'scientist':14 'searcher':1 'tale':7 'wait':2 'woman':19", "Language": { "LanguageID": 1, @@ -2875,7 +1402,10 @@ "ReplacementCost": 12.99, "Rating": "G", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Deleted Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Deleted Scenes" + ], "Fulltext": "'compos':16 'drama':5 'epic':4 'feminist':8 'fool':2 'moonwalk':1 'must':13 'new':18 'orlean':19 'pioneer':11 'sink':14", "Language": { "LanguageID": 1, @@ -2910,7 +1440,11 @@ "ReplacementCost": 25.99, "Rating": "PG-13", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,Commentaries,\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Commentaries", + "Behind the Scenes" + ], "Fulltext": "'ancient':18 'battl':14 'boat':11 'china':19 'drama':5 'feminist':16 'must':13 'pond':1 'seattl':2 'stun':4 'teacher':8", "Language": { "LanguageID": 1, @@ -2927,179 +1461,12 @@ } ] }, - { - "ActorID": 135, - "FirstName": "Rita", - "LastName": "Reynolds", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 719, - "Title": "Records Zorro", - "Description": "A Amazing Drama of a Mad Scientist And a Composer who must Build a Husband in The Outback", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 7, - "RentalRate": 4.99, - "Length": 182, - "ReplacementCost": 11.99, - "Rating": "PG", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Behind the Scenes\"}", - "Fulltext": "'amaz':4 'build':15 'compos':12 'drama':5 'husband':17 'mad':8 'must':14 'outback':20 'record':1 'scientist':9 'zorro':2", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 15, - "Name": "Sports", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, - { - "ActorID": 137, - "FirstName": "Morgan", - "LastName": "Williams", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 841, - "Title": "Star Operation", - "Description": "A Insightful Character Study of a Girl And a Car who must Pursue a Mad Cow in A Shark Tank", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 5, - "RentalRate": 2.99, - "Length": 181, - "ReplacementCost": 9.99, - "Rating": "PG", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries}", - "Fulltext": "'car':12 'charact':5 'cow':18 'girl':9 'insight':4 'mad':17 'must':14 'oper':2 'pursu':15 'shark':21 'star':1 'studi':6 'tank':22", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 15, - "Name": "Sports", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, - { - "ActorID": 139, - "FirstName": "Ewan", - "LastName": "Gooding", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 719, - "Title": "Records Zorro", - "Description": "A Amazing Drama of a Mad Scientist And a Composer who must Build a Husband in The Outback", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 7, - "RentalRate": 4.99, - "Length": 182, - "ReplacementCost": 11.99, - "Rating": "PG", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Behind the Scenes\"}", - "Fulltext": "'amaz':4 'build':15 'compos':12 'drama':5 'husband':17 'mad':8 'must':14 'outback':20 'record':1 'scientist':9 'zorro':2", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 15, - "Name": "Sports", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, - { - "ActorID": 140, - "FirstName": "Whoopi", - "LastName": "Hurt", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 820, - "Title": "Sons Interview", - "Description": "A Taut Character Study of a Explorer And a Mad Cow who must Battle a Hunter in Ancient China", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 3, - "RentalRate": 2.99, - "Length": 184, - "ReplacementCost": 11.99, - "Rating": "NC-17", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries,\"Behind the Scenes\"}", - "Fulltext": "'ancient':20 'battl':16 'charact':5 'china':21 'cow':13 'explor':9 'hunter':18 'interview':2 'mad':12 'must':15 'son':1 'studi':6 'taut':4", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 2, - "Name": "Animation", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, { "ActorID": 141, "FirstName": "Cate", "LastName": "Harris", "LastUpdate": "2013-05-26T14:47:57.62Z", "Films": [ - { - "FilmID": 467, - "Title": "Intrigue Worst", - "Description": "A Fanciful Character Study of a Explorer And a Mad Scientist who must Vanquish a Squirrel in A Jet Boat", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 0.99, - "Length": 181, - "ReplacementCost": 10.99, - "Rating": "G", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\"}", - "Fulltext": "'boat':22 'charact':5 'explor':9 'fanci':4 'intrigu':1 'jet':21 'mad':12 'must':15 'scientist':13 'squirrel':18 'studi':6 'vanquish':16 'worst':2", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 9, - "Name": "Foreign", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - }, { "FilmID": 821, "Title": "Sorority Queen", @@ -3112,7 +1479,10 @@ "ReplacementCost": 17.99, "Rating": "NC-17", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Deleted Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Deleted Scenes" + ], "Fulltext": "'boat':23 'compos':13 'display':7 'fast':5 'fast-pac':4 'fight':16 'forens':18 'jet':22 'must':15 'pace':6 'psychologist':19 'queen':2 'soror':1 'squirrel':10", "Language": { "LanguageID": 1, @@ -3135,33 +1505,6 @@ "LastName": "Dean", "LastUpdate": "2013-05-26T14:47:57.62Z", "Films": [ - { - "FilmID": 141, - "Title": "Chicago North", - "Description": "A Fateful Yarn of a Mad Cow And a Waitress who must Battle a Student in California", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 4.99, - "Length": 185, - "ReplacementCost": 11.99, - "Rating": "PG-13", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\",\"Behind the Scenes\"}", - "Fulltext": "'battl':15 'california':19 'chicago':1 'cow':9 'fate':4 'mad':8 'must':14 'north':2 'student':17 'waitress':12 'yarn':5", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 10, - "Name": "Games", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - }, { "FilmID": 690, "Title": "Pond Seattle", @@ -3174,7 +1517,11 @@ "ReplacementCost": 25.99, "Rating": "PG-13", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,Commentaries,\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Commentaries", + "Behind the Scenes" + ], "Fulltext": "'ancient':18 'battl':14 'boat':11 'china':19 'drama':5 'feminist':16 'must':13 'pond':1 'seattl':2 'stun':4 'teacher':8", "Language": { "LanguageID": 1, @@ -3201,7 +1548,10 @@ "ReplacementCost": 17.99, "Rating": "NC-17", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Deleted Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Deleted Scenes" + ], "Fulltext": "'boat':23 'compos':13 'display':7 'fast':5 'fast-pac':4 'fight':16 'forens':18 'jet':22 'must':15 'pace':6 'psychologist':19 'queen':2 'soror':1 'squirrel':10", "Language": { "LanguageID": 1, @@ -3236,7 +1586,11 @@ "ReplacementCost": 16.99, "Rating": "PG-13", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Deleted Scenes\",\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Deleted Scenes", + "Behind the Scenes" + ], "Fulltext": "'baloon':20 'chef':17 'conquer':14 'frisco':2 'husband':11 'insight':4 'jacket':1 'must':13 'pastri':16 'reflect':5 'woman':8", "Language": { "LanguageID": 1, @@ -3253,41 +1607,6 @@ } ] }, - { - "ActorID": 146, - "FirstName": "Albert", - "LastName": "Johansson", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 591, - "Title": "Monsoon Cause", - "Description": "A Astounding Tale of a Crocodile And a Car who must Outrace a Squirrel in A U-Boat", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 4.99, - "Length": 182, - "ReplacementCost": 20.99, - "Rating": "PG", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries,\"Behind the Scenes\"}", - "Fulltext": "'astound':4 'boat':21 'car':11 'caus':2 'crocodil':8 'monsoon':1 'must':13 'outrac':14 'squirrel':16 'tale':5 'u':20 'u-boat':19", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 10, - "Name": "Games", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, { "ActorID": 152, "FirstName": "Ben", @@ -3306,7 +1625,10 @@ "ReplacementCost": 17.99, "Rating": "NC-17", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Deleted Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Deleted Scenes" + ], "Fulltext": "'boat':23 'compos':13 'display':7 'fast':5 'fast-pac':4 'fight':16 'forens':18 'jet':22 'must':15 'pace':6 'psychologist':19 'queen':2 'soror':1 'squirrel':10", "Language": { "LanguageID": 1, @@ -3341,7 +1663,10 @@ "ReplacementCost": 27.99, "Rating": "PG-13", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,Commentaries}", + "SpecialFeatures": [ + "Trailers", + "Commentaries" + ], "Fulltext": "'abandon':21 'awe':5 'awe-inspir':4 'conquer':16 'conspiraci':1 'crocodil':18 'frisbe':13 'inspir':6 'mine':22 'must':15 'shaft':23 'spirit':2 'stori':7 'student':10", "Language": { "LanguageID": 1, @@ -3358,68 +1683,6 @@ } ] }, - { - "ActorID": 154, - "FirstName": "Meryl", - "LastName": "Gibson", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 141, - "Title": "Chicago North", - "Description": "A Fateful Yarn of a Mad Cow And a Waitress who must Battle a Student in California", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 4.99, - "Length": 185, - "ReplacementCost": 11.99, - "Rating": "PG-13", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\",\"Behind the Scenes\"}", - "Fulltext": "'battl':15 'california':19 'chicago':1 'cow':9 'fate':4 'mad':8 'must':14 'north':2 'student':17 'waitress':12 'yarn':5", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 10, - "Name": "Games", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - }, - { - "FilmID": 467, - "Title": "Intrigue Worst", - "Description": "A Fanciful Character Study of a Explorer And a Mad Scientist who must Vanquish a Squirrel in A Jet Boat", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 0.99, - "Length": 181, - "ReplacementCost": 10.99, - "Rating": "G", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\"}", - "Fulltext": "'boat':22 'charact':5 'explor':9 'fanci':4 'intrigu':1 'jet':21 'mad':12 'must':15 'scientist':13 'squirrel':18 'studi':6 'vanquish':16 'worst':2", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 9, - "Name": "Foreign", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, { "ActorID": 155, "FirstName": "Ian", @@ -3438,7 +1701,10 @@ "ReplacementCost": 10.99, "Rating": "G", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Behind the Scenes" + ], "Fulltext": "'amistad':2 'bore':4 'catch':1 'discov':14 'feminist':11 'lumberjack':8 'must':13 'nigeria':18 'reflect':5 'woman':16", "Language": { "LanguageID": 1, @@ -3473,7 +1739,10 @@ "ReplacementCost": 22.99, "Rating": "NC-17", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,Commentaries}", + "SpecialFeatures": [ + "Trailers", + "Commentaries" + ], "Fulltext": "'ancient':22 'break':2 'charact':7 'chef':20 'crystal':1 'explor':14 'face':17 'fast':5 'fast-pac':4 'feminist':11 'japan':23 'must':16 'pace':6 'pastri':19 'studi':8", "Language": { "LanguageID": 1, @@ -3487,95 +1756,6 @@ "LastUpdate": "2006-02-15T09:46:27Z" } ] - }, - { - "FilmID": 349, - "Title": "Gangs Pride", - "Description": "A Taut Character Study of a Woman And a A Shark who must Confront a Frisbee in Berlin", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 4, - "RentalRate": 2.99, - "Length": 185, - "ReplacementCost": 27.99, - "Rating": "PG-13", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Behind the Scenes\"}", - "Fulltext": "'berlin':20 'charact':5 'confront':16 'frisbe':18 'gang':1 'must':15 'pride':2 'shark':13 'studi':6 'taut':4 'woman':9", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 2, - "Name": "Animation", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - }, - { - "FilmID": 467, - "Title": "Intrigue Worst", - "Description": "A Fanciful Character Study of a Explorer And a Mad Scientist who must Vanquish a Squirrel in A Jet Boat", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 0.99, - "Length": 181, - "ReplacementCost": 10.99, - "Rating": "G", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\"}", - "Fulltext": "'boat':22 'charact':5 'explor':9 'fanci':4 'intrigu':1 'jet':21 'mad':12 'must':15 'scientist':13 'squirrel':18 'studi':6 'vanquish':16 'worst':2", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 9, - "Name": "Foreign", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, - { - "ActorID": 157, - "FirstName": "Greta", - "LastName": "Malden", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 973, - "Title": "Wife Turn", - "Description": "A Awe-Inspiring Epistle of a Teacher And a Feminist who must Confront a Pioneer in Ancient Japan", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 3, - "RentalRate": 4.99, - "Length": 183, - "ReplacementCost": 27.99, - "Rating": "NC-17", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\",\"Behind the Scenes\"}", - "Fulltext": "'ancient':20 'awe':5 'awe-inspir':4 'confront':16 'epistl':7 'feminist':13 'inspir':6 'japan':21 'must':15 'pioneer':18 'teacher':10 'turn':2 'wife':1", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 6, - "Name": "Documentary", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] } ] }, @@ -3597,7 +1777,11 @@ "ReplacementCost": 16.99, "Rating": "PG-13", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Deleted Scenes\",\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Deleted Scenes", + "Behind the Scenes" + ], "Fulltext": "'baloon':20 'chef':17 'conquer':14 'frisco':2 'husband':11 'insight':4 'jacket':1 'must':13 'pastri':16 'reflect':5 'woman':8", "Language": { "LanguageID": 1, @@ -3614,76 +1798,6 @@ } ] }, - { - "ActorID": 160, - "FirstName": "Chris", - "LastName": "Depp", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 767, - "Title": "Scalawag Duck", - "Description": "A Fateful Reflection of a Car And a Teacher who must Confront a Waitress in A Monastery", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 4.99, - "Length": 183, - "ReplacementCost": 13.99, - "Rating": "NC-17", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries,\"Behind the Scenes\"}", - "Fulltext": "'car':8 'confront':14 'duck':2 'fate':4 'monasteri':19 'must':13 'reflect':5 'scalawag':1 'teacher':11 'waitress':16", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 12, - "Name": "Music", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, - { - "ActorID": 161, - "FirstName": "Harvey", - "LastName": "Hope", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 340, - "Title": "Frontier Cabin", - "Description": "A Emotional Story of a Madman And a Waitress who must Battle a Teacher in An Abandoned Fun House", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 4.99, - "Length": 183, - "ReplacementCost": 14.99, - "Rating": "PG-13", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries,\"Deleted Scenes\"}", - "Fulltext": "'abandon':19 'battl':14 'cabin':2 'emot':4 'frontier':1 'fun':20 'hous':21 'madman':8 'must':13 'stori':5 'teacher':16 'waitress':11", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 13, - "Name": "New", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, { "ActorID": 163, "FirstName": "Christopher", @@ -3702,7 +1816,10 @@ "ReplacementCost": 27.99, "Rating": "PG-13", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,Commentaries}", + "SpecialFeatures": [ + "Trailers", + "Commentaries" + ], "Fulltext": "'abandon':21 'awe':5 'awe-inspir':4 'conquer':16 'conspiraci':1 'crocodil':18 'frisbe':13 'inspir':6 'mine':22 'must':15 'shaft':23 'spirit':2 'stori':7 'student':10", "Language": { "LanguageID": 1, @@ -3717,33 +1834,6 @@ } ] }, - { - "FilmID": 719, - "Title": "Records Zorro", - "Description": "A Amazing Drama of a Mad Scientist And a Composer who must Build a Husband in The Outback", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 7, - "RentalRate": 4.99, - "Length": 182, - "ReplacementCost": 11.99, - "Rating": "PG", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Behind the Scenes\"}", - "Fulltext": "'amaz':4 'build':15 'compos':12 'drama':5 'husband':17 'mad':8 'must':14 'outback':20 'record':1 'scientist':9 'zorro':2", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 15, - "Name": "Sports", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - }, { "FilmID": 996, "Title": "Young Language", @@ -3756,7 +1846,10 @@ "ReplacementCost": 9.99, "Rating": "G", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Behind the Scenes" + ], "Fulltext": "'administr':12 'boat':8 'boy':17 'databas':11 'first':20 'languag':2 'man':21 'meet':15 'must':14 'space':22 'station':23 'unbeliev':4 'yarn':5 'young':1", "Language": { "LanguageID": 1, @@ -3773,41 +1866,6 @@ } ] }, - { - "ActorID": 164, - "FirstName": "Humphrey", - "LastName": "Willis", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 820, - "Title": "Sons Interview", - "Description": "A Taut Character Study of a Explorer And a Mad Cow who must Battle a Hunter in Ancient China", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 3, - "RentalRate": 2.99, - "Length": 184, - "ReplacementCost": 11.99, - "Rating": "NC-17", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries,\"Behind the Scenes\"}", - "Fulltext": "'ancient':20 'battl':16 'charact':5 'china':21 'cow':13 'explor':9 'hunter':18 'interview':2 'mad':12 'must':15 'son':1 'studi':6 'taut':4", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 2, - "Name": "Animation", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, { "ActorID": 165, "FirstName": "Al", @@ -3826,7 +1884,11 @@ "ReplacementCost": 16.99, "Rating": "PG-13", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Deleted Scenes\",\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Deleted Scenes", + "Behind the Scenes" + ], "Fulltext": "'baloon':20 'chef':17 'conquer':14 'frisco':2 'husband':11 'insight':4 'jacket':1 'must':13 'pastri':16 'reflect':5 'woman':8", "Language": { "LanguageID": 1, @@ -3843,103 +1905,6 @@ } ] }, - { - "ActorID": 168, - "FirstName": "Will", - "LastName": "Wilson", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 841, - "Title": "Star Operation", - "Description": "A Insightful Character Study of a Girl And a Car who must Pursue a Mad Cow in A Shark Tank", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 5, - "RentalRate": 2.99, - "Length": 181, - "ReplacementCost": 9.99, - "Rating": "PG", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries}", - "Fulltext": "'car':12 'charact':5 'cow':18 'girl':9 'insight':4 'mad':17 'must':14 'oper':2 'pursu':15 'shark':21 'star':1 'studi':6 'tank':22", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 15, - "Name": "Sports", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - }, - { - "FilmID": 886, - "Title": "Theory Mermaid", - "Description": "A Fateful Yarn of a Composer And a Monkey who must Vanquish a Womanizer in The First Manned Space Station", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 5, - "RentalRate": 0.99, - "Length": 184, - "ReplacementCost": 9.99, - "Rating": "PG-13", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\",\"Behind the Scenes\"}", - "Fulltext": "'compos':8 'fate':4 'first':19 'man':20 'mermaid':2 'monkey':11 'must':13 'space':21 'station':22 'theori':1 'vanquish':14 'woman':16 'yarn':5", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 2, - "Name": "Animation", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, - { - "ActorID": 169, - "FirstName": "Kenneth", - "LastName": "Hoffman", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 349, - "Title": "Gangs Pride", - "Description": "A Taut Character Study of a Woman And a A Shark who must Confront a Frisbee in Berlin", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 4, - "RentalRate": 2.99, - "Length": 185, - "ReplacementCost": 27.99, - "Rating": "PG-13", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Behind the Scenes\"}", - "Fulltext": "'berlin':20 'charact':5 'confront':16 'frisbe':18 'gang':1 'must':15 'pride':2 'shark':13 'studi':6 'taut':4 'woman':9", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 2, - "Name": "Animation", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, { "ActorID": 170, "FirstName": "Mena", @@ -3958,7 +1923,10 @@ "ReplacementCost": 27.99, "Rating": "PG-13", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,Commentaries}", + "SpecialFeatures": [ + "Trailers", + "Commentaries" + ], "Fulltext": "'abandon':21 'awe':5 'awe-inspir':4 'conquer':16 'conspiraci':1 'crocodil':18 'frisbe':13 'inspir':6 'mine':22 'must':15 'shaft':23 'spirit':2 'stori':7 'student':10", "Language": { "LanguageID": 1, @@ -3973,33 +1941,6 @@ } ] }, - { - "FilmID": 886, - "Title": "Theory Mermaid", - "Description": "A Fateful Yarn of a Composer And a Monkey who must Vanquish a Womanizer in The First Manned Space Station", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 5, - "RentalRate": 0.99, - "Length": 184, - "ReplacementCost": 9.99, - "Rating": "PG-13", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\",\"Behind the Scenes\"}", - "Fulltext": "'compos':8 'fate':4 'first':19 'man':20 'mermaid':2 'monkey':11 'must':13 'space':21 'station':22 'theori':1 'vanquish':14 'woman':16 'yarn':5", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 2, - "Name": "Animation", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - }, { "FilmID": 996, "Title": "Young Language", @@ -4012,7 +1953,10 @@ "ReplacementCost": 9.99, "Rating": "G", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Behind the Scenes" + ], "Fulltext": "'administr':12 'boat':8 'boy':17 'databas':11 'first':20 'languag':2 'man':21 'meet':15 'must':14 'space':22 'station':23 'unbeliev':4 'yarn':5 'young':1", "Language": { "LanguageID": 1, @@ -4029,235 +1973,6 @@ } ] }, - { - "ActorID": 172, - "FirstName": "Groucho", - "LastName": "Williams", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 609, - "Title": "Muscle Bright", - "Description": "A Stunning Panorama of a Sumo Wrestler And a Husband who must Redeem a Madman in Ancient India", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 7, - "RentalRate": 2.99, - "Length": 185, - "ReplacementCost": 23.99, - "Rating": "G", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\"}", - "Fulltext": "'ancient':19 'bright':2 'husband':12 'india':20 'madman':17 'muscl':1 'must':14 'panorama':5 'redeem':15 'stun':4 'sumo':8 'wrestler':9", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 16, - "Name": "Travel", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, - { - "ActorID": 175, - "FirstName": "William", - "LastName": "Hackman", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 591, - "Title": "Monsoon Cause", - "Description": "A Astounding Tale of a Crocodile And a Car who must Outrace a Squirrel in A U-Boat", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 4.99, - "Length": 182, - "ReplacementCost": 20.99, - "Rating": "PG", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries,\"Behind the Scenes\"}", - "Fulltext": "'astound':4 'boat':21 'car':11 'caus':2 'crocodil':8 'monsoon':1 'must':13 'outrac':14 'squirrel':16 'tale':5 'u':20 'u-boat':19", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 10, - "Name": "Games", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - }, - { - "FilmID": 719, - "Title": "Records Zorro", - "Description": "A Amazing Drama of a Mad Scientist And a Composer who must Build a Husband in The Outback", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 7, - "RentalRate": 4.99, - "Length": 182, - "ReplacementCost": 11.99, - "Rating": "PG", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Behind the Scenes\"}", - "Fulltext": "'amaz':4 'build':15 'compos':12 'drama':5 'husband':17 'mad':8 'must':14 'outback':20 'record':1 'scientist':9 'zorro':2", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 15, - "Name": "Sports", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, - { - "ActorID": 177, - "FirstName": "Gene", - "LastName": "Mckellen", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 751, - "Title": "Runaway Tenenbaums", - "Description": "A Thoughtful Documentary of a Boat And a Man who must Meet a Boat in An Abandoned Fun House", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 0.99, - "Length": 181, - "ReplacementCost": 17.99, - "Rating": "NC-17", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries}", - "Fulltext": "'abandon':19 'boat':8,16 'documentari':5 'fun':20 'hous':21 'man':11 'meet':14 'must':13 'runaway':1 'tenenbaum':2 'thought':4", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 13, - "Name": "New", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, - { - "ActorID": 180, - "FirstName": "Jeff", - "LastName": "Silverstone", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 609, - "Title": "Muscle Bright", - "Description": "A Stunning Panorama of a Sumo Wrestler And a Husband who must Redeem a Madman in Ancient India", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 7, - "RentalRate": 2.99, - "Length": 185, - "ReplacementCost": 23.99, - "Rating": "G", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\"}", - "Fulltext": "'ancient':19 'bright':2 'husband':12 'india':20 'madman':17 'muscl':1 'must':14 'panorama':5 'redeem':15 'stun':4 'sumo':8 'wrestler':9", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 16, - "Name": "Travel", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - }, - { - "FilmID": 820, - "Title": "Sons Interview", - "Description": "A Taut Character Study of a Explorer And a Mad Cow who must Battle a Hunter in Ancient China", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 3, - "RentalRate": 2.99, - "Length": 184, - "ReplacementCost": 11.99, - "Rating": "NC-17", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries,\"Behind the Scenes\"}", - "Fulltext": "'ancient':20 'battl':16 'charact':5 'china':21 'cow':13 'explor':9 'hunter':18 'interview':2 'mad':12 'must':15 'son':1 'studi':6 'taut':4", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 2, - "Name": "Animation", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, - { - "ActorID": 181, - "FirstName": "Matthew", - "LastName": "Carrey", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 609, - "Title": "Muscle Bright", - "Description": "A Stunning Panorama of a Sumo Wrestler And a Husband who must Redeem a Madman in Ancient India", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 7, - "RentalRate": 2.99, - "Length": 185, - "ReplacementCost": 23.99, - "Rating": "G", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\"}", - "Fulltext": "'ancient':19 'bright':2 'husband':12 'india':20 'madman':17 'muscl':1 'must':14 'panorama':5 'redeem':15 'stun':4 'sumo':8 'wrestler':9", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 16, - "Name": "Travel", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, { "ActorID": 184, "FirstName": "Humphrey", @@ -4276,7 +1991,10 @@ "ReplacementCost": 12.99, "Rating": "G", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Deleted Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Deleted Scenes" + ], "Fulltext": "'compos':16 'drama':5 'epic':4 'feminist':8 'fool':2 'moonwalk':1 'must':13 'new':18 'orlean':19 'pioneer':11 'sink':14", "Language": { "LanguageID": 1, @@ -4293,101 +2011,12 @@ } ] }, - { - "ActorID": 185, - "FirstName": "Michael", - "LastName": "Bolger", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 510, - "Title": "Lawless Vision", - "Description": "A Insightful Yarn of a Boy And a Sumo Wrestler who must Outgun a Car in The Outback", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 4.99, - "Length": 181, - "ReplacementCost": 29.99, - "Rating": "G", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\",\"Behind the Scenes\"}", - "Fulltext": "'boy':8 'car':17 'insight':4 'lawless':1 'must':14 'outback':20 'outgun':15 'sumo':11 'vision':2 'wrestler':12 'yarn':5", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 2, - "Name": "Animation", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - }, - { - "FilmID": 973, - "Title": "Wife Turn", - "Description": "A Awe-Inspiring Epistle of a Teacher And a Feminist who must Confront a Pioneer in Ancient Japan", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 3, - "RentalRate": 4.99, - "Length": 183, - "ReplacementCost": 27.99, - "Rating": "NC-17", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\",\"Behind the Scenes\"}", - "Fulltext": "'ancient':20 'awe':5 'awe-inspir':4 'confront':16 'epistl':7 'feminist':13 'inspir':6 'japan':21 'must':15 'pioneer':18 'teacher':10 'turn':2 'wife':1", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 6, - "Name": "Documentary", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, { "ActorID": 187, "FirstName": "Renee", "LastName": "Ball", "LastUpdate": "2013-05-26T14:47:57.62Z", "Films": [ - { - "FilmID": 435, - "Title": "Hotel Happiness", - "Description": "A Thrilling Yarn of a Pastry Chef And a A Shark who must Challenge a Mad Scientist in The Outback", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 4.99, - "Length": 181, - "ReplacementCost": 28.99, - "Rating": "PG-13", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Behind the Scenes\"}", - "Fulltext": "'challeng':16 'chef':9 'happi':2 'hotel':1 'mad':18 'must':15 'outback':22 'pastri':8 'scientist':19 'shark':13 'thrill':4 'yarn':5", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 9, - "Name": "Foreign", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - }, { "FilmID": 499, "Title": "King Evolution", @@ -4400,7 +2029,11 @@ "ReplacementCost": 24.99, "Rating": "NC-17", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Deleted Scenes\",\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Deleted Scenes", + "Behind the Scenes" + ], "Fulltext": "'action':5 'action-pack':4 'baloon':21 'boy':10 'chase':16 'evolut':2 'king':1 'lumberjack':13 'madman':18 'must':15 'pack':6 'tale':7", "Language": { "LanguageID": 1, @@ -4435,7 +2068,12 @@ "ReplacementCost": 22.99, "Rating": "NC-17", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,Commentaries,\"Deleted Scenes\",\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Commentaries", + "Deleted Scenes", + "Behind the Scenes" + ], "Fulltext": "'ancient':21 'car':10 'fast':5 'fast-pac':4 'japan':22 'kill':17 'mad':13 'must':16 'pace':6 'scientist':14 'searcher':1 'tale':7 'wait':2 'woman':19", "Language": { "LanguageID": 1, @@ -4452,146 +2090,6 @@ } ] }, - { - "ActorID": 189, - "FirstName": "Cuba", - "LastName": "Birch", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 820, - "Title": "Sons Interview", - "Description": "A Taut Character Study of a Explorer And a Mad Cow who must Battle a Hunter in Ancient China", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 3, - "RentalRate": 2.99, - "Length": 184, - "ReplacementCost": 11.99, - "Rating": "NC-17", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries,\"Behind the Scenes\"}", - "Fulltext": "'ancient':20 'battl':16 'charact':5 'china':21 'cow':13 'explor':9 'hunter':18 'interview':2 'mad':12 'must':15 'son':1 'studi':6 'taut':4", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 2, - "Name": "Animation", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, - { - "ActorID": 193, - "FirstName": "Burt", - "LastName": "Temple", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 141, - "Title": "Chicago North", - "Description": "A Fateful Yarn of a Mad Cow And a Waitress who must Battle a Student in California", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 4.99, - "Length": 185, - "ReplacementCost": 11.99, - "Rating": "PG-13", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\",\"Behind the Scenes\"}", - "Fulltext": "'battl':15 'california':19 'chicago':1 'cow':9 'fate':4 'mad':8 'must':14 'north':2 'student':17 'waitress':12 'yarn':5", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 10, - "Name": "Games", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, - { - "ActorID": 194, - "FirstName": "Meryl", - "LastName": "Allen", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 719, - "Title": "Records Zorro", - "Description": "A Amazing Drama of a Mad Scientist And a Composer who must Build a Husband in The Outback", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 7, - "RentalRate": 4.99, - "Length": 182, - "ReplacementCost": 11.99, - "Rating": "PG", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Behind the Scenes\"}", - "Fulltext": "'amaz':4 'build':15 'compos':12 'drama':5 'husband':17 'mad':8 'must':14 'outback':20 'record':1 'scientist':9 'zorro':2", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 15, - "Name": "Sports", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, - { - "ActorID": 195, - "FirstName": "Jayne", - "LastName": "Silverstone", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 141, - "Title": "Chicago North", - "Description": "A Fateful Yarn of a Mad Cow And a Waitress who must Battle a Student in California", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 4.99, - "Length": 185, - "ReplacementCost": 11.99, - "Rating": "PG-13", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\",\"Behind the Scenes\"}", - "Fulltext": "'battl':15 'california':19 'chicago':1 'cow':9 'fate':4 'mad':8 'must':14 'north':2 'student':17 'waitress':12 'yarn':5", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 10, - "Name": "Games", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, { "ActorID": 196, "FirstName": "Bela", @@ -4610,7 +2108,11 @@ "ReplacementCost": 16.99, "Rating": "PG-13", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Deleted Scenes\",\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Deleted Scenes", + "Behind the Scenes" + ], "Fulltext": "'baloon':20 'chef':17 'conquer':14 'frisco':2 'husband':11 'insight':4 'jacket':1 'must':13 'pastri':16 'reflect':5 'woman':8", "Language": { "LanguageID": 1, @@ -4645,7 +2147,11 @@ "ReplacementCost": 24.99, "Rating": "NC-17", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Deleted Scenes\",\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Deleted Scenes", + "Behind the Scenes" + ], "Fulltext": "'action':5 'action-pack':4 'baloon':21 'boy':10 'chase':16 'evolut':2 'king':1 'lumberjack':13 'madman':18 'must':15 'pack':6 'tale':7", "Language": { "LanguageID": 1, @@ -4672,7 +2178,10 @@ "ReplacementCost": 12.99, "Rating": "G", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Deleted Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Deleted Scenes" + ], "Fulltext": "'compos':16 'drama':5 'epic':4 'feminist':8 'fool':2 'moonwalk':1 'must':13 'new':18 'orlean':19 'pioneer':11 'sink':14", "Language": { "LanguageID": 1, @@ -4686,68 +2195,6 @@ "LastUpdate": "2006-02-15T09:46:27Z" } ] - }, - { - "FilmID": 886, - "Title": "Theory Mermaid", - "Description": "A Fateful Yarn of a Composer And a Monkey who must Vanquish a Womanizer in The First Manned Space Station", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 5, - "RentalRate": 0.99, - "Length": 184, - "ReplacementCost": 9.99, - "Rating": "PG-13", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\",\"Behind the Scenes\"}", - "Fulltext": "'compos':8 'fate':4 'first':19 'man':20 'mermaid':2 'monkey':11 'must':13 'space':21 'station':22 'theori':1 'vanquish':14 'woman':16 'yarn':5", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 2, - "Name": "Animation", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] - } - ] - }, - { - "ActorID": 199, - "FirstName": "Julia", - "LastName": "Fawcett", - "LastUpdate": "2013-05-26T14:47:57.62Z", - "Films": [ - { - "FilmID": 886, - "Title": "Theory Mermaid", - "Description": "A Fateful Yarn of a Composer And a Monkey who must Vanquish a Womanizer in The First Manned Space Station", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 5, - "RentalRate": 0.99, - "Length": 184, - "ReplacementCost": 9.99, - "Rating": "PG-13", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\",\"Behind the Scenes\"}", - "Fulltext": "'compos':8 'fate':4 'first':19 'man':20 'mermaid':2 'monkey':11 'must':13 'space':21 'station':22 'theori':1 'vanquish':14 'woman':16 'yarn':5", - "Language": { - "LanguageID": 1, - "Name": "English ", - "LastUpdate": "0001-01-01T00:00:00Z" - }, - "Categories": [ - { - "CategoryID": 2, - "Name": "Animation", - "LastUpdate": "2006-02-15T09:46:27Z" - } - ] } ] } diff --git a/examples/quick-start/dest2.json b/examples/quick-start/dest2.json index 9cd444f..45f3930 100644 --- a/examples/quick-start/dest2.json +++ b/examples/quick-start/dest2.json @@ -16,23 +16,12 @@ "ReplacementCost": 24.99, "Rating": "NC-17", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Deleted Scenes\",\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Deleted Scenes", + "Behind the Scenes" + ], "Fulltext": "'action':5 'action-pack':4 'baloon':21 'boy':10 'chase':16 'evolut':2 'king':1 'lumberjack':13 'madman':18 'must':15 'pack':6 'tale':7" - }, - { - "FilmID": 50, - "Title": "Baked Cleopatra", - "Description": "A Stunning Drama of a Forensic Psychologist And a Husband who must Overcome a Waitress in A Monastery", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 3, - "RentalRate": 2.99, - "Length": 182, - "ReplacementCost": 20.99, - "Rating": "G", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries,\"Behind the Scenes\"}", - "Fulltext": "'bake':1 'cleopatra':2 'drama':5 'forens':8 'husband':12 'monasteri':20 'must':14 'overcom':15 'psychologist':9 'stun':4 'waitress':17" } ], "Actors": [ @@ -54,12 +43,6 @@ "LastName": "Dukakis", "LastUpdate": "2013-05-26T14:47:57.62Z" }, - { - "ActorID": 70, - "FirstName": "Michelle", - "LastName": "Mcconaughey", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, { "ActorID": 118, "FirstName": "Cuba", @@ -97,23 +80,11 @@ "ReplacementCost": 9.99, "Rating": "G", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Behind the Scenes" + ], "Fulltext": "'administr':12 'boat':8 'boy':17 'databas':11 'first':20 'languag':2 'man':21 'meet':15 'must':14 'space':22 'station':23 'unbeliev':4 'yarn':5 'young':1" - }, - { - "FilmID": 973, - "Title": "Wife Turn", - "Description": "A Awe-Inspiring Epistle of a Teacher And a Feminist who must Confront a Pioneer in Ancient Japan", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 3, - "RentalRate": 4.99, - "Length": 183, - "ReplacementCost": 27.99, - "Rating": "NC-17", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\",\"Behind the Scenes\"}", - "Fulltext": "'ancient':20 'awe':5 'awe-inspir':4 'confront':16 'epistl':7 'feminist':13 'inspir':6 'japan':21 'must':15 'pioneer':18 'teacher':10 'turn':2 'wife':1" } ], "Actors": [ @@ -129,42 +100,12 @@ "LastName": "Mcqueen", "LastUpdate": "2013-05-26T14:47:57.62Z" }, - { - "ActorID": 28, - "FirstName": "Woody", - "LastName": "Hoffman", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 47, - "FirstName": "Julia", - "LastName": "Barrymore", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, { "ActorID": 84, "FirstName": "James", "LastName": "Pitt", "LastUpdate": "2013-05-26T14:47:57.62Z" }, - { - "ActorID": 107, - "FirstName": "Gina", - "LastName": "Degeneres", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 111, - "FirstName": "Cameron", - "LastName": "Zellweger", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 157, - "FirstName": "Greta", - "LastName": "Malden", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, { "ActorID": 163, "FirstName": "Christopher", @@ -176,12 +117,6 @@ "FirstName": "Mena", "LastName": "Hopper", "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 185, - "FirstName": "Michael", - "LastName": "Bolger", - "LastUpdate": "2013-05-26T14:47:57.62Z" } ] }, @@ -202,23 +137,11 @@ "ReplacementCost": 23.99, "Rating": "PG-13", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Behind the Scenes" + ], "Fulltext": "'georgia':20 'lacklustur':4 'monkey':17 'must':14 'pocus':2 'red':1 'redeem':15 'soviet':19 'squirrel':12 'sumo':8 'wrestler':9 'yarn':5" - }, - { - "FilmID": 767, - "Title": "Scalawag Duck", - "Description": "A Fateful Reflection of a Car And a Teacher who must Confront a Waitress in A Monastery", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 4.99, - "Length": 183, - "ReplacementCost": 13.99, - "Rating": "NC-17", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries,\"Behind the Scenes\"}", - "Fulltext": "'car':8 'confront':14 'duck':2 'fate':4 'monasteri':19 'must':13 'reflect':5 'scalawag':1 'teacher':11 'waitress':16" } ], "Actors": [ @@ -234,30 +157,6 @@ "LastName": "Degeneres", "LastUpdate": "2013-05-26T14:47:57.62Z" }, - { - "ActorID": 45, - "FirstName": "Reese", - "LastName": "Kilmer", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 57, - "FirstName": "Jude", - "LastName": "Cruise", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 61, - "FirstName": "Christian", - "LastName": "Neeson", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 78, - "FirstName": "Groucho", - "LastName": "Sinatra", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, { "ActorID": 87, "FirstName": "Spencer", @@ -275,444 +174,6 @@ "FirstName": "Warren", "LastName": "Nolte", "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 160, - "FirstName": "Chris", - "LastName": "Depp", - "LastUpdate": "2013-05-26T14:47:57.62Z" - } - ] - }, - { - "CategoryID": 13, - "Name": "New", - "LastUpdate": "2006-02-15T09:46:27Z", - "Films": [ - { - "FilmID": 340, - "Title": "Frontier Cabin", - "Description": "A Emotional Story of a Madman And a Waitress who must Battle a Teacher in An Abandoned Fun House", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 4.99, - "Length": 183, - "ReplacementCost": 14.99, - "Rating": "PG-13", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries,\"Deleted Scenes\"}", - "Fulltext": "'abandon':19 'battl':14 'cabin':2 'emot':4 'frontier':1 'fun':20 'hous':21 'madman':8 'must':13 'stori':5 'teacher':16 'waitress':11" - }, - { - "FilmID": 751, - "Title": "Runaway Tenenbaums", - "Description": "A Thoughtful Documentary of a Boat And a Man who must Meet a Boat in An Abandoned Fun House", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 0.99, - "Length": 181, - "ReplacementCost": 17.99, - "Rating": "NC-17", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries}", - "Fulltext": "'abandon':19 'boat':8,16 'documentari':5 'fun':20 'hous':21 'man':11 'meet':14 'must':13 'runaway':1 'tenenbaum':2 'thought':4" - } - ], - "Actors": [ - { - "ActorID": 5, - "FirstName": "Johnny", - "LastName": "Lollobrigida", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 26, - "FirstName": "Rip", - "LastName": "Crawford", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 44, - "FirstName": "Nick", - "LastName": "Stallone", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 55, - "FirstName": "Fay", - "LastName": "Kilmer", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 57, - "FirstName": "Jude", - "LastName": "Cruise", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 83, - "FirstName": "Ben", - "LastName": "Willis", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 119, - "FirstName": "Warren", - "LastName": "Jackman", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 161, - "FirstName": "Harvey", - "LastName": "Hope", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 177, - "FirstName": "Gene", - "LastName": "Mckellen", - "LastUpdate": "2013-05-26T14:47:57.62Z" - } - ] - }, - { - "CategoryID": 15, - "Name": "Sports", - "LastUpdate": "2006-02-15T09:46:27Z", - "Films": [ - { - "FilmID": 841, - "Title": "Star Operation", - "Description": "A Insightful Character Study of a Girl And a Car who must Pursue a Mad Cow in A Shark Tank", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 5, - "RentalRate": 2.99, - "Length": 181, - "ReplacementCost": 9.99, - "Rating": "PG", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries}", - "Fulltext": "'car':12 'charact':5 'cow':18 'girl':9 'insight':4 'mad':17 'must':14 'oper':2 'pursu':15 'shark':21 'star':1 'studi':6 'tank':22" - }, - { - "FilmID": 719, - "Title": "Records Zorro", - "Description": "A Amazing Drama of a Mad Scientist And a Composer who must Build a Husband in The Outback", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 7, - "RentalRate": 4.99, - "Length": 182, - "ReplacementCost": 11.99, - "Rating": "PG", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Behind the Scenes\"}", - "Fulltext": "'amaz':4 'build':15 'compos':12 'drama':5 'husband':17 'mad':8 'must':14 'outback':20 'record':1 'scientist':9 'zorro':2" - } - ], - "Actors": [ - { - "ActorID": 5, - "FirstName": "Johnny", - "LastName": "Lollobrigida", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 62, - "FirstName": "Jayne", - "LastName": "Neeson", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 83, - "FirstName": "Ben", - "LastName": "Willis", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 101, - "FirstName": "Susan", - "LastName": "Davis", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 113, - "FirstName": "Morgan", - "LastName": "Hopkins", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 114, - "FirstName": "Morgan", - "LastName": "Mcdormand", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 135, - "FirstName": "Rita", - "LastName": "Reynolds", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 137, - "FirstName": "Morgan", - "LastName": "Williams", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 139, - "FirstName": "Ewan", - "LastName": "Gooding", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 163, - "FirstName": "Christopher", - "LastName": "West", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 168, - "FirstName": "Will", - "LastName": "Wilson", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 175, - "FirstName": "William", - "LastName": "Hackman", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 194, - "FirstName": "Meryl", - "LastName": "Allen", - "LastUpdate": "2013-05-26T14:47:57.62Z" - } - ] - }, - { - "CategoryID": 2, - "Name": "Animation", - "LastUpdate": "2006-02-15T09:46:27Z", - "Films": [ - { - "FilmID": 510, - "Title": "Lawless Vision", - "Description": "A Insightful Yarn of a Boy And a Sumo Wrestler who must Outgun a Car in The Outback", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 4.99, - "Length": 181, - "ReplacementCost": 29.99, - "Rating": "G", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\",\"Behind the Scenes\"}", - "Fulltext": "'boy':8 'car':17 'insight':4 'lawless':1 'must':14 'outback':20 'outgun':15 'sumo':11 'vision':2 'wrestler':12 'yarn':5" - }, - { - "FilmID": 886, - "Title": "Theory Mermaid", - "Description": "A Fateful Yarn of a Composer And a Monkey who must Vanquish a Womanizer in The First Manned Space Station", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 5, - "RentalRate": 0.99, - "Length": 184, - "ReplacementCost": 9.99, - "Rating": "PG-13", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\",\"Behind the Scenes\"}", - "Fulltext": "'compos':8 'fate':4 'first':19 'man':20 'mermaid':2 'monkey':11 'must':13 'space':21 'station':22 'theori':1 'vanquish':14 'woman':16 'yarn':5" - }, - { - "FilmID": 349, - "Title": "Gangs Pride", - "Description": "A Taut Character Study of a Woman And a A Shark who must Confront a Frisbee in Berlin", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 4, - "RentalRate": 2.99, - "Length": 185, - "ReplacementCost": 27.99, - "Rating": "PG-13", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Behind the Scenes\"}", - "Fulltext": "'berlin':20 'charact':5 'confront':16 'frisbe':18 'gang':1 'must':15 'pride':2 'shark':13 'studi':6 'taut':4 'woman':9" - }, - { - "FilmID": 820, - "Title": "Sons Interview", - "Description": "A Taut Character Study of a Explorer And a Mad Cow who must Battle a Hunter in Ancient China", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 3, - "RentalRate": 2.99, - "Length": 184, - "ReplacementCost": 11.99, - "Rating": "NC-17", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries,\"Behind the Scenes\"}", - "Fulltext": "'ancient':20 'battl':16 'charact':5 'china':21 'cow':13 'explor':9 'hunter':18 'interview':2 'mad':12 'must':15 'son':1 'studi':6 'taut':4" - }, - { - "FilmID": 690, - "Title": "Pond Seattle", - "Description": "A Stunning Drama of a Teacher And a Boat who must Battle a Feminist in Ancient China", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 7, - "RentalRate": 2.99, - "Length": 185, - "ReplacementCost": 25.99, - "Rating": "PG-13", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,Commentaries,\"Behind the Scenes\"}", - "Fulltext": "'ancient':18 'battl':14 'boat':11 'china':19 'drama':5 'feminist':16 'must':13 'pond':1 'seattl':2 'stun':4 'teacher':8" - } - ], - "Actors": [ - { - "ActorID": 9, - "FirstName": "Joe", - "LastName": "Swank", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 15, - "FirstName": "Cuba", - "LastName": "Olivier", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 16, - "FirstName": "Fred", - "LastName": "Costner", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 19, - "FirstName": "Bob", - "LastName": "Fawcett", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 22, - "FirstName": "Elvis", - "LastName": "Marx", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 23, - "FirstName": "Sandra", - "LastName": "Kilmer", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 46, - "FirstName": "Parker", - "LastName": "Goldberg", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 48, - "FirstName": "Frances", - "LastName": "Day-Lewis", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 54, - "FirstName": "Penelope", - "LastName": "Pinkett", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 95, - "FirstName": "Daryl", - "LastName": "Wahlberg", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 134, - "FirstName": "Gene", - "LastName": "Hopkins", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 140, - "FirstName": "Whoopi", - "LastName": "Hurt", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 143, - "FirstName": "River", - "LastName": "Dean", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 156, - "FirstName": "Fay", - "LastName": "Wood", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 164, - "FirstName": "Humphrey", - "LastName": "Willis", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 168, - "FirstName": "Will", - "LastName": "Wilson", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 169, - "FirstName": "Kenneth", - "LastName": "Hoffman", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 170, - "FirstName": "Mena", - "LastName": "Hopper", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 180, - "FirstName": "Jeff", - "LastName": "Silverstone", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 185, - "FirstName": "Michael", - "LastName": "Bolger", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 189, - "FirstName": "Cuba", - "LastName": "Birch", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 198, - "FirstName": "Mary", - "LastName": "Keitel", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 199, - "FirstName": "Julia", - "LastName": "Fawcett", - "LastUpdate": "2013-05-26T14:47:57.62Z" } ] }, @@ -733,38 +194,11 @@ "ReplacementCost": 12.99, "Rating": "G", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Deleted Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Deleted Scenes" + ], "Fulltext": "'compos':16 'drama':5 'epic':4 'feminist':8 'fool':2 'moonwalk':1 'must':13 'new':18 'orlean':19 'pioneer':11 'sink':14" - }, - { - "FilmID": 591, - "Title": "Monsoon Cause", - "Description": "A Astounding Tale of a Crocodile And a Car who must Outrace a Squirrel in A U-Boat", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 4.99, - "Length": 182, - "ReplacementCost": 20.99, - "Rating": "PG", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries,\"Behind the Scenes\"}", - "Fulltext": "'astound':4 'boat':21 'car':11 'caus':2 'crocodil':8 'monsoon':1 'must':13 'outrac':14 'squirrel':16 'tale':5 'u':20 'u-boat':19" - }, - { - "FilmID": 141, - "Title": "Chicago North", - "Description": "A Fateful Yarn of a Mad Cow And a Waitress who must Battle a Student in California", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 4.99, - "Length": 185, - "ReplacementCost": 11.99, - "Rating": "PG-13", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\",\"Behind the Scenes\"}", - "Fulltext": "'battl':15 'california':19 'chicago':1 'cow':9 'fate':4 'mad':8 'must':14 'north':2 'student':17 'waitress':12 'yarn':5" } ], "Actors": [ @@ -786,102 +220,24 @@ "LastName": "Hoffman", "LastUpdate": "2013-05-26T14:47:57.62Z" }, - { - "ActorID": 44, - "FirstName": "Nick", - "LastName": "Stallone", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 50, - "FirstName": "Natalie", - "LastName": "Hopkins", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, { "ActorID": 64, "FirstName": "Ray", "LastName": "Johansson", "LastUpdate": "2013-05-26T14:47:57.62Z" }, - { - "ActorID": 79, - "FirstName": "Mae", - "LastName": "Hoffman", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 85, - "FirstName": "Minnie", - "LastName": "Zellweger", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 118, - "FirstName": "Cuba", - "LastName": "Allen", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 121, - "FirstName": "Liza", - "LastName": "Bergman", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 127, - "FirstName": "Kevin", - "LastName": "Garland", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, { "ActorID": 129, "FirstName": "Daryl", "LastName": "Crawford", "LastUpdate": "2013-05-26T14:47:57.62Z" }, - { - "ActorID": 143, - "FirstName": "River", - "LastName": "Dean", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 146, - "FirstName": "Albert", - "LastName": "Johansson", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 154, - "FirstName": "Meryl", - "LastName": "Gibson", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 175, - "FirstName": "William", - "LastName": "Hackman", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, { "ActorID": 184, "FirstName": "Humphrey", "LastName": "Garland", "LastUpdate": "2013-05-26T14:47:57.62Z" }, - { - "ActorID": 193, - "FirstName": "Burt", - "LastName": "Temple", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 195, - "FirstName": "Jayne", - "LastName": "Silverstone", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, { "ActorID": 198, "FirstName": "Mary", @@ -890,87 +246,6 @@ } ] }, - { - "CategoryID": 5, - "Name": "Comedy", - "LastUpdate": "2006-02-15T09:46:27Z", - "Films": [ - { - "FilmID": 182, - "Title": "Control Anthem", - "Description": "A Fateful Documentary of a Robot And a Student who must Battle a Cat in A Monastery", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 7, - "RentalRate": 4.99, - "Length": 185, - "ReplacementCost": 9.99, - "Rating": "G", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Commentaries}", - "Fulltext": "'anthem':2 'battl':14 'cat':16 'control':1 'documentari':5 'fate':4 'monasteri':19 'must':13 'robot':8 'student':11" - }, - { - "FilmID": 774, - "Title": "Searchers Wait", - "Description": "A Fast-Paced Tale of a Car And a Mad Scientist who must Kill a Womanizer in Ancient Japan", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 3, - "RentalRate": 2.99, - "Length": 182, - "ReplacementCost": 22.99, - "Rating": "NC-17", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,Commentaries,\"Deleted Scenes\",\"Behind the Scenes\"}", - "Fulltext": "'ancient':21 'car':10 'fast':5 'fast-pac':4 'japan':22 'kill':17 'mad':13 'must':16 'pace':6 'scientist':14 'searcher':1 'tale':7 'wait':2 'woman':19" - } - ], - "Actors": [ - { - "ActorID": 19, - "FirstName": "Bob", - "LastName": "Fawcett", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 34, - "FirstName": "Audrey", - "LastName": "Olivier", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 89, - "FirstName": "Charlize", - "LastName": "Dench", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 101, - "FirstName": "Susan", - "LastName": "Davis", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 107, - "FirstName": "Gina", - "LastName": "Degeneres", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 128, - "FirstName": "Cate", - "LastName": "Mcqueen", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 188, - "FirstName": "Rock", - "LastName": "Dukakis", - "LastUpdate": "2013-05-26T14:47:57.62Z" - } - ] - }, { "CategoryID": 7, "Name": "Drama", @@ -988,7 +263,11 @@ "ReplacementCost": 16.99, "Rating": "PG-13", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Deleted Scenes\",\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Deleted Scenes", + "Behind the Scenes" + ], "Fulltext": "'baloon':20 'chef':17 'conquer':14 'frisco':2 'husband':11 'insight':4 'jacket':1 'must':13 'pastri':16 'reflect':5 'woman':8" } ], @@ -1060,21 +339,6 @@ "Name": "Foreign", "LastUpdate": "2006-02-15T09:46:27Z", "Films": [ - { - "FilmID": 435, - "Title": "Hotel Happiness", - "Description": "A Thrilling Yarn of a Pastry Chef And a A Shark who must Challenge a Mad Scientist in The Outback", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 4.99, - "Length": 181, - "ReplacementCost": 28.99, - "Rating": "PG-13", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Behind the Scenes\"}", - "Fulltext": "'challeng':16 'chef':9 'happi':2 'hotel':1 'mad':18 'must':15 'outback':22 'pastri':8 'scientist':19 'shark':13 'thrill':4 'yarn':5" - }, { "FilmID": 821, "Title": "Sorority Queen", @@ -1087,24 +351,12 @@ "ReplacementCost": 17.99, "Rating": "NC-17", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Deleted Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Deleted Scenes" + ], "Fulltext": "'boat':23 'compos':13 'display':7 'fast':5 'fast-pac':4 'fight':16 'forens':18 'jet':22 'must':15 'pace':6 'psychologist':19 'queen':2 'soror':1 'squirrel':10" }, - { - "FilmID": 467, - "Title": "Intrigue Worst", - "Description": "A Fanciful Character Study of a Explorer And a Mad Scientist who must Vanquish a Squirrel in A Jet Boat", - "ReleaseYear": 2006, - "LanguageID": 1, - "RentalDuration": 6, - "RentalRate": 0.99, - "Length": 181, - "ReplacementCost": 10.99, - "Rating": "G", - "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\"}", - "Fulltext": "'boat':22 'charact':5 'explor':9 'fanci':4 'intrigu':1 'jet':21 'mad':12 'must':15 'scientist':13 'squirrel':18 'studi':6 'vanquish':16 'worst':2" - }, { "FilmID": 128, "Title": "Catch Amistad", @@ -1117,7 +369,10 @@ "ReplacementCost": 10.99, "Rating": "G", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Behind the Scenes" + ], "Fulltext": "'amistad':2 'bore':4 'catch':1 'discov':14 'feminist':11 'lumberjack':8 'must':13 'nigeria':18 'reflect':5 'woman':16" }, { @@ -1132,29 +387,20 @@ "ReplacementCost": 22.99, "Rating": "NC-17", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,Commentaries}", + "SpecialFeatures": [ + "Trailers", + "Commentaries" + ], "Fulltext": "'ancient':22 'break':2 'charact':7 'chef':20 'crystal':1 'explor':14 'face':17 'fast':5 'fast-pac':4 'feminist':11 'japan':23 'must':16 'pace':6 'pastri':19 'studi':8" } ], "Actors": [ - { - "ActorID": 23, - "FirstName": "Sandra", - "LastName": "Kilmer", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, { "ActorID": 26, "FirstName": "Rip", "LastName": "Crawford", "LastUpdate": "2013-05-26T14:47:57.62Z" }, - { - "ActorID": 37, - "FirstName": "Val", - "LastName": "Bolger", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, { "ActorID": 40, "FirstName": "Johnny", @@ -1179,18 +425,6 @@ "LastName": "Neeson", "LastUpdate": "2013-05-26T14:47:57.62Z" }, - { - "ActorID": 68, - "FirstName": "Rip", - "LastName": "Winslet", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 73, - "FirstName": "Gary", - "LastName": "Penn", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, { "ActorID": 88, "FirstName": "Kenneth", @@ -1203,18 +437,6 @@ "LastName": "Cronyn", "LastUpdate": "2013-05-26T14:47:57.62Z" }, - { - "ActorID": 107, - "FirstName": "Gina", - "LastName": "Degeneres", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 110, - "FirstName": "Susan", - "LastName": "Davis", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, { "ActorID": 116, "FirstName": "Dan", @@ -1245,12 +467,6 @@ "LastName": "Harris", "LastUpdate": "2013-05-26T14:47:57.62Z" }, - { - "ActorID": 154, - "FirstName": "Meryl", - "LastName": "Gibson", - "LastUpdate": "2013-05-26T14:47:57.62Z" - }, { "ActorID": 155, "FirstName": "Ian", @@ -1262,12 +478,6 @@ "FirstName": "Fay", "LastName": "Wood", "LastUpdate": "2013-05-26T14:47:57.62Z" - }, - { - "ActorID": 187, - "FirstName": "Renee", - "LastName": "Ball", - "LastUpdate": "2013-05-26T14:47:57.62Z" } ] }, @@ -1288,7 +498,10 @@ "ReplacementCost": 27.99, "Rating": "PG-13", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,Commentaries}", + "SpecialFeatures": [ + "Trailers", + "Commentaries" + ], "Fulltext": "'abandon':21 'awe':5 'awe-inspir':4 'conquer':16 'conspiraci':1 'crocodil':18 'frisbe':13 'inspir':6 'mine':22 'must':15 'shaft':23 'spirit':2 'stori':7 'student':10" } ], @@ -1320,55 +533,100 @@ ] }, { - "CategoryID": 16, - "Name": "Travel", + "CategoryID": 2, + "Name": "Animation", "LastUpdate": "2006-02-15T09:46:27Z", "Films": [ { - "FilmID": 609, - "Title": "Muscle Bright", - "Description": "A Stunning Panorama of a Sumo Wrestler And a Husband who must Redeem a Madman in Ancient India", + "FilmID": 690, + "Title": "Pond Seattle", + "Description": "A Stunning Drama of a Teacher And a Boat who must Battle a Feminist in Ancient China", "ReleaseYear": 2006, "LanguageID": 1, "RentalDuration": 7, "RentalRate": 2.99, "Length": 185, - "ReplacementCost": 23.99, - "Rating": "G", + "ReplacementCost": 25.99, + "Rating": "PG-13", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\"}", - "Fulltext": "'ancient':19 'bright':2 'husband':12 'india':20 'madman':17 'muscl':1 'must':14 'panorama':5 'redeem':15 'stun':4 'sumo':8 'wrestler':9" + "SpecialFeatures": [ + "Trailers", + "Commentaries", + "Behind the Scenes" + ], + "Fulltext": "'ancient':18 'battl':14 'boat':11 'china':19 'drama':5 'feminist':16 'must':13 'pond':1 'seattl':2 'stun':4 'teacher':8" } ], "Actors": [ { - "ActorID": 72, - "FirstName": "Sean", - "LastName": "Williams", + "ActorID": 95, + "FirstName": "Daryl", + "LastName": "Wahlberg", "LastUpdate": "2013-05-26T14:47:57.62Z" }, { - "ActorID": 103, - "FirstName": "Matthew", - "LastName": "Leigh", + "ActorID": 134, + "FirstName": "Gene", + "LastName": "Hopkins", "LastUpdate": "2013-05-26T14:47:57.62Z" }, { - "ActorID": 172, - "FirstName": "Groucho", - "LastName": "Williams", + "ActorID": 143, + "FirstName": "River", + "LastName": "Dean", + "LastUpdate": "2013-05-26T14:47:57.62Z" + } + ] + }, + { + "CategoryID": 5, + "Name": "Comedy", + "LastUpdate": "2006-02-15T09:46:27Z", + "Films": [ + { + "FilmID": 774, + "Title": "Searchers Wait", + "Description": "A Fast-Paced Tale of a Car And a Mad Scientist who must Kill a Womanizer in Ancient Japan", + "ReleaseYear": 2006, + "LanguageID": 1, + "RentalDuration": 3, + "RentalRate": 2.99, + "Length": 182, + "ReplacementCost": 22.99, + "Rating": "NC-17", + "LastUpdate": "2013-05-26T14:50:58.951Z", + "SpecialFeatures": [ + "Trailers", + "Commentaries", + "Deleted Scenes", + "Behind the Scenes" + ], + "Fulltext": "'ancient':21 'car':10 'fast':5 'fast-pac':4 'japan':22 'kill':17 'mad':13 'must':16 'pace':6 'scientist':14 'searcher':1 'tale':7 'wait':2 'woman':19" + } + ], + "Actors": [ + { + "ActorID": 101, + "FirstName": "Susan", + "LastName": "Davis", "LastUpdate": "2013-05-26T14:47:57.62Z" }, { - "ActorID": 180, - "FirstName": "Jeff", - "LastName": "Silverstone", + "ActorID": 107, + "FirstName": "Gina", + "LastName": "Degeneres", "LastUpdate": "2013-05-26T14:47:57.62Z" }, { - "ActorID": 181, - "FirstName": "Matthew", - "LastName": "Carrey", + "ActorID": 128, + "FirstName": "Cate", + "LastName": "Mcqueen", + "LastUpdate": "2013-05-26T14:47:57.62Z" + }, + { + "ActorID": 188, + "FirstName": "Rock", + "LastName": "Dukakis", "LastUpdate": "2013-05-26T14:47:57.62Z" } ] diff --git a/examples/quick-start/quick-start.go b/examples/quick-start/quick-start.go index a0fb252..7ff42f2 100644 --- a/examples/quick-start/quick-start.go +++ b/examples/quick-start/quick-start.go @@ -35,9 +35,9 @@ func main() { // Write query stmt := SELECT( - Actor.ActorID, Actor.FirstName, Actor.LastName, Actor.LastUpdate, + Actor.ActorID, Actor.FirstName, Actor.LastName, Actor.LastUpdate, // or just Actor.AllColumns Film.AllColumns, - Language.AllColumns.Except(Language.LastUpdate), + Language.AllColumns.Except(Language.LastUpdate), // all language columns except last_update Category.AllColumns, ).FROM( Actor. @@ -47,10 +47,13 @@ func main() { INNER_JOIN(FilmCategory, FilmCategory.FilmID.EQ(Film.FilmID)). INNER_JOIN(Category, Category.CategoryID.EQ(FilmCategory.CategoryID)), ).WHERE( - Language.Name.EQ(Char(20)("English")). - AND(Category.Name.NOT_EQ(Text("Action"))). - AND(Film.Length.GT(Int(180))). - AND(Film.Rating.NOT_EQ(enum.MpaaRating.R)), + AND( + Language.Name.EQ(Char(20)("English")), // string columns Language.Name and Category.Name can be compared only with string expression + Category.Name.NOT_EQ(Text("Action")), + Film.Length.GT(Int32(180)), // Film.Length is integer column and can be compared only with integer expression + Film.Rating.NOT_EQ(enum.MpaaRating.R), + String("Trailers").EQ(ANY(Film.SpecialFeatures)), // type safety is also enforced on array element types + ), ).ORDER_BY( Actor.ActorID.ASC(), Film.FilmID.ASC(), diff --git a/generator/metadata/column_meta_data.go b/generator/metadata/column_meta_data.go index ecd61e2..5035842 100644 --- a/generator/metadata/column_meta_data.go +++ b/generator/metadata/column_meta_data.go @@ -19,7 +19,6 @@ const ( BaseType DataTypeKind = "base" EnumType DataTypeKind = "enum" UserDefinedType DataTypeKind = "user-defined" - ArrayType DataTypeKind = "array" RangeType DataTypeKind = "range" ) @@ -28,4 +27,9 @@ type DataType struct { Name string Kind DataTypeKind IsUnsigned bool + Dimensions int // The number of array dimensions +} + +func (d DataType) IsArray() bool { + return d.Dimensions > 0 } diff --git a/generator/postgres/query_set.go b/generator/postgres/query_set.go index fc4135a..5b39110 100644 --- a/generator/postgres/query_set.go +++ b/generator/postgres/query_set.go @@ -66,22 +66,25 @@ select not attr.attnotnull as "column.isNullable", attr.attgenerated = 's' as "column.isGenerated", attr.atthasdef as "column.hasDefault", - (case - when tp.typtype = 'b' AND tp.typcategory <> 'A' then 'base' - when tp.typtype = 'b' AND tp.typcategory = 'A' then 'array' - when tp.typtype = 'd' then 'base' - when tp.typtype = 'e' then 'enum' - when tp.typtype = 'r' then 'range' - end) as "dataType.Kind", + (case when tp.typcategory = 'A' then greatest(1, attr.attndims) --cockroach num dims fix + else 0 + end) as "dataType.dimensions", + (case coalesce(elem.typtype, tp.typtype) + when 'b' then 'base' + when 'd' then 'base' + when 'e' then 'enum' + when 'r' then 'range' + end) as "dataType.Kind", (case when tp.typtype = 'd' then (select pg_type.typname from pg_catalog.pg_type where pg_type.oid = tp.typbasetype) - when tp.typcategory = 'A' then pg_catalog.format_type(attr.atttypid, attr.atttypmod) + when tp.typcategory = 'A' then elem.typname else tp.typname - end) as "dataType.Name", + end) as "dataType.Name", false as "dataType.isUnsigned" from pg_catalog.pg_attribute as attr join pg_catalog.pg_class as cls on cls.oid = attr.attrelid join pg_catalog.pg_namespace as ns on ns.oid = cls.relnamespace join pg_catalog.pg_type as tp on tp.oid = attr.atttypid + left join pg_catalog.pg_type elem ON tp.typelem = elem.oid -- only for arrays where ns.nspname = $1 and cls.relname = $2 and diff --git a/generator/template/model_template.go b/generator/template/model_template.go index cd5c5f1..5672d19 100644 --- a/generator/template/model_template.go +++ b/generator/template/model_template.go @@ -2,6 +2,7 @@ package template import ( "fmt" + "github.com/lib/pq" "path/filepath" "reflect" "strings" @@ -247,10 +248,21 @@ func getType(columnMetadata metadata.Column) Type { userDefinedType := getUserDefinedType(columnMetadata) if userDefinedType != "" { - if columnMetadata.IsNullable { - return Type{Name: "*" + userDefinedType} + var importPath string + + if columnMetadata.DataType.IsArray() { + userDefinedType = "pq.StringArray" + importPath = "github.com/lib/pq" + } + + if columnMetadata.IsNullable { + userDefinedType = "*" + userDefinedType + } + + return Type{ + Name: userDefinedType, + ImportPath: importPath, } - return Type{Name: userDefinedType} } return NewType(getGoType(columnMetadata)) @@ -260,7 +272,7 @@ func getUserDefinedType(column metadata.Column) string { switch column.DataType.Kind { case metadata.EnumType: return dbidentifier.ToGoIdentifier(column.DataType.Name) - case metadata.UserDefinedType, metadata.ArrayType: + case metadata.UserDefinedType: return "string" } @@ -268,17 +280,45 @@ func getUserDefinedType(column metadata.Column) string { } func getGoType(column metadata.Column) interface{} { - defaultGoType := toGoType(column) + goType := toGoType(column) - if column.IsNullable { - return reflect.New(reflect.TypeOf(defaultGoType)).Interface() + if column.DataType.IsArray() { + goType = toGoArrayType(goType, column) } - return defaultGoType + if column.IsNullable { + return reflect.New(reflect.TypeOf(goType)).Interface() + } + + return goType +} + +func toGoArrayType(elemType any, column metadata.Column) any { + if column.DataType.Dimensions > 1 { + return "" // unsupported multidimensional arrays + } + + switch elemType.(type) { + case bool: + return pq.BoolArray{} + case int32: + return pq.Int32Array{} + case int64: + return pq.Int64Array{} + case float32: + return pq.Float32Array{} + case float64: + return pq.Float64Array{} + case []byte: + return pq.ByteaArray{} + default: + return pq.StringArray{} + } } // toGoType returns model type for column info. func toGoType(column metadata.Column) interface{} { + switch strings.ToLower(column.DataType.Name) { case "user-defined", "enum": return "" diff --git a/generator/template/sql_builder_template.go b/generator/template/sql_builder_template.go index a06faed..0c4c66c 100644 --- a/generator/template/sql_builder_template.go +++ b/generator/template/sql_builder_template.go @@ -162,11 +162,32 @@ func DefaultTableSQLBuilderColumn(columnMetaData metadata.Column) TableSQLBuilde // getSqlBuilderColumnType returns type of jet sql builder column func getSqlBuilderColumnType(columnMetaData metadata.Column) string { - if columnMetaData.DataType.Kind != metadata.BaseType && - columnMetaData.DataType.Kind != metadata.RangeType { + switch columnMetaData.DataType.Kind { + case metadata.EnumType, metadata.UserDefinedType: + if columnMetaData.DataType.IsArray() { + return "StringArray" + } return "String" } + columnType := sqlToColumnType(columnMetaData) + + if columnMetaData.DataType.IsArray() { + if columnMetaData.DataType.Dimensions > 1 { + fmt.Println("- [SQL Builder] Unsupported sql array with multiple dimensions column '" + + columnMetaData.Name + " " + columnMetaData.DataType.Name + "', using StringColumn instead.") + return "String" + } + + columnType = columnType + "Array" + } + + return columnType +} + +// sqlToColumnType maps the type of a SQL column type to a go jet sql builder column. The second return value returns +// whether the given type is supported. +func sqlToColumnType(columnMetaData metadata.Column) string { switch strings.ToLower(columnMetaData.DataType.Name) { case "boolean", "bool": return "Bool" diff --git a/internal/jet/array_expression.go b/internal/jet/array_expression.go new file mode 100644 index 0000000..e0ab8dc --- /dev/null +++ b/internal/jet/array_expression.go @@ -0,0 +1,136 @@ +package jet + +// Array interface +type Array[E Expression] interface { + Expression + + EQ(rhs Array[E]) BoolExpression + NOT_EQ(rhs Array[E]) BoolExpression + LT(rhs Array[E]) BoolExpression + GT(rhs Array[E]) BoolExpression + LT_EQ(rhs Array[E]) BoolExpression + GT_EQ(rhs Array[E]) BoolExpression + + CONTAINS(rhs Array[E]) BoolExpression + IS_CONTAINED_BY(rhs Array[E]) BoolExpression + OVERLAP(rhs Array[E]) BoolExpression + CONCAT(rhs Array[E]) Array[E] + CONCAT_ELEMENT(E) Array[E] + + AT(expression IntegerExpression) E +} + +type arrayInterfaceImpl[E Expression] struct { + parent Array[E] +} + +type BinaryBoolOp func(Expression, Expression) BoolExpression + +func (a arrayInterfaceImpl[E]) EQ(rhs Array[E]) BoolExpression { + return Eq(a.parent, rhs) +} + +func (a arrayInterfaceImpl[E]) NOT_EQ(rhs Array[E]) BoolExpression { + return NotEq(a.parent, rhs) +} + +func (a arrayInterfaceImpl[E]) LT(rhs Array[E]) BoolExpression { + return Lt(a.parent, rhs) +} + +func (a arrayInterfaceImpl[E]) GT(rhs Array[E]) BoolExpression { + return Gt(a.parent, rhs) +} + +func (a arrayInterfaceImpl[E]) LT_EQ(rhs Array[E]) BoolExpression { + return LtEq(a.parent, rhs) +} + +func (a arrayInterfaceImpl[E]) GT_EQ(rhs Array[E]) BoolExpression { + return GtEq(a.parent, rhs) +} + +func (a arrayInterfaceImpl[E]) CONTAINS(rhs Array[E]) BoolExpression { + return Contains(a.parent, rhs) +} + +func (a arrayInterfaceImpl[E]) IS_CONTAINED_BY(rhs Array[E]) BoolExpression { + return IsContainedBy(a.parent, rhs) +} + +func (a arrayInterfaceImpl[E]) OVERLAP(rhs Array[E]) BoolExpression { + return Overlap(a.parent, rhs) +} + +func (a arrayInterfaceImpl[E]) CONCAT(rhs Array[E]) Array[E] { + return ArrayExp[E](NewBinaryOperatorExpression(a.parent, rhs, "||")) +} + +func (a arrayInterfaceImpl[E]) CONCAT_ELEMENT(rhs E) Array[E] { + return ArrayExp[E](NewBinaryOperatorExpression(a.parent, rhs, "||")) +} + +func (a arrayInterfaceImpl[E]) AT(at IntegerExpression) E { + return CastToArrayElemType[E](a.parent, CustomExpression(a.parent, Token("["), at, Token("]"))) +} + +type arrayExpressionWrapper[E Expression] struct { + arrayInterfaceImpl[E] + Expression +} + +func newArrayExpressionWrap[E Expression](expression Expression) Array[E] { + arrayExpressionWrapper := arrayExpressionWrapper[E]{Expression: expression} + arrayExpressionWrapper.arrayInterfaceImpl.parent = &arrayExpressionWrapper + return &arrayExpressionWrapper +} + +// ArrayExp is array expression wrapper around arbitrary expression. +// Allows go compiler to see any expression as array expression. +// Does not add sql cast to generated sql builder output. +func ArrayExp[E Expression](expression Expression) Array[E] { + return newArrayExpressionWrap[E](expression) +} + +// CastToArrayElemType casts exp to array element type +func CastToArrayElemType[E Expression](array Array[E], exp Expression) E { + var i Expression + switch array.(type) { + case Array[BoolExpression]: + i = BoolExp(exp) + case Array[StringExpression]: + i = StringExp(exp) + case Array[IntegerExpression]: + i = IntExp(exp) + case Array[FloatExpression]: + i = FloatExp(exp) + case Array[BlobExpression]: + i = BlobExp(exp) + case Array[DateExpression]: + i = DateExp(exp) + case Array[TimestampExpression]: + i = TimestampExp(exp) + case Array[TimestampzExpression]: + i = TimestampzExp(exp) + case Array[TimeExpression]: + i = TimeExp(exp) + case Array[TimezExpression]: + i = TimezExp(exp) + case Array[IntervalExpression]: + i = IntervalExp(exp) + } + + return i.(E) +} + +// ARRAY constructor builds an array value using list of expressions. +func ARRAY[E Expression](elems ...E) Array[E] { + var args = make([]Serializer, len(elems)) + for i, each := range elems { + args[i] = each + } + return ArrayExp[E](CustomExpression(Token("ARRAY["), ListSerializer{ + Serializers: args, + Separator: ",", + }, Token("]"))) +} diff --git a/internal/jet/array_expression_test.go b/internal/jet/array_expression_test.go new file mode 100644 index 0000000..54e851e --- /dev/null +++ b/internal/jet/array_expression_test.go @@ -0,0 +1,68 @@ +package jet + +import ( + "testing" +) + +func TestArrayExpressionEQ(t *testing.T) { + assertClauseSerialize(t, table1ColStringArray.EQ(table2ColArray), "(table1.col_array_string = table2.col_array_string)") +} + +func TestArrayExpressionNOT_EQ(t *testing.T) { + assertClauseSerialize(t, table1ColStringArray.NOT_EQ(table2ColArray), "(table1.col_array_string != table2.col_array_string)") +} + +func TestArrayExpressionLT(t *testing.T) { + assertClauseSerialize(t, table1ColStringArray.LT(table2ColArray), "(table1.col_array_string < table2.col_array_string)") +} + +func TestArrayExpressionGT(t *testing.T) { + assertClauseSerialize(t, table1ColStringArray.GT(table2ColArray), "(table1.col_array_string > table2.col_array_string)") +} + +func TestArrayExpressionLT_EQ(t *testing.T) { + assertClauseSerialize(t, table1ColStringArray.LT_EQ(table2ColArray), "(table1.col_array_string <= table2.col_array_string)") +} + +func TestArrayExpressionGT_EQ(t *testing.T) { + assertClauseSerialize(t, table1ColStringArray.GT_EQ(table2ColArray), "(table1.col_array_string >= table2.col_array_string)") +} + +func TestArrayExpressionCONTAINS(t *testing.T) { + assertClauseSerialize(t, table1ColStringArray.CONTAINS(table2ColArray), "(table1.col_array_string @> table2.col_array_string)") +} + +func TestArrayExpressionCONTAINED_BY(t *testing.T) { + assertClauseSerialize(t, table1ColStringArray.IS_CONTAINED_BY(table2ColArray), "(table1.col_array_string <@ table2.col_array_string)") +} + +func TestArrayExpressionOVERLAP(t *testing.T) { + assertClauseSerialize(t, table1ColStringArray.OVERLAP(table2ColArray), "(table1.col_array_string && table2.col_array_string)") +} + +func TestArrayExpressionCONCAT(t *testing.T) { + assertClauseSerialize(t, table1ColStringArray.CONCAT(table2ColArray), "(table1.col_array_string || table2.col_array_string)") +} + +func TestArrayExpressionCONCAT_ELEMENT(t *testing.T) { + assertClauseSerialize(t, table1ColStringArray.CONCAT_ELEMENT(StringExp(table2ColArray.AT(Int(1)))), "(table1.col_array_string || table2.col_array_string[$1])", int64(1)) + assertClauseSerialize(t, table1ColStringArray.CONCAT_ELEMENT(String("x")), "(table1.col_array_string || $1)", "x") +} + +func TestArrayExpressionAT(t *testing.T) { + assertClauseSerialize(t, table1ColStringArray.AT(Int(1)), "table1.col_array_string[$1]", int64(1)) +} + +func TestCastToArrayElemType(t *testing.T) { + var _ BoolExpression = CastToArrayElemType[BoolExpression](ARRAY[BoolExpression](), table1Col1) + var _ IntegerExpression = CastToArrayElemType[IntegerExpression](ARRAY[IntegerExpression](), table1Col1) + var _ FloatExpression = CastToArrayElemType[FloatExpression](ARRAY[FloatExpression](), table1Col1) + var _ StringExpression = CastToArrayElemType[StringExpression](ARRAY[StringExpression](), table1Col1) + var _ BlobExpression = CastToArrayElemType[BlobExpression](ARRAY[BlobExpression](), table1Col1) + var _ DateExpression = CastToArrayElemType[DateExpression](ARRAY[DateExpression](), table1Col1) + var _ TimestampExpression = CastToArrayElemType[TimestampExpression](ARRAY[TimestampExpression](), table1Col1) + var _ TimestampzExpression = CastToArrayElemType[TimestampzExpression](ARRAY[TimestampzExpression](), table1Col1) + var _ TimeExpression = CastToArrayElemType[TimeExpression](ARRAY[TimeExpression](), table1Col1) + var _ TimezExpression = CastToArrayElemType[TimezExpression](ARRAY[TimezExpression](), table1Col1) + var _ IntervalExpression = CastToArrayElemType[IntervalExpression](ARRAY[IntervalExpression](), table1Col1) +} diff --git a/internal/jet/column_types.go b/internal/jet/column_types.go index 68a5042..5d63485 100644 --- a/internal/jet/column_types.go +++ b/internal/jet/column_types.go @@ -133,6 +133,50 @@ func IntegerColumn(name string) ColumnInteger { //------------------------------------------------------// +type ColumnArray[E Expression] interface { + Array[E] + Column + + From(subQuery SelectTable) ColumnArray[E] + SET(stringExp Array[E]) ColumnAssigment +} + +type arrayColumnImpl[E Expression] struct { + arrayInterfaceImpl[E] + + *ColumnExpressionImpl +} + +func (a arrayColumnImpl[E]) fromImpl(subQuery SelectTable) Projection { + return a.From(subQuery) +} + +func (a arrayColumnImpl[E]) From(subQuery SelectTable) ColumnArray[E] { + newArrayColumn := ArrayColumn[E](a.name) + newArrayColumn.setTableName(a.tableName) + newArrayColumn.setSubQuery(subQuery) + + return newArrayColumn +} + +func (a *arrayColumnImpl[E]) SET(stringExp Array[E]) ColumnAssigment { + return columnAssigmentImpl{ + column: a, + toAssign: stringExp, + } +} + +// StringColumn creates named string column. +func ArrayColumn[E Expression](name string) ColumnArray[E] { + arrayColumn := &arrayColumnImpl[E]{} + arrayColumn.arrayInterfaceImpl.parent = arrayColumn + arrayColumn.ColumnExpressionImpl = NewColumnImpl(name, "", arrayColumn) + + return arrayColumn +} + +//------------------------------------------------------// + // ColumnString is interface for SQL text, character, character varying // uuid columns and enums types. type ColumnString interface { diff --git a/internal/jet/column_types_test.go b/internal/jet/column_types_test.go index 059d722..cf585e2 100644 --- a/internal/jet/column_types_test.go +++ b/internal/jet/column_types_test.go @@ -8,6 +8,36 @@ var subQuery = &selectTableImpl{ alias: "sub_query", } +func TestNewArrayColumnString(t *testing.T) { + stringArrayColumn := ArrayColumn[StringExpression]("colArray").From(subQuery) + assertClauseSerialize(t, stringArrayColumn, `sub_query."colArray"`) + assertProjectionSerialize(t, stringArrayColumn, `sub_query."colArray" AS "colArray"`) + + arrayColumn2 := table1ColStringArray.From(subQuery) + assertClauseSerialize(t, arrayColumn2, `sub_query."table1.col_array_string"`) + assertProjectionSerialize(t, arrayColumn2, `sub_query."table1.col_array_string" AS "table1.col_array_string"`) +} + +func TestNewArrayColumnBool(t *testing.T) { + boolArrayColumn := ArrayColumn[BoolExpression]("colArrayBool").From(subQuery) + assertClauseSerialize(t, boolArrayColumn, `sub_query."colArrayBool"`) + assertProjectionSerialize(t, boolArrayColumn, `sub_query."colArrayBool" AS "colArrayBool"`) + + arrayColumn2 := table1ColBoolArray.From(subQuery) + assertClauseSerialize(t, arrayColumn2, `sub_query."table1.col_array_bool"`) + assertProjectionSerialize(t, arrayColumn2, `sub_query."table1.col_array_bool" AS "table1.col_array_bool"`) +} + +func TestNewArrayColumnInteger(t *testing.T) { + intArrayColumn := ArrayColumn[IntegerExpression]("colArrayInt").From(subQuery) + assertClauseSerialize(t, intArrayColumn, `sub_query."colArrayInt"`) + assertProjectionSerialize(t, intArrayColumn, `sub_query."colArrayInt" AS "colArrayInt"`) + + arrayColumn2 := table1ColIntArray.From(subQuery) + assertClauseSerialize(t, arrayColumn2, `sub_query."table1.col_array_int"`) + assertProjectionSerialize(t, arrayColumn2, `sub_query."table1.col_array_int" AS "table1.col_array_int"`) +} + func TestNewBoolColumn(t *testing.T) { boolColumn := BoolColumn("colBool").From(subQuery) assertClauseSerialize(t, boolColumn, `sub_query."colBool"`) diff --git a/internal/jet/operators.go b/internal/jet/operators.go index 8c7cc16..b56cb1b 100644 --- a/internal/jet/operators.go +++ b/internal/jet/operators.go @@ -74,6 +74,11 @@ func Contains(lhs Expression, rhs Expression) BoolExpression { return newBinaryBoolOperatorExpression(lhs, rhs, "@>") } +// IsContainedBy returns a representation of "a <@ b" +func IsContainedBy(lhs Expression, rhs Expression) BoolExpression { + return newBinaryBoolOperatorExpression(lhs, rhs, "<@") +} + // Overlap returns a representation of "a && b" func Overlap(lhs, rhs Expression) BoolExpression { return newBinaryBoolOperatorExpression(lhs, rhs, "&&") diff --git a/internal/jet/sql_builder.go b/internal/jet/sql_builder.go index 8764dd7..9471911 100644 --- a/internal/jet/sql_builder.go +++ b/internal/jet/sql_builder.go @@ -4,16 +4,15 @@ import ( "bytes" "database/sql/driver" "fmt" + "github.com/go-jet/jet/v2/internal/3rdparty/pq" + "github.com/go-jet/jet/v2/internal/utils/is" + "github.com/google/uuid" "reflect" "sort" "strconv" "strings" "time" "unicode" - - "github.com/go-jet/jet/v2/internal/3rdparty/pq" - "github.com/go-jet/jet/v2/internal/utils/is" - "github.com/google/uuid" ) // SQLBuilder generates output SQL @@ -93,11 +92,11 @@ func (s *SQLBuilder) write(data []byte) { } func isPreSeparator(b byte) bool { - return b == ' ' || b == '.' || b == ',' || b == '(' || b == '\n' || b == ':' + return b == ' ' || b == '.' || b == ',' || b == '(' || b == '\n' || b == ':' || b == '[' } func isPostSeparator(b byte) bool { - return b == ' ' || b == '.' || b == ',' || b == ')' || b == '\n' || b == ':' + return b == ' ' || b == '.' || b == ',' || b == ')' || b == '\n' || b == ':' || b == '[' || b == ']' } // WriteAlias is used to add alias to output SQL diff --git a/internal/jet/testutils.go b/internal/jet/testutils.go index 866048a..667cc64 100644 --- a/internal/jet/testutils.go +++ b/internal/jet/testutils.go @@ -18,19 +18,22 @@ var defaultDialect = NewDialect(DialectParams{ // just for tests }) var ( - table1Col1 = IntegerColumn("col1") - table1ColInt = IntegerColumn("col_int") - table1ColFloat = FloatColumn("col_float") - table1Col3 = IntegerColumn("col3") - table1ColTime = TimeColumn("col_time") - table1ColTimez = TimezColumn("col_timez") - table1ColTimestamp = TimestampColumn("col_timestamp") - table1ColTimestampz = TimestampzColumn("col_timestampz") - table1ColBool = BoolColumn("col_bool") - table1ColDate = DateColumn("col_date") - table1ColRange = RangeColumn[Int8Expression]("col_range") + table1Col1 = IntegerColumn("col1") + table1ColInt = IntegerColumn("col_int") + table1ColFloat = FloatColumn("col_float") + table1Col3 = IntegerColumn("col3") + table1ColTime = TimeColumn("col_time") + table1ColTimez = TimezColumn("col_timez") + table1ColTimestamp = TimestampColumn("col_timestamp") + table1ColTimestampz = TimestampzColumn("col_timestampz") + table1ColBool = BoolColumn("col_bool") + table1ColDate = DateColumn("col_date") + table1ColRange = RangeColumn[Int8Expression]("col_range") + table1ColStringArray = ArrayColumn[StringExpression]("col_array_string") + table1ColBoolArray = ArrayColumn[BoolExpression]("col_array_bool") + table1ColIntArray = ArrayColumn[IntegerExpression]("col_array_int") ) -var table1 = NewTable("db", "table1", "", table1Col1, table1ColInt, table1ColFloat, table1Col3, table1ColTime, table1ColTimez, table1ColBool, table1ColDate, table1ColRange, table1ColTimestamp, table1ColTimestampz) +var table1 = NewTable("db", "table1", "", table1Col1, table1ColInt, table1ColFloat, table1Col3, table1ColTime, table1ColTimez, table1ColBool, table1ColDate, table1ColRange, table1ColTimestamp, table1ColTimestampz, table1ColStringArray, table1ColBoolArray, table1ColIntArray) var ( table2Col3 = IntegerColumn("col3") @@ -45,8 +48,9 @@ var ( table2ColTimestampz = TimestampzColumn("col_timestampz") table2ColDate = DateColumn("col_date") table2ColRange = RangeColumn[Int8Expression]("col_range") + table2ColArray = ArrayColumn[StringExpression]("col_array_string") ) -var table2 = NewTable("db", "table2", "", table2Col3, table2Col4, table2ColInt, table2ColFloat, table2ColStr, table2ColBool, table2ColTime, table2ColTimez, table2ColDate, table2ColRange, table2ColTimestamp, table2ColTimestampz) +var table2 = NewTable("db", "table2", "", table2Col3, table2Col4, table2ColInt, table2ColFloat, table2ColStr, table2ColBool, table2ColTime, table2ColTimez, table2ColDate, table2ColRange, table2ColTimestamp, table2ColTimestampz, table2ColArray) var ( table3Col1 = IntegerColumn("col1") diff --git a/internal/testutils/test_utils.go b/internal/testutils/test_utils.go index eb1f8bf..88f00ab 100644 --- a/internal/testutils/test_utils.go +++ b/internal/testutils/test_utils.go @@ -299,6 +299,16 @@ func AssertFileNamesEqual(t *testing.T, dirPath string, fileNames ...string) { } } +// DeepCopy create deep copy of src +func DeepCopy[T any](t require.TestingT, src T) T { + var dst T + data, err := json.Marshal(src) + require.NoError(t, err) + err = json.Unmarshal(data, &dst) + require.NoError(t, err) + return dst +} + // AssertDeepEqual checks if actual and expected objects are deeply equal. func AssertDeepEqual(t require.TestingT, actual, expected interface{}, option ...cmp.Option) { if !assert.True(t, cmp.Equal(actual, expected, option...)) { diff --git a/postgres/array_columns.go b/postgres/array_columns.go new file mode 100755 index 0000000..b704fa6 --- /dev/null +++ b/postgres/array_columns.go @@ -0,0 +1,33 @@ +package postgres + +import "github.com/go-jet/jet/v2/internal/jet" + +// Interfaces for different postgres array column types +type ( + ColumnBoolArray jet.ColumnArray[BoolExpression] + ColumnStringArray jet.ColumnArray[StringExpression] + ColumnIntegerArray jet.ColumnArray[IntegerExpression] + ColumnFloatArray jet.ColumnArray[FloatExpression] + ColumnByteaArray jet.ColumnArray[ByteaExpression] + ColumnDateArray jet.ColumnArray[DateExpression] + ColumnTimestampArray jet.ColumnArray[TimestampExpression] + ColumnTimestampzArray jet.ColumnArray[TimestampzExpression] + ColumnTimeArray jet.ColumnArray[TimeExpression] + ColumnTimezArray jet.ColumnArray[TimezExpression] + ColumnIntervalArray jet.ColumnArray[IntervalExpression] +) + +// Column constructors for different postgres array column types +var ( + BoolArrayColumn = jet.ArrayColumn[BoolExpression] + StringArrayColumn = jet.ArrayColumn[StringExpression] + IntegerArrayColumn = jet.ArrayColumn[IntegerExpression] + FloatArrayColumn = jet.ArrayColumn[FloatExpression] + ByteaArrayColumn = jet.ArrayColumn[ByteaExpression] + DateArrayColumn = jet.ArrayColumn[DateExpression] + TimestampArrayColumn = jet.ArrayColumn[TimestampExpression] + TimestampzArrayColumn = jet.ArrayColumn[TimestampzExpression] + TimeArrayColumn = jet.ArrayColumn[TimeExpression] + TimezArrayColumn = jet.ArrayColumn[TimezExpression] + IntervalArrayColumn = jet.ArrayColumn[IntervalExpression] +) diff --git a/postgres/cast.go b/postgres/cast.go index e4d09ce..46abf39 100644 --- a/postgres/cast.go +++ b/postgres/cast.go @@ -96,7 +96,7 @@ func (b *cast) AS_DATE() DateExpression { return DateExp(b.AS("date")) } -// AS_DECIMAL casts expression AS date type +// AS_DECIMAL casts expression AS decimal type func (b *cast) AS_DECIMAL() FloatExpression { return FloatExp(b.AS("decimal")) } @@ -130,3 +130,68 @@ func (b *cast) AS_TIMESTAMPZ() TimestampzExpression { func (b *cast) AS_INTERVAL() IntervalExpression { return IntervalExp(b.AS("interval")) } + +// AS_UUID casts expression AS uuid type +func (b *cast) AS_UUID() StringExpression { + return StringExp(b.AS("uuid")) +} + +// AS_BOOL_ARRAY casts expression as boolean array type +func (b *cast) AS_BOOL_ARRAY() Array[BoolExpression] { + return ArrayExp[BoolExpression](b.AS("boolean[]")) +} + +// AS_INTEGER_ARRAY casts expression as integer array type +func (b *cast) AS_INTEGER_ARRAY() Array[IntegerExpression] { + return ArrayExp[IntegerExpression](b.AS("integer[]")) +} + +// AS_BIGINT_ARRAY casts expression as bigint array type +func (b *cast) AS_BIGINT_ARRAY() Array[IntegerExpression] { + return ArrayExp[IntegerExpression](b.AS("bigint[]")) +} + +// AS_REAL_ARRAY casts expression as real array +func (b *cast) AS_REAL_ARRAY() Array[FloatExpression] { + return ArrayExp[FloatExpression](b.AS("real[]")) +} + +// AS_DOUBLE_ARRAY casts expression as double precision array +func (b *cast) AS_DOUBLE_ARRAY() Array[FloatExpression] { + return ArrayExp[FloatExpression](b.AS("double precision[]")) +} + +// AS_TEXT_ARRAY casts expression as text array +func (b *cast) AS_TEXT_ARRAY() Array[StringExpression] { + return ArrayExp[StringExpression](b.AS("text[]")) +} + +// AS_BYTEA_ARRAY casts expression as bytea array +func (b *cast) AS_BYTEA_ARRAY() Array[ByteaExpression] { + return ArrayExp[ByteaExpression](b.AS("bytea[]")) +} + +// AS_DATE_ARRAY casts expression as date array +func (b *cast) AS_DATE_ARRAY() Array[DateExpression] { + return ArrayExp[DateExpression](b.AS("date[]")) +} + +// AS_TIMESTAMP_ARRAY casts expression as timestamp array +func (b *cast) AS_TIMESTAMP_ARRAY() Array[TimestampExpression] { + return ArrayExp[TimestampExpression](b.AS("timestamp without time zone[]")) +} + +// AS_TIMESTAMPZ_ARRAY casts expression as timestamp with time zone array +func (b *cast) AS_TIMESTAMPZ_ARRAY() Array[TimestampzExpression] { + return ArrayExp[TimestampzExpression](b.AS("timestamp with time zone[]")) +} + +// AS_TIME_ARRAY casts expression as time array +func (b *cast) AS_TIME_ARRAY() Array[TimeExpression] { + return ArrayExp[TimeExpression](b.AS("time without time zone[]")) +} + +// AS_TIMEZ_ARRAY casts expression as time with timezone array +func (b *cast) AS_TIMEZ_ARRAY() Array[TimezExpression] { + return ArrayExp[TimezExpression](b.AS("time with time zone[]")) +} diff --git a/postgres/expressions.go b/postgres/expressions.go index f4fbb13..f332aee 100644 --- a/postgres/expressions.go +++ b/postgres/expressions.go @@ -2,7 +2,7 @@ package postgres import "github.com/go-jet/jet/v2/internal/jet" -// Expression is common interface for all expressions. +// Expression is a common interface for all expressions. // Can be Bool, Int, Float, String, Date, Time, Timez, Timestamp or Timestampz expressions. type Expression = jet.Expression @@ -176,3 +176,13 @@ var NewEnumValue = jet.NewEnumValue // BinaryOperator can be used to use custom or unsupported operators that take two operands. var BinaryOperator = jet.BinaryOperator + +// Array is a common template interface for all array expressions. +type Array[T Expression] jet.Array[T] + +// ArrayExp serves as a wrapper for an arbitrary expression, treating it as an array expression of type T. +// This enables the Go compiler to interpret any expression as an array expression of type T. +// Note: This does not modify the generated SQL builder output by adding an SQL CAST operation. +func ArrayExp[T Expression](exp Expression) Array[T] { + return jet.ArrayExp[T](exp) +} diff --git a/postgres/functions.go b/postgres/functions.go index 2e92648..14a5bd7 100644 --- a/postgres/functions.go +++ b/postgres/functions.go @@ -335,7 +335,7 @@ var TO_ASCII = jet.TO_ASCII // TO_HEX converts number to its equivalent hexadecimal representation var TO_HEX = jet.TO_HEX -//----------Data Type Formatting Functions ----------------------// +//---------- Range Functions ----------------------// // LOWER_BOUND returns range expressions lower bound func LOWER_BOUND[T Expression](expression jet.Range[T]) T { @@ -347,7 +347,144 @@ func UPPER_BOUND[T Expression](expression jet.Range[T]) T { return jet.UPPER_BOUND[T](expression) } -//----------Data Type Formatting Functions ----------------------// +// ---------- Array Functions ----------------------// + +// ANY should be used in combination with a boolean operator. The result of ANY is "true" if any true result is obtained +func ANY[E Expression](arr Array[E]) E { + return jet.CastToArrayElemType(arr, Func("ANY", arr)) +} + +// ALL should be used in combination with a boolean operator. The result of ALL is “true” if all comparisons yield true +func ALL[E Expression](arr Array[E]) E { + return jet.CastToArrayElemType(arr, Func("ALL", arr)) +} + +// ARRAY_APPEND appends an element to the end of an array +func ARRAY_APPEND[E Expression](arr Array[E], elem E) Array[E] { + return ArrayExp[E](Func("ARRAY_APPEND", arr, elem)) +} + +// ARRAY_CAT concatenates two arrays +func ARRAY_CAT[E Expression](arr1, arr2 Array[E]) Array[E] { + return ArrayExp[E](Func("ARRAY_CAT", arr1, arr2)) +} + +// ARRAY_DIMS returns a text representation of the array's dimensions. +func ARRAY_DIMS[E Expression](arr Array[E]) StringExpression { + return StringExp(Func("ARRAY_DIMS", arr)) +} + +// ARRAY_LENGTH returns the length of the requested array dimension. +// Produces NULL instead of 0 for empty or missing array dimensions. +func ARRAY_LENGTH[E Expression](arr Array[E], elem IntegerExpression) IntegerExpression { + return IntExp(Func("ARRAY_LENGTH", arr, elem)) +} + +// ARRAY_LOWER returns the lower bound of the requested array dimension. +func ARRAY_LOWER[E Expression](arr Array[E]) IntegerExpression { + return IntExp(Func("ARRAY_LOWER", arr)) +} + +// ARRAY_NDIMS returns the number of dimensions of the array. +func ARRAY_NDIMS[E Expression](arr Array[E]) IntegerExpression { + return IntExp(Func("ARRAY_NDIMS", arr)) +} + +// ARRAY_POSITION returns the subscript of the first occurrence of the second argument in the array, or NULL if it's not present. +// If the third argument is given, the search begins at that subscript. +// The array must be one-dimensional. +// Comparisons are done using IS NOT DISTINCT FROM semantics, so it is possible to search for NULL. +func ARRAY_POSITION[E Expression](arr Array[E], elem E, start ...IntegerExpression) IntegerExpression { + return IntExp(Func("ARRAY_POSITION", optionalAppend([]Expression{arr, elem}, start)...)) +} + +// ARRAY_POSITIONS returns an array of the subscripts of all occurrences of the second argument in the array given as first argument. +// The array must be one-dimensional. +// Comparisons are done using IS NOT DISTINCT FROM semantics, so it is possible to search for NULL. +// NULL is returned only if the array is NULL; if the value is not found in the array, an empty array is returned. +func ARRAY_POSITIONS[E Expression](arr Array[E], elem E) Array[IntegerExpression] { + return ArrayExp[IntegerExpression](Func("ARRAY_POSITIONS", arr, elem)) +} + +// ARRAY_PREPEND prepends an element to the beginning of an array +func ARRAY_PREPEND[E Expression](el E, arr Array[E]) Array[E] { + return ArrayExp[E](Func("ARRAY_PREPEND", el, arr)) +} + +// ARRAY_REMOVE removes all elements equal to the given value from the array. The array must be one-dimensional. +// Comparisons are done using IS NOT DISTINCT FROM semantics, so it is possible to remove NULLs. +func ARRAY_REMOVE[E Expression](arr Array[E], elem Expression) IntegerExpression { + return IntExp(Func("ARRAY_REMOVE", arr, elem)) +} + +// ARRAY_REPLACE replaces each array element equal to the second argument with the third argument. +func ARRAY_REPLACE[E Expression](arr Array[E], existing E, new E) Array[E] { + return ArrayExp[E](Func("ARRAY_REPLACE", arr, existing, new)) +} + +// ARRAY_REVERSE reverses the first dimension of the array. +func ARRAY_REVERSE[E Expression](arr Array[E]) Array[E] { + return ArrayExp[E](Func("ARRAY_REVERSE", arr)) +} + +// ARRAY_SAMPLE returns an array of n items randomly selected from array. +// n may not exceed the length of array's first dimension. +// If array is multi-dimensional, an “item” is a slice having a given first subscript. +func ARRAY_SAMPLE[E Expression](arr Array[E], n IntegerExpression) Array[E] { + return ArrayExp[E](Func("ARRAY_SAMPLE", arr, n)) +} + +// ARRAY_SHUFFLE randomly shuffles the first dimension of the array. +func ARRAY_SHUFFLE[E Expression](arr Array[E]) Array[E] { + return ArrayExp[E](Func("ARRAY_SHUFFLE", arr)) +} + +// ARRAY_SORT sorts the first dimension of the array. +// The sort order is determined by the default sort ordering of the array's element type; however, if the element type is collatable, the collation to use can be specified by adding a COLLATE clause to the array argument. +// +// If descending is true then sort in descending order, otherwise ascending order. +// If omitted, the default is ascending order. +// If nulls_first is true then nulls appear before non-null values, otherwise nulls appear after non-null values. +// If omitted, nulls_first is taken to have the same value as descending. +func ARRAY_SORT[E Expression](arr Array[E], desc BoolExpression, nullFirst ...BoolExpression) Array[E] { + return ArrayExp[E](Func("ARRAY_SORT", optionalAppend([]Expression{arr, desc}, nullFirst)...)) +} + +// ARRAY_TO_STRING Converts each array element to its text representation, and concatenates those separated by the delimiter string. +// If null_string is given and is not NULL, then NULL array entries are represented by that string; otherwise, they are omitted. +func ARRAY_TO_STRING[T Expression](arr Array[T], delim StringExpression) StringExpression { + return StringExp(Func("ARRAY_TO_STRING", arr, delim)) +} + +// ARRAY_UPPER returns the upper bound of the requested array dimension. +func ARRAY_UPPER[E Expression](arr Array[E], dim IntegerExpression) IntegerExpression { + return IntExp(Func("ARRAY_UPPER", arr, dim)) +} + +// CARDINALITY returns the total number of elements in the array, or 0 if the array is empty. +func CARDINALITY[E Expression](arr Array[E]) IntegerExpression { + return IntExp(Func("CARDINALITY", arr)) +} + +// TRIM_ARRAY trims an array by removing the last n elements. If the array is multidimensional, only the first dimension is trimmed. +func TRIM_ARRAY[E Expression](arr Array[E], n IntegerExpression) Array[E] { + return ArrayExp[E](Func("TRIM_ARRAY", arr, n)) +} + +// ARRAY constructor is an expression that builds an array value using values for its member elements. +func ARRAY[T Expression](elems ...T) Array[T] { + return jet.ARRAY[T](elems...) +} + +func optionalAppend[O Expression](elem []Expression, optional []O) []Expression { + if len(optional) == 0 { + return elem + } + + return append(elem, optional[0]) +} + +//---------- Data Type Formatting Functions ----------------------// // TO_CHAR converts expression to string with format var TO_CHAR = jet.TO_CHAR diff --git a/postgres/functions_test.go b/postgres/functions_test.go index c7afea8..06c1d05 100644 --- a/postgres/functions_test.go +++ b/postgres/functions_test.go @@ -1,6 +1,7 @@ package postgres import ( + "github.com/lib/pq" "testing" ) @@ -34,3 +35,41 @@ func TestGENERATE_SERIES(t *testing.T) { "GENERATE_SERIES(NOW(), NOW() + INTERVAL '10 DAY', INTERVAL '2 DAY')", ) } + +func TestArrayFunctions(t *testing.T) { + + intArray := Int32Array(1, 2, 3) + stringArrayColumn := StringArrayColumn("str_arr_col") + + assertSerialize(t, ARRAY_LOWER(intArray), "ARRAY_LOWER($1::integer[])", pq.Int32Array{1, 2, 3}) + assertSerialize(t, ARRAY_DIMS(stringArrayColumn).EQ(String("[1,1]")), + "(ARRAY_DIMS(str_arr_col) = $1::text)", + "[1,1]", + ) + assertSerialize(t, ARRAY_NDIMS(stringArrayColumn).EQ(Int(1)), "(ARRAY_NDIMS(str_arr_col) = $1)", int64(1)) + assertSerialize(t, ARRAY_REVERSE(stringArrayColumn), "ARRAY_REVERSE(str_arr_col)") + assertSerialize(t, ARRAY_SAMPLE(stringArrayColumn, Int(2)).AT(Int(1)).EQ(String("john")), + "(ARRAY_SAMPLE(str_arr_col, $1)[$2] = $3::text)", + int64(2), int64(1), "john", + ) + + assertSerialize(t, ARRAY_SHUFFLE(intArray).AT(Int(2)).EQ(Int(33)), + "(ARRAY_SHUFFLE($1::integer[])[$2] = $3)", + pq.Int32Array{1, 2, 3}, int64(2), int64(33), + ) + + assertSerialize(t, ARRAY_SORT(stringArrayColumn, Bool(true)), + "ARRAY_SORT(str_arr_col, $1::boolean)", + true, + ) + + assertSerialize(t, ARRAY_SORT(stringArrayColumn, Bool(true), Bool(false)), + "ARRAY_SORT(str_arr_col, $1::boolean, $2::boolean)", + true, false, + ) + + assertSerialize(t, TRIM_ARRAY(stringArrayColumn, Int(6)), + "TRIM_ARRAY(str_arr_col, $1)", + int64(6), + ) +} diff --git a/postgres/literal.go b/postgres/literal.go index a6a1618..1e93110 100644 --- a/postgres/literal.go +++ b/postgres/literal.go @@ -1,6 +1,8 @@ package postgres import ( + "fmt" + "github.com/lib/pq" "time" "github.com/go-jet/jet/v2/internal/jet" @@ -68,8 +70,11 @@ func Double(value float64) FloatExpression { } // Decimal creates new float literal expression -var Decimal = jet.Decimal +func Decimal(value string) FloatExpression { + return CAST(jet.Literal(value)).AS_DECIMAL() +} +// String creates new string literal expression // String is a parameter constructor for the PostgreSQL text type. Using the `Text` constructor is // generally preferable. // @@ -124,7 +129,9 @@ func Json(value interface{}) StringExpression { // UUID is a helper function to create string literal expression from uuid object // value can be any uuid type with a String method -var UUID = jet.UUID +func UUID(value fmt.Stringer) StringExpression { + return CAST(jet.Literal(value.String())).AS_UUID() +} // Bytea creates new bytea literal expression func Bytea(value interface{}) ByteaExpression { @@ -185,3 +192,63 @@ func Timestampz(year int, month time.Month, day, hour, minute, second int, milli func TimestampzT(t time.Time) TimestampzExpression { return CAST(jet.TimestampzT(t)).AS_TIMESTAMPZ() } + +// BoolArray creates new bool array literal expression from list of values +func BoolArray(values ...bool) Array[BoolExpression] { + return CAST(jet.Literal(pq.BoolArray(values))).AS_BOOL_ARRAY() +} + +// Int32Array creates new integer array literal expression from list of values +func Int32Array(values ...int32) Array[IntegerExpression] { + return CAST(jet.Literal(pq.Int32Array(values))).AS_INTEGER_ARRAY() +} + +// Int64Array creates new bigint array literal expression from list of values +func Int64Array(values ...int64) Array[IntegerExpression] { + return CAST(jet.Literal(pq.Int64Array(values))).AS_BIGINT_ARRAY() +} + +// Float32Array creates new real array literal expression from list of values +func Float32Array(values ...float32) Array[FloatExpression] { + return CAST(jet.Literal(pq.Float32Array(values))).AS_REAL_ARRAY() +} + +// Float64Array creates new double precision array literal expression from list of values +func Float64Array(values ...float64) Array[FloatExpression] { + return CAST(jet.Literal(pq.Float64Array(values))).AS_DOUBLE_ARRAY() +} + +// StringArray creates new string array literal expression from list of values +func StringArray(values ...string) Array[StringExpression] { + return CAST(jet.Literal(pq.StringArray(values))).AS_TEXT_ARRAY() +} + +// ByteaArray creates new bytea array literal expression from list of values +func ByteaArray(values ...[]byte) Array[ByteaExpression] { + return CAST(jet.Literal(pq.ByteaArray(values))).AS_BYTEA_ARRAY() +} + +// DateArray creates new date array literal expression from list of values +func DateArray(values ...time.Time) Array[DateExpression] { + return CAST(jet.Literal(pq.Array(values))).AS_DATE_ARRAY() +} + +// TimestampArray creates new timestamp array literal expression from list of values +func TimestampArray(values ...time.Time) Array[TimestampExpression] { + return CAST(jet.Literal(pq.Array(values))).AS_TIMESTAMP_ARRAY() +} + +// TimestampzArray creates new timestampt with timezone array literal expression from list of values +func TimestampzArray(values ...time.Time) Array[TimestampzExpression] { + return CAST(jet.Literal(pq.Array(values))).AS_TIMESTAMPZ_ARRAY() +} + +// TimeArray creates new time array literal expression from list of values +func TimeArray(values ...time.Time) Array[TimeExpression] { + return CAST(jet.Literal(pq.Array(values))).AS_TIME_ARRAY() +} + +// TimezArray creates new time with timezone array literal expression from list of values +func TimezArray(values ...time.Time) Array[TimezExpression] { + return CAST(jet.Literal(pq.Array(values))).AS_TIMEZ_ARRAY() +} diff --git a/postgres/utils_test.go b/postgres/utils_test.go index 96bb13b..d89b17b 100644 --- a/postgres/utils_test.go +++ b/postgres/utils_test.go @@ -18,6 +18,8 @@ var table1ColBool = BoolColumn("col_bool") var table1ColDate = DateColumn("col_date") var table1ColInterval = IntervalColumn("col_interval") var table1ColRange = Int8RangeColumn("col_range") +var table1ColStringArray = StringArrayColumn("col_string_array") +var table1ColIntArray = IntegerArrayColumn("col_int_array") var table1 = NewTable( "db", @@ -34,6 +36,8 @@ var table1 = NewTable( table1ColTimestampz, table1ColInterval, table1ColRange, + table1ColStringArray, + table1ColIntArray, ) var table2Col3 = IntegerColumn("col3") @@ -49,8 +53,10 @@ var table2ColTimestampz = TimestampzColumn("col_timestampz") var table2ColDate = DateColumn("col_date") var table2ColInterval = IntervalColumn("col_interval") var table2ColRange = Int8RangeColumn("col_range") +var table2ColStringArray = StringArrayColumn("col_string_array") +var table2ColIntArray = IntegerArrayColumn("col_int_array") -var table2 = NewTable("db", "table2", "", table2Col3, table2Col4, table2ColInt, table2ColFloat, table2ColStr, table2ColBool, table2ColTime, table2ColTimez, table2ColDate, table2ColTimestamp, table2ColTimestampz, table2ColInterval, table2ColRange) +var table2 = NewTable("db", "table2", "", table2Col3, table2Col4, table2ColInt, table2ColFloat, table2ColStr, table2ColBool, table2ColTime, table2ColTimez, table2ColDate, table2ColTimestamp, table2ColTimestampz, table2ColInterval, table2ColRange, table2ColStringArray, table2ColIntArray) var table3Col1 = IntegerColumn("col1") var table3ColInt = IntegerColumn("col_int") diff --git a/tests/docker-compose.yaml b/tests/docker-compose.yaml index 8c0d2a2..6375cc4 100644 --- a/tests/docker-compose.yaml +++ b/tests/docker-compose.yaml @@ -1,4 +1,3 @@ -version: '3' services: postgres: image: postgres:14.1 @@ -13,7 +12,7 @@ services: - ./testdata/init/postgres:/docker-entrypoint-initdb.d mysql: - image: mysql:8.0.27 + image: mysql/mysql-server:8.0.27 command: ['--default-authentication-plugin=mysql_native_password', '--log_bin_trust_function_creators=1'] restart: always environment: diff --git a/tests/postgres/alltypes_test.go b/tests/postgres/alltypes_test.go index 36c8d62..d7338fe 100644 --- a/tests/postgres/alltypes_test.go +++ b/tests/postgres/alltypes_test.go @@ -2,12 +2,12 @@ package postgres import ( "encoding/base64" - "fmt" "github.com/go-jet/jet/v2/internal/utils/ptr" "github.com/stretchr/testify/assert" "math" "github.com/go-jet/jet/v2/qrm" + "github.com/lib/pq" "testing" "time" @@ -44,8 +44,7 @@ func TestAllTypesSelectJson(t *testing.T) { AllTypesAllColumns.Except( AllTypes.JSON, AllTypes.JSONPtr, AllTypes.Jsonb, AllTypes.JsonbPtr, - AllTypes.TextArray, AllTypes.TextArrayPtr, - AllTypes.JsonbArray, AllTypes.IntegerArray, AllTypes.IntegerArrayPtr, + AllTypes.JsonbArray, AllTypes.TextMultiDimArray, AllTypes.TextMultiDimArrayPtr, ), // unsupported at the moment, casting to text allows these columns to be assigned to string fields @@ -53,11 +52,7 @@ func TestAllTypesSelectJson(t *testing.T) { CAST(AllTypes.JSON).AS_TEXT().AS("JSON"), CAST(AllTypes.JsonbPtr).AS_TEXT().AS("jsonbPtr"), CAST(AllTypes.Jsonb).AS_TEXT().AS("Jsonb"), - CAST(AllTypes.TextArrayPtr).AS_TEXT().AS("TextArrayPtr"), - CAST(AllTypes.TextArray).AS_TEXT().AS("TextArray"), - CAST(AllTypes.JsonbArray).AS_TEXT().AS("JsonbArray"), - CAST(AllTypes.IntegerArray).AS_TEXT().AS("IntegerArray"), - CAST(AllTypes.IntegerArrayPtr).AS_TEXT().AS("IntegerArrayPtr"), + CAST(AllTypes.JsonbArray).AS_TEXT_ARRAY().AS("JsonbArray"), CAST(AllTypes.TextMultiDimArray).AS_TEXT().AS("TextMultiDimArray"), CAST(AllTypes.TextMultiDimArrayPtr).AS_TEXT().AS("TextMultiDimArrayPtr"), ).FROM(AllTypes) @@ -115,17 +110,17 @@ FROM ( all_types.uuid AS "uuid", all_types.xml_ptr AS "xmlPtr", all_types.xml AS "xml", + all_types.integer_array_ptr AS "integerArrayPtr", + all_types.integer_array AS "integerArray", + all_types.text_array_ptr AS "textArrayPtr", + all_types.text_array AS "textArray", all_types.mood_ptr AS "moodPtr", all_types.mood AS "mood", all_types.json_ptr::text AS "jsonPtr", all_types.json::text AS "JSON", all_types.jsonb_ptr::text AS "jsonbPtr", all_types.jsonb::text AS "Jsonb", - all_types.text_array_ptr::text AS "TextArrayPtr", - all_types.text_array::text AS "TextArray", - all_types.jsonb_array::text AS "JsonbArray", - all_types.integer_array::text AS "IntegerArray", - all_types.integer_array_ptr::text AS "IntegerArrayPtr", + all_types.jsonb_array::text[] AS "JsonbArray", all_types.text_multi_dim_array::text AS "TextMultiDimArray", all_types.text_multi_dim_array_ptr::text AS "TextMultiDimArrayPtr" FROM test_sample.all_types @@ -257,7 +252,7 @@ func TestUUIDType(t *testing.T) { SELECT all_types.uuid AS "all_types.uuid", all_types.uuid_ptr AS "all_types.uuid_ptr" FROM test_sample.all_types -WHERE all_types.uuid = 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'; +WHERE all_types.uuid = 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid; `, "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11") result := model.AllTypes{} @@ -873,10 +868,7 @@ FROM ( err := stmtJson.QueryContext(ctx, db, &destSelectJson) require.NoError(t, err) - testutils.PrintJson(destSelectJson) - require.Equal(t, dest, destSelectJson) - }) } @@ -1581,8 +1573,6 @@ func TestInterval(t *testing.T) { AllTypes.IntervalPtr.DIV(Float(22.222)).EQ(AllTypes.IntervalPtr), ).FROM(AllTypes) - fmt.Println(stmt.Sql()) - testutils.AssertDebugStatementSql(t, stmt, ` SELECT INTERVAL '1 YEAR', INTERVAL '1 MONTH', @@ -2243,11 +2233,11 @@ var allTypesRow0 = model.AllTypes{ JSON: `{"a": 1, "b": 3}`, JsonbPtr: ptr.Of(`{"a": 1, "b": 3}`), Jsonb: `{"a": 1, "b": 3}`, - IntegerArrayPtr: ptr.Of("{1,2,3}"), - IntegerArray: "{1,2,3}", - TextArrayPtr: ptr.Of("{breakfast,consulting}"), - TextArray: "{breakfast,consulting}", - JsonbArray: `{"{\"a\": 1, \"b\": 2}","{\"a\": 3, \"b\": 4}"}`, + IntegerArrayPtr: &pq.Int32Array{1, 2, 3}, + IntegerArray: pq.Int32Array{1, 2, 3}, + TextArrayPtr: &pq.StringArray{"breakfast", "consulting"}, + TextArray: pq.StringArray{"breakfast", "consulting"}, + JsonbArray: pq.StringArray{`{"a": 1, "b": 2}`, `{"a": 3, "b": 4}`}, TextMultiDimArrayPtr: ptr.Of("{{meeting,lunch},{training,presentation}}"), TextMultiDimArray: "{{meeting,lunch},{training,presentation}}", MoodPtr: &moodSad, @@ -2312,10 +2302,10 @@ var allTypesRow1 = model.AllTypes{ JsonbPtr: nil, Jsonb: `{"a": 1, "b": 3}`, IntegerArrayPtr: nil, - IntegerArray: "{1,2,3}", + IntegerArray: pq.Int32Array{1, 2, 3}, TextArrayPtr: nil, - TextArray: "{breakfast,consulting}", - JsonbArray: `{"{\"a\": 1, \"b\": 2}","{\"a\": 3, \"b\": 4}"}`, + TextArray: pq.StringArray{"breakfast", "consulting"}, + JsonbArray: pq.StringArray{`{"a": 1, "b": 2}`, `{"a": 3, "b": 4}`}, TextMultiDimArrayPtr: nil, TextMultiDimArray: "{{meeting,lunch},{training,presentation}}", MoodPtr: nil, diff --git a/tests/postgres/array_test.go b/tests/postgres/array_test.go new file mode 100644 index 0000000..b1677c8 --- /dev/null +++ b/tests/postgres/array_test.go @@ -0,0 +1,726 @@ +package postgres + +import ( + "github.com/go-jet/jet/v2/internal/testutils" + "github.com/go-jet/jet/v2/internal/utils/ptr" + . "github.com/go-jet/jet/v2/postgres" + "github.com/go-jet/jet/v2/qrm" + "github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/test_sample/enum" + "github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/test_sample/model" + . "github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/test_sample/table" + "github.com/google/uuid" + "github.com/lib/pq" + "github.com/stretchr/testify/require" + "testing" + "time" +) + +func TestArraySelect(t *testing.T) { + stmt := SELECT( + SampleArrays.AllColumns, + ).FROM( + SampleArrays, + ) + + testutils.AssertDebugStatementSql(t, stmt, ` +SELECT sample_arrays.id AS "sample_arrays.id", + sample_arrays.bool_array AS "sample_arrays.bool_array", + sample_arrays.int2_array_ptr AS "sample_arrays.int2_array_ptr", + sample_arrays.int4_array AS "sample_arrays.int4_array", + sample_arrays.int8_array AS "sample_arrays.int8_array", + sample_arrays.numeric_array AS "sample_arrays.numeric_array", + sample_arrays.decimal_array AS "sample_arrays.decimal_array", + sample_arrays.real_array AS "sample_arrays.real_array", + sample_arrays.double_array AS "sample_arrays.double_array", + sample_arrays.text_array AS "sample_arrays.text_array", + sample_arrays.varchar_array AS "sample_arrays.varchar_array", + sample_arrays.char_array AS "sample_arrays.char_array", + sample_arrays.bytea_array AS "sample_arrays.bytea_array", + sample_arrays.date_array AS "sample_arrays.date_array", + sample_arrays.timestamp_array AS "sample_arrays.timestamp_array", + sample_arrays.timestamptz_array AS "sample_arrays.timestamptz_array", + sample_arrays.time_array AS "sample_arrays.time_array", + sample_arrays.timetz_array AS "sample_arrays.timetz_array", + sample_arrays.interval_array AS "sample_arrays.interval_array", + sample_arrays.uuid_array AS "sample_arrays.uuid_array", + sample_arrays.mood_enum_array AS "sample_arrays.mood_enum_array" +FROM test_sample.sample_arrays; +`) + + var dest []model.SampleArrays + + err := stmt.Query(db, &dest) + + require.NoError(t, err) + require.Len(t, dest, 1) + require.Equal(t, dest[0], sampleArrayRow0) +} + +func TestArrayOperations(t *testing.T) { + + boolArray := BoolArray(true, false, false, true) + int32Array := Int32Array(-1, 2, -3, 4, 5) + int64Array := Int64Array(10, -11, 12, -13, 14, 1515551) + float32Array := Float32Array(1.01, -2.02, 3.03, 4.04) + float64Array := Float64Array(10.001, 20.002, -3.003, 400050.04) + stringArray := StringArray("temp", "text", "array") + byteaArray := ByteaArray([]byte("temporal"), []byte("byte array"), []byte("array")) + dateArray := DateArray(*testutils.Date("2022-04-06"), *testutils.Date("2018-05-06")) + dateArray2 := ARRAY(Date(2022, 2, 3), Date(2023, 2, 2)) + timestampArray := TimestampArray(*testutils.TimestampWithoutTimeZone("1999-01-08 04:05:06", 0)) + timestampzArray := TimestampzArray(time.Date(2022, 1, 1, 8, 30, 50, 0, time.UTC)) + timestampzArray2 := ARRAY(Timestampz(2023, 2, 3, 10, 29, 34, 1000, "UTC")) + timeArray := TimeArray(*testutils.TimeWithoutTimeZone("14:20:45"), *testutils.TimeWithoutTimeZone("8:10:15")) + timezArray := TimezArray(*testutils.TimeWithTimeZone("04:05:06 -0800"), *testutils.TimeWithTimeZone("01:02:03 -0600")) + timeArray2 := ARRAY(Time(10, 20, 30), Time(5, 45, 45)) + timezArray2 := ARRAY(Timez(10, 20, 30, 0, "UTC"), Timez(5, 45, 45, 0, "UTC")) + + timestampz := Timestampz(1950, 2, 3, 10, 30, 40, 0, "UTC") + + query := SELECT( + // array constructors + boolArray.AS("bool_array"), + int32Array.AS("int32_array"), + int64Array.AS("int64_array"), + float32Array.AS("float32_array"), + float64Array.AS("float64_array"), + stringArray.AS("string_array"), + byteaArray.AS("bytea_array"), + dateArray.AS("date_array"), + timestampArray.AS("timestamp_array"), + timestampzArray.AS("timestampz_array"), + timeArray.AS("time_array"), + timezArray.AS("timez_array"), + + // operators + SampleArrays.BoolArray.EQ(boolArray).AS("bool_eq"), + SampleArrays.TextArray.EQ(SampleArrays.TextArray).AS("text_eq"), + SampleArrays.TextArray.NOT_EQ(stringArray).AS("text_neq"), + SampleArrays.Int4Array.LT(int32Array).IS_TRUE().AS("int4_lt"), + SampleArrays.Int8Array.LT_EQ(int64Array).IS_FALSE().AS("int8_lteq"), + SampleArrays.RealArray.GT(float32Array).AS("decimal_gt"), + SampleArrays.DoubleArray.GT_EQ(float64Array).AS("numeric_gt_eq"), + SampleArrays.ByteaArray.CONTAINS(byteaArray).AS("bytea_contains"), + byteaArray.IS_CONTAINED_BY(SampleArrays.ByteaArray).AS("bytea_contained_by"), + SampleArrays.DateArray.OVERLAP(dateArray2).AS("date_overlaps"), + SampleArrays.TimestampArray.CONCAT(timestampArray).AS("timestamp_concat"), + timestampzArray2.CONCAT_ELEMENT(timestampz).AS("timestampz_concat_elem"), + SampleArrays.TimeArray.AT(Int32(1)).AS("time_at"), + + Int32(22).EQ(ANY(SampleArrays.Int4Array)).AS("int32_eq_any"), + Double(7.89).NOT_EQ(ANY(SampleArrays.DoubleArray)).AS("double_neq_any"), + String("temp").EQ(ALL(stringArray)).AS("string_eq_all"), + + // functions + ARRAY_APPEND(SampleArrays.TextArray, String("after")).AS("append"), + ARRAY_CAT(SampleArrays.TimeArray, timeArray2).AS("cat"), + ARRAY_LENGTH(timezArray2, Int32(1)).AS("length"), + // ARRAY_LOWER(SampleArrays.UUIDArray).AS("lower"), + ARRAY_POSITION(SampleArrays.Int4Array, Int32(30)).AS("position"), + //ARRAY_POSITION(SampleArrays.DoubleArray, Float(33.33), Int(1)).AS("position_from"), + ARRAY_POSITIONS(stringArray, String("text")).AS("positions"), + ARRAY_PREPEND(String("before"), SampleArrays.TextArray).AS("prepend"), + ARRAY_REMOVE(boolArray, Bool(true)).AS("remove"), + ARRAY_REPLACE(SampleArrays.VarcharArray, String("hello"), String("hi")).AS("replace"), + //ARRAY_REVERSE(SampleArrays.TextArray).AS("reverse"), + //ARRAY_SAMPLE(SampleArrays.TimestampArray, Int(2)).AS("sample"), + //ARRAY_SHUFFLE(SampleArrays.BoolArray).AS("shuffle"), + //ARRAY_SORT(SampleArrays.Int8Array, Bool(true)), + ARRAY_TO_STRING(SampleArrays.MoodEnumArray, String(", ")).AS("to_string"), + ARRAY_UPPER(SampleArrays.Int8Array, Int(1)).AS("upper"), + CARDINALITY(SampleArrays.DoubleArray).AS("cardinality"), + + // unsupported by cockroachdb + + //ARRAY_DIMS(SampleArrays.IntervalArray).AS("dims"), + //ARRAY_NDIMS(SampleArrays.TextArray).AS("ndims"), + //TRIM_ARRAY(SampleArrays.DateArray, Int(1)).AS("trim"), + + ).FROM( + SampleArrays, + ).WHERE( + SampleArrays.BoolArray.CONTAINS(BoolArray(true)), + ) + + testutils.AssertStatementSql(t, query, ` +SELECT $1::boolean[] AS "bool_array", + $2::integer[] AS "int32_array", + $3::bigint[] AS "int64_array", + $4::real[] AS "float32_array", + $5::double precision[] AS "float64_array", + $6::text[] AS "string_array", + $7::bytea[] AS "bytea_array", + $8::date[] AS "date_array", + $9::timestamp without time zone[] AS "timestamp_array", + $10::timestamp with time zone[] AS "timestampz_array", + $11::time without time zone[] AS "time_array", + $12::time with time zone[] AS "timez_array", + (sample_arrays.bool_array = $13::boolean[]) AS "bool_eq", + (sample_arrays.text_array = sample_arrays.text_array) AS "text_eq", + (sample_arrays.text_array != $14::text[]) AS "text_neq", + (sample_arrays.int4_array < $15::integer[]) IS TRUE AS "int4_lt", + (sample_arrays.int8_array <= $16::bigint[]) IS FALSE AS "int8_lteq", + (sample_arrays.real_array > $17::real[]) AS "decimal_gt", + (sample_arrays.double_array >= $18::double precision[]) AS "numeric_gt_eq", + (sample_arrays.bytea_array @> $19::bytea[]) AS "bytea_contains", + ($20::bytea[] <@ sample_arrays.bytea_array) AS "bytea_contained_by", + (sample_arrays.date_array && ARRAY[$21::date,$22::date]) AS "date_overlaps", + (sample_arrays.timestamp_array || $23::timestamp without time zone[]) AS "timestamp_concat", + (ARRAY[$24::timestamp with time zone] || $25::timestamp with time zone) AS "timestampz_concat_elem", + sample_arrays.time_array[$26::integer] AS "time_at", + ($27::integer = ANY(sample_arrays.int4_array)) AS "int32_eq_any", + ($28::double precision != ANY(sample_arrays.double_array)) AS "double_neq_any", + ($29::text = ALL($30::text[])) AS "string_eq_all", + ARRAY_APPEND(sample_arrays.text_array, $31::text) AS "append", + ARRAY_CAT(sample_arrays.time_array, ARRAY[$32::time without time zone,$33::time without time zone]) AS "cat", + ARRAY_LENGTH(ARRAY[$34::time with time zone,$35::time with time zone], $36::integer) AS "length", + ARRAY_POSITION(sample_arrays.int4_array, $37::integer) AS "position", + ARRAY_POSITIONS($38::text[], $39::text) AS "positions", + ARRAY_PREPEND($40::text, sample_arrays.text_array) AS "prepend", + ARRAY_REMOVE($41::boolean[], $42::boolean) AS "remove", + ARRAY_REPLACE(sample_arrays.varchar_array, $43::text, $44::text) AS "replace", + ARRAY_TO_STRING(sample_arrays.mood_enum_array, $45::text) AS "to_string", + ARRAY_UPPER(sample_arrays.int8_array, $46) AS "upper", + CARDINALITY(sample_arrays.double_array) AS "cardinality" +FROM test_sample.sample_arrays +WHERE sample_arrays.bool_array @> $47::boolean[]; +`) + + var dest struct { + // array constructors + BoolArray pq.BoolArray + Int32Array pq.Int32Array + Int64Array pq.Int64Array + Float32Array pq.Float32Array + Float64Array pq.Float64Array + StringArray pq.StringArray + ByteaArray pq.ByteaArray + DateArray pq.StringArray + TimestampArray pq.StringArray + TimestampzArray pq.StringArray + TimeArray pq.StringArray + TimezArray pq.StringArray + + // array operators + TextEq bool + BoolEq bool + TextNeq bool + Int4Lt bool + Int8Lteq bool + DecimalGt bool + NumericGtEq bool + ByteaContains bool + ByteaContainedBy bool + DateOverlaps bool + TimestampConcat pq.StringArray + TimestampzConcatElem pq.StringArray + TimeAt time.Time + + Int32EqAny bool + DoubleNeqAny bool + StringEqAll bool + + // functions + Append pq.StringArray + Cat pq.StringArray + Dims string + Length int32 + Lower int32 + NDims int32 + Position *int32 + PositionFrom *int32 + Positions pq.Int32Array + Prepend pq.StringArray + Remove pq.BoolArray + Replace pq.StringArray + ToString string + Upper int32 + Cardinality int32 + Trim pq.StringArray + } + + err := query.Query(db, &dest) + require.NoError(t, err) + + testutils.AssertJSON(t, dest, ` +{ + "BoolArray": [ + true, + false, + false, + true + ], + "Int32Array": [ + -1, + 2, + -3, + 4, + 5 + ], + "Int64Array": [ + 10, + -11, + 12, + -13, + 14, + 1515551 + ], + "Float32Array": [ + 1.01, + -2.02, + 3.03, + 4.04 + ], + "Float64Array": [ + 10.001, + 20.002, + -3.003, + 400050.04 + ], + "StringArray": [ + "temp", + "text", + "array" + ], + "ByteaArray": [ + "dGVtcG9yYWw=", + "Ynl0ZSBhcnJheQ==", + "YXJyYXk=" + ], + "DateArray": [ + "2022-04-06", + "2018-05-06" + ], + "TimestampArray": [ + "1999-01-08 04:05:06" + ], + "TimestampzArray": [ + "2022-01-01 08:30:50+00" + ], + "TimeArray": [ + "14:20:45", + "08:10:15" + ], + "TimezArray": [ + "04:05:06-08", + "01:02:03-06" + ], + "TextEq": true, + "BoolEq": false, + "TextNeq": true, + "Int4Lt": false, + "Int8Lteq": true, + "DecimalGt": true, + "NumericGtEq": true, + "ByteaContains": false, + "ByteaContainedBy": false, + "DateOverlaps": false, + "TimestampConcat": [ + "2025-01-01 10:00:00", + "2025-02-01 10:00:00", + "1999-01-08 04:05:06" + ], + "TimestampzConcatElem": [ + "2023-02-03 10:29:34.000001+00", + "1950-02-03 10:30:40+00" + ], + "TimeAt": "0000-01-01T12:00:00Z", + "Int32EqAny": false, + "DoubleNeqAny": true, + "StringEqAll": false, + "Append": [ + "alpha", + "beta", + "gama", + "after" + ], + "Cat": [ + "12:00:00", + "13:00:00", + "10:20:30", + "05:45:45" + ], + "Dims": "", + "Length": 2, + "Lower": 0, + "NDims": 0, + "Position": 3, + "PositionFrom": null, + "Positions": [ + 2 + ], + "Prepend": [ + "before", + "alpha", + "beta", + "gama" + ], + "Remove": [ + false, + false + ], + "Replace": [ + "hi", + "world" + ], + "ToString": "happy, ok", + "Upper": 4, + "Cardinality": 3, + "Trim": null +} +`) + requireLogged(t, query) +} + +func TestArraySelectColumnsFromSubQuery(t *testing.T) { + + subQuery := SELECT( + SampleArrays.AllColumns, + Int64Array(10, -11, 12, -13, 14, 1515551).AS("int64_array"), + ).FROM( + SampleArrays, + ).AsTable("sub_query") + + int64Array := IntegerArrayColumn("int64_array").From(subQuery) + + stmt := SELECT( + subQuery.AllColumns().Except(int64Array), + int64Array, + ).FROM( + subQuery, + ) + + testutils.AssertDebugStatementSql(t, stmt, ` +SELECT sub_query."sample_arrays.id" AS "sample_arrays.id", + sub_query."sample_arrays.bool_array" AS "sample_arrays.bool_array", + sub_query."sample_arrays.int2_array_ptr" AS "sample_arrays.int2_array_ptr", + sub_query."sample_arrays.int4_array" AS "sample_arrays.int4_array", + sub_query."sample_arrays.int8_array" AS "sample_arrays.int8_array", + sub_query."sample_arrays.numeric_array" AS "sample_arrays.numeric_array", + sub_query."sample_arrays.decimal_array" AS "sample_arrays.decimal_array", + sub_query."sample_arrays.real_array" AS "sample_arrays.real_array", + sub_query."sample_arrays.double_array" AS "sample_arrays.double_array", + sub_query."sample_arrays.text_array" AS "sample_arrays.text_array", + sub_query."sample_arrays.varchar_array" AS "sample_arrays.varchar_array", + sub_query."sample_arrays.char_array" AS "sample_arrays.char_array", + sub_query."sample_arrays.bytea_array" AS "sample_arrays.bytea_array", + sub_query."sample_arrays.date_array" AS "sample_arrays.date_array", + sub_query."sample_arrays.timestamp_array" AS "sample_arrays.timestamp_array", + sub_query."sample_arrays.timestamptz_array" AS "sample_arrays.timestamptz_array", + sub_query."sample_arrays.time_array" AS "sample_arrays.time_array", + sub_query."sample_arrays.timetz_array" AS "sample_arrays.timetz_array", + sub_query."sample_arrays.interval_array" AS "sample_arrays.interval_array", + sub_query."sample_arrays.uuid_array" AS "sample_arrays.uuid_array", + sub_query."sample_arrays.mood_enum_array" AS "sample_arrays.mood_enum_array", + sub_query.int64_array AS "int64_array" +FROM ( + SELECT sample_arrays.id AS "sample_arrays.id", + sample_arrays.bool_array AS "sample_arrays.bool_array", + sample_arrays.int2_array_ptr AS "sample_arrays.int2_array_ptr", + sample_arrays.int4_array AS "sample_arrays.int4_array", + sample_arrays.int8_array AS "sample_arrays.int8_array", + sample_arrays.numeric_array AS "sample_arrays.numeric_array", + sample_arrays.decimal_array AS "sample_arrays.decimal_array", + sample_arrays.real_array AS "sample_arrays.real_array", + sample_arrays.double_array AS "sample_arrays.double_array", + sample_arrays.text_array AS "sample_arrays.text_array", + sample_arrays.varchar_array AS "sample_arrays.varchar_array", + sample_arrays.char_array AS "sample_arrays.char_array", + sample_arrays.bytea_array AS "sample_arrays.bytea_array", + sample_arrays.date_array AS "sample_arrays.date_array", + sample_arrays.timestamp_array AS "sample_arrays.timestamp_array", + sample_arrays.timestamptz_array AS "sample_arrays.timestamptz_array", + sample_arrays.time_array AS "sample_arrays.time_array", + sample_arrays.timetz_array AS "sample_arrays.timetz_array", + sample_arrays.interval_array AS "sample_arrays.interval_array", + sample_arrays.uuid_array AS "sample_arrays.uuid_array", + sample_arrays.mood_enum_array AS "sample_arrays.mood_enum_array", + '{10,-11,12,-13,14,1515551}'::bigint[] AS "int64_array" + FROM test_sample.sample_arrays + ) AS sub_query; +`) + + var dest struct { + model.SampleArrays + + Int64Array pq.Int64Array + } + + err := stmt.Query(db, &dest) + + require.NoError(t, err) + testutils.AssertDeepEqual(t, dest.SampleArrays, sampleArrayRow0) + testutils.AssertDeepEqual(t, dest.Int64Array, pq.Int64Array{10, -11, 12, -13, 14, 1515551}) +} + +func TestArrayTableInsert(t *testing.T) { + + sampleArrayRow3 := testutils.DeepCopy(t, sampleArrayRow0) + sampleArrayRow3.ID = 3 + + insertQuery := SampleArrays.INSERT(SampleArrays.AllColumns). + VALUES( + Int64(2), + ARRAY(Bool(false), Bool(false), Bool(true)), + ARRAY(Int16(4), Int16(5), Int(6)), + Int32Array(40, 50, 60), + Int64Array(400, 500, 600), + ARRAY(Decimal("1.11"), Decimal("2.22")), + ARRAY(Decimal("1.11"), Decimal("2.22")), + Float32Array(4.4, 5.5, 6.6, 7.7), + Float64Array(40.04, 50.05, 60.06, 70.07), + StringArray("john", "doe"), + ARRAY(VarChar(10)("Andy"), VarChar(10)("Bob")), + ARRAY(Char(1)("q"), Char(1)("w"), Char(1)("e")), + ByteaArray([]byte("title"), []byte("name")), + ARRAY(Date(2010, 2, 3), Date(2025, 4, 5)), + ARRAY(Timestamp(2025, 2, 3, 0, 10, 20, 0)), + ARRAY(Timestampz(2025, 2, 3, 0, 10, 20, 0, "UTC")), + ARRAY(Time(12, 15, 45), Time(2, 30, 40)), + ARRAY(Timez(12, 15, 45, 0, "UTC"), Timez(2, 30, 40, 0, "UTC")), + ARRAY(INTERVAL(1, DAY, 3, MINUTE), INTERVAL(2, YEAR, 30, DAY)), + ARRAY(UUID(uuid.MustParse("a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11"))), + CAST(ARRAY(enum.Mood.Happy, enum.Mood.Sad)).AS("test_sample.mood[]"), + ). + MODEL( + sampleArrayRow3, + ). + RETURNING(SampleArrays.AllColumns) + + testutils.AssertStatementSql(t, insertQuery, ` +INSERT INTO test_sample.sample_arrays (id, bool_array, int2_array_ptr, int4_array, int8_array, numeric_array, decimal_array, real_array, double_array, text_array, varchar_array, char_array, bytea_array, date_array, timestamp_array, timestamptz_array, time_array, timetz_array, interval_array, uuid_array, mood_enum_array) +VALUES ($1::bigint, ARRAY[$2::boolean,$3::boolean,$4::boolean], ARRAY[$5::smallint,$6::smallint,$7], $8::integer[], $9::bigint[], ARRAY[$10::decimal,$11::decimal], ARRAY[$12::decimal,$13::decimal], $14::real[], $15::double precision[], $16::text[], ARRAY[$17::varchar(10),$18::varchar(10)], ARRAY[$19::char(1),$20::char(1),$21::char(1)], $22::bytea[], ARRAY[$23::date,$24::date], ARRAY[$25::timestamp without time zone], ARRAY[$26::timestamp with time zone], ARRAY[$27::time without time zone,$28::time without time zone], ARRAY[$29::time with time zone,$30::time with time zone], ARRAY[INTERVAL '1 DAY 3 MINUTE',INTERVAL '2 YEAR 30 DAY'], ARRAY[$31::uuid], ARRAY['happy','sad']::test_sample.mood[]), + ($32, $33, $34, $35, $36, $37, $38, $39, $40, $41, $42, $43, $44, $45, $46, $47, $48, $49, $50, $51, $52) +RETURNING sample_arrays.id AS "sample_arrays.id", + sample_arrays.bool_array AS "sample_arrays.bool_array", + sample_arrays.int2_array_ptr AS "sample_arrays.int2_array_ptr", + sample_arrays.int4_array AS "sample_arrays.int4_array", + sample_arrays.int8_array AS "sample_arrays.int8_array", + sample_arrays.numeric_array AS "sample_arrays.numeric_array", + sample_arrays.decimal_array AS "sample_arrays.decimal_array", + sample_arrays.real_array AS "sample_arrays.real_array", + sample_arrays.double_array AS "sample_arrays.double_array", + sample_arrays.text_array AS "sample_arrays.text_array", + sample_arrays.varchar_array AS "sample_arrays.varchar_array", + sample_arrays.char_array AS "sample_arrays.char_array", + sample_arrays.bytea_array AS "sample_arrays.bytea_array", + sample_arrays.date_array AS "sample_arrays.date_array", + sample_arrays.timestamp_array AS "sample_arrays.timestamp_array", + sample_arrays.timestamptz_array AS "sample_arrays.timestamptz_array", + sample_arrays.time_array AS "sample_arrays.time_array", + sample_arrays.timetz_array AS "sample_arrays.timetz_array", + sample_arrays.interval_array AS "sample_arrays.interval_array", + sample_arrays.uuid_array AS "sample_arrays.uuid_array", + sample_arrays.mood_enum_array AS "sample_arrays.mood_enum_array"; +`) + + testutils.ExecuteInTxAndRollback(t, db, func(tx qrm.DB) { + var dest []model.SampleArrays + err := insertQuery.Query(tx, &dest) + + require.NoError(t, err) + require.Len(t, dest, 2) + + testutils.AssertDeepEqual(t, sampleArrayRow3, dest[1]) + testutils.AssertJSON(t, dest[0], ` +{ + "ID": 2, + "BoolArray": [ + false, + false, + true + ], + "Int2ArrayPtr": [ + "4", + "5", + "6" + ], + "Int4Array": [ + 40, + 50, + 60 + ], + "Int8Array": [ + 400, + 500, + 600 + ], + "NumericArray": [ + 1.11, + 2.22 + ], + "DecimalArray": [ + 1.11, + 2.22 + ], + "RealArray": [ + 4.4, + 5.5, + 6.6, + 7.7 + ], + "DoubleArray": [ + 40.04, + 50.05, + 60.06, + 70.07 + ], + "TextArray": [ + "john", + "doe" + ], + "VarcharArray": [ + "Andy", + "Bob" + ], + "CharArray": [ + "q", + "w", + "e" + ], + "ByteaArray": [ + "dGl0bGU=", + "bmFtZQ==" + ], + "DateArray": [ + "2010-02-03", + "2025-04-05" + ], + "TimestampArray": [ + "2025-02-03 00:10:20" + ], + "TimestamptzArray": [ + "2025-02-03 00:10:20+00" + ], + "TimeArray": [ + "12:15:45", + "02:30:40" + ], + "TimetzArray": [ + "12:15:45+00", + "02:30:40+00" + ], + "IntervalArray": [ + "1 day 00:03:00", + "2 years 30 days" + ], + "UUIDArray": [ + "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11" + ], + "MoodEnumArray": [ + "happy", + "sad" + ] +} +`) + }) +} + +func TestArrayTableUpdate(t *testing.T) { + + t.Run("using model", func(t *testing.T) { + + sampleArrayRow1Clone := testutils.DeepCopy(t, sampleArrayRow0) + sampleArrayRow1Clone.RealArray = pq.Float32Array{100.11, 200.22, 300.33} + + stmt := SampleArrays.UPDATE(SampleArrays.MutableColumns). + MODEL(sampleArrayRow1Clone). + WHERE(String("alpha").EQ(ANY(SampleArrays.TextArray))). + RETURNING(SampleArrays.AllColumns) + + testutils.AssertDebugStatementSql(t, stmt, ` +UPDATE test_sample.sample_arrays +SET (bool_array, int2_array_ptr, int4_array, int8_array, numeric_array, decimal_array, real_array, double_array, text_array, varchar_array, char_array, bytea_array, date_array, timestamp_array, timestamptz_array, time_array, timetz_array, interval_array, uuid_array, mood_enum_array) = ('{t,f,t}', '{"1","2","3","4"}', '{10,20,30,40}', '{100,200,300,400}', '{1.8881,2.8882,3.8883,4.8884}', '{1.0001,2.0002,3.0003,4.0004}', '{100.11,200.22,300.33}', '{11.11,22.22,33.33}', '{"alpha","beta","gama"}', '{"hello","world"}', '{"a","b","c"}', '{"\\x01020304","\\x11223344"}', '{"2024-11-01","2025-02-28"}', '{"2025-01-01 10:00:00","2025-02-01 10:00:00"}', '{"2025-01-01 09:00:00+00","2025-02-01 09:00:00+00"}', '{"12:00:00","13:00:00"}', '{"12:00:00+01","13:00:00+02"}', '{"1 day","02:00:00"}', '{"550e8400-e29b-41d4-a716-446655440000"}', '{"happy","ok"}') +WHERE 'alpha'::text = ANY(sample_arrays.text_array) +RETURNING sample_arrays.id AS "sample_arrays.id", + sample_arrays.bool_array AS "sample_arrays.bool_array", + sample_arrays.int2_array_ptr AS "sample_arrays.int2_array_ptr", + sample_arrays.int4_array AS "sample_arrays.int4_array", + sample_arrays.int8_array AS "sample_arrays.int8_array", + sample_arrays.numeric_array AS "sample_arrays.numeric_array", + sample_arrays.decimal_array AS "sample_arrays.decimal_array", + sample_arrays.real_array AS "sample_arrays.real_array", + sample_arrays.double_array AS "sample_arrays.double_array", + sample_arrays.text_array AS "sample_arrays.text_array", + sample_arrays.varchar_array AS "sample_arrays.varchar_array", + sample_arrays.char_array AS "sample_arrays.char_array", + sample_arrays.bytea_array AS "sample_arrays.bytea_array", + sample_arrays.date_array AS "sample_arrays.date_array", + sample_arrays.timestamp_array AS "sample_arrays.timestamp_array", + sample_arrays.timestamptz_array AS "sample_arrays.timestamptz_array", + sample_arrays.time_array AS "sample_arrays.time_array", + sample_arrays.timetz_array AS "sample_arrays.timetz_array", + sample_arrays.interval_array AS "sample_arrays.interval_array", + sample_arrays.uuid_array AS "sample_arrays.uuid_array", + sample_arrays.mood_enum_array AS "sample_arrays.mood_enum_array"; +`) + + testutils.ExecuteInTxAndRollback(t, db, func(tx qrm.DB) { + var dest []model.SampleArrays + + err := stmt.Query(tx, &dest) + + require.NoError(t, err) + require.Len(t, dest, 1) + testutils.AssertDeepEqual(t, sampleArrayRow1Clone, dest[0]) + }) + }) + + t.Run("update using SET", func(t *testing.T) { + stmt := SampleArrays.UPDATE(). + SET( + SampleArrays.Int4Array.SET(ARRAY(Int32(-10), Int32(11))), + SampleArrays.Int8Array.SET(ARRAY(Int64(-1200), Int64(7800))), + ). + WHERE(String("alpha").EQ(ANY(SampleArrays.TextArray))). + RETURNING( + SampleArrays.Int4Array, + SampleArrays.Int8Array, + ) + + testutils.AssertStatementSql(t, stmt, ` +UPDATE test_sample.sample_arrays +SET int4_array = ARRAY[$1::integer,$2::integer], + int8_array = ARRAY[$3::bigint,$4::bigint] +WHERE $5::text = ANY(sample_arrays.text_array) +RETURNING sample_arrays.int4_array AS "sample_arrays.int4_array", + sample_arrays.int8_array AS "sample_arrays.int8_array"; +`) + + testutils.ExecuteInTxAndRollback(t, db, func(tx qrm.DB) { + var dest []model.SampleArrays + + err := stmt.Query(tx, &dest) + + require.NoError(t, err) + require.Len(t, dest, 1) + testutils.AssertDeepEqual(t, dest[0].Int4Array, pq.Int32Array{-10, 11}) + testutils.AssertDeepEqual(t, dest[0].Int8Array, pq.Int64Array{-1200, 7800}) + }) + }) + +} + +var sampleArrayRow0 = model.SampleArrays{ + ID: 1, + BoolArray: ptr.Of(pq.BoolArray{true, false, true}), + Int2ArrayPtr: ptr.Of(pq.StringArray{"1", "2", "3", "4"}), + Int4Array: pq.Int32Array{10, 20, 30, 40}, + Int8Array: pq.Int64Array{100, 200, 300, 400}, + NumericArray: pq.Float64Array{1.8881, 2.8882, 3.8883, 4.8884}, + DecimalArray: pq.Float64Array{1.0001, 2.0002, 3.0003, 4.0004}, + RealArray: pq.Float32Array{1.0099999904632568, 2.0199999809265137, 3.0299999713897705, 4.039999961853027}, + DoubleArray: pq.Float64Array{11.11, 22.22, 33.33}, + TextArray: pq.StringArray{"alpha", "beta", "gama"}, + CharArray: pq.StringArray{"a", "b", "c"}, + VarcharArray: pq.StringArray{"hello", "world"}, + ByteaArray: pq.ByteaArray{{0x01, 0x02, 0x03, 0x04}, {0x11, 0x22, 0x33, 0x44}}, + DateArray: pq.StringArray{"2024-11-01", "2025-02-28"}, + TimestampArray: &pq.StringArray{"2025-01-01 10:00:00", "2025-02-01 10:00:00"}, + TimestamptzArray: pq.StringArray{"2025-01-01 09:00:00+00", "2025-02-01 09:00:00+00"}, + TimeArray: pq.StringArray{"12:00:00", "13:00:00"}, + TimetzArray: pq.StringArray{"12:00:00+01", "13:00:00+02"}, + IntervalArray: pq.StringArray{"1 day", "02:00:00"}, + UUIDArray: pq.StringArray{"550e8400-e29b-41d4-a716-446655440000"}, + MoodEnumArray: pq.StringArray{"happy", "ok"}, +} diff --git a/tests/postgres/generator_template_test.go b/tests/postgres/generator_template_test.go index b295862..91d419d 100644 --- a/tests/postgres/generator_template_test.go +++ b/tests/postgres/generator_template_test.go @@ -450,7 +450,7 @@ func TestGeneratorTemplate_Model_ChangeFieldTypes(t *testing.T) { require.Contains(t, data, `"github.com/google/uuid"`) require.Contains(t, data, "Description sql.NullString") require.Contains(t, data, "ReleaseYear sql.NullInt32") - require.Contains(t, data, "SpecialFeatures sql.NullString") + require.Contains(t, data, "SpecialFeatures *pq.StringArray") require.Contains(t, data, "LastUpdate sql.Null[uuid.UUID]") } diff --git a/tests/postgres/generator_test.go b/tests/postgres/generator_test.go index d8f468c..46626a5 100644 --- a/tests/postgres/generator_test.go +++ b/tests/postgres/generator_test.go @@ -319,7 +319,7 @@ func TestGenerator_TableMetadata(t *testing.T) { }, } require.Equal(t, want, got) - require.Equal(t, metadata.ArrayType, specialFeatures.DataType.Kind) + require.Equal(t, 1, specialFeatures.DataType.Dimensions) } func TestGeneratorSpecialCharacters(t *testing.T) { @@ -765,13 +765,13 @@ func TestGeneratedAllTypesSQLBuilderFiles(t *testing.T) { testutils.AssertFileNamesEqual(t, modelDir, "all_types.go", "all_types_view.go", "employee.go", "link.go", "mood.go", "person.go", "person_phone.go", "weird_names_table.go", "level.go", "user.go", "floats.go", "people.go", - "components.go", "vulnerabilities.go", "all_types_materialized_view.go", "sample_ranges.go") + "components.go", "vulnerabilities.go", "all_types_materialized_view.go", "sample_ranges.go", "sample_arrays.go") testutils.AssertFileContent(t, modelDir+"/all_types.go", allTypesModelContent) testutils.AssertFileContent(t, modelDir+"/link.go", linkModelContent) testutils.AssertFileNamesEqual(t, tableDir, "all_types.go", "employee.go", "link.go", "person.go", "person_phone.go", "weird_names_table.go", "user.go", "floats.go", "people.go", "table_use_schema.go", - "components.go", "vulnerabilities.go", "sample_ranges.go") + "components.go", "vulnerabilities.go", "sample_ranges.go", "sample_arrays.go") testutils.AssertFileContent(t, tableDir+"/all_types.go", allTypesTableContent) testutils.AssertFileContent(t, tableDir+"/sample_ranges.go", sampleRangeTableContent) @@ -844,6 +844,7 @@ package model import ( "github.com/google/uuid" + "github.com/lib/pq" "time" ) @@ -902,11 +903,11 @@ type AllTypes struct { JSON string JsonbPtr *string Jsonb string - IntegerArrayPtr *string - IntegerArray string - TextArrayPtr *string - TextArray string - JsonbArray string + IntegerArrayPtr *pq.Int32Array + IntegerArray pq.Int32Array + TextArrayPtr *pq.StringArray + TextArray pq.StringArray + JsonbArray pq.StringArray TextMultiDimArrayPtr *string TextMultiDimArray string MoodPtr *Mood @@ -1007,11 +1008,11 @@ type allTypesTable struct { JSON postgres.ColumnString JsonbPtr postgres.ColumnString Jsonb postgres.ColumnString - IntegerArrayPtr postgres.ColumnString - IntegerArray postgres.ColumnString - TextArrayPtr postgres.ColumnString - TextArray postgres.ColumnString - JsonbArray postgres.ColumnString + IntegerArrayPtr postgres.ColumnIntegerArray + IntegerArray postgres.ColumnIntegerArray + TextArrayPtr postgres.ColumnStringArray + TextArray postgres.ColumnStringArray + JsonbArray postgres.ColumnStringArray TextMultiDimArrayPtr postgres.ColumnString TextMultiDimArray postgres.ColumnString MoodPtr postgres.ColumnString @@ -1111,11 +1112,11 @@ func newAllTypesTableImpl(schemaName, tableName, alias string) allTypesTable { JSONColumn = postgres.StringColumn("json") JsonbPtrColumn = postgres.StringColumn("jsonb_ptr") JsonbColumn = postgres.StringColumn("jsonb") - IntegerArrayPtrColumn = postgres.StringColumn("integer_array_ptr") - IntegerArrayColumn = postgres.StringColumn("integer_array") - TextArrayPtrColumn = postgres.StringColumn("text_array_ptr") - TextArrayColumn = postgres.StringColumn("text_array") - JsonbArrayColumn = postgres.StringColumn("jsonb_array") + IntegerArrayPtrColumn = postgres.IntegerArrayColumn("integer_array_ptr") + IntegerArrayColumn = postgres.IntegerArrayColumn("integer_array") + TextArrayPtrColumn = postgres.StringArrayColumn("text_array_ptr") + TextArrayColumn = postgres.StringArrayColumn("text_array") + JsonbArrayColumn = postgres.StringArrayColumn("jsonb_array") TextMultiDimArrayPtrColumn = postgres.StringColumn("text_multi_dim_array_ptr") TextMultiDimArrayColumn = postgres.StringColumn("text_multi_dim_array") MoodPtrColumn = postgres.StringColumn("mood_ptr") @@ -1687,3 +1688,192 @@ func TestCamelCaseModelJsonTag(t *testing.T) { }) } } + +func TestGeneratorTestSample(t *testing.T) { + + err := postgres.GenerateDSN(defaultDSN(), "test_sample", genTestDir2) + require.NoError(t, err) + + modelDir := filepath.Join(testRoot, "/postgres/.gentestdata2/jetdb/test_sample/model/") + tableDir := filepath.Join(testRoot, "/postgres/.gentestdata2/jetdb/test_sample/table/") + + testutils.AssertFileContent(t, modelDir+"/sample_arrays.go", ` +// +// Code generated by go-jet DO NOT EDIT. +// +// WARNING: Changes to this file may cause incorrect behavior +// and will be lost if the code is regenerated +// + +package model + +import ( + "github.com/lib/pq" +) + +type SampleArrays struct { + ID int32 `+"`sql:\"primary_key\"`"+` + BoolArray *pq.BoolArray + Int2ArrayPtr *pq.StringArray + Int4Array pq.Int32Array + Int8Array pq.Int64Array + NumericArray pq.Float64Array + DecimalArray pq.Float64Array + RealArray pq.Float32Array + DoubleArray pq.Float64Array + TextArray pq.StringArray + VarcharArray pq.StringArray + CharArray pq.StringArray + ByteaArray pq.ByteaArray + DateArray pq.StringArray + TimestampArray *pq.StringArray + TimestamptzArray pq.StringArray + TimeArray pq.StringArray + TimetzArray pq.StringArray + IntervalArray pq.StringArray + UUIDArray pq.StringArray + MoodEnumArray pq.StringArray +} +`) + + testutils.AssertFileContent(t, tableDir+"/sample_arrays.go", ` +// +// Code generated by go-jet DO NOT EDIT. +// +// WARNING: Changes to this file may cause incorrect behavior +// and will be lost if the code is regenerated +// + +package table + +import ( + "github.com/go-jet/jet/v2/postgres" +) + +var SampleArrays = newSampleArraysTable("test_sample", "sample_arrays", "") + +type sampleArraysTable struct { + postgres.Table + + // Columns + ID postgres.ColumnInteger + BoolArray postgres.ColumnBoolArray + Int2ArrayPtr postgres.ColumnIntegerArray + Int4Array postgres.ColumnIntegerArray + Int8Array postgres.ColumnIntegerArray + NumericArray postgres.ColumnFloatArray + DecimalArray postgres.ColumnFloatArray + RealArray postgres.ColumnFloatArray + DoubleArray postgres.ColumnFloatArray + TextArray postgres.ColumnStringArray + VarcharArray postgres.ColumnStringArray + CharArray postgres.ColumnStringArray + ByteaArray postgres.ColumnByteaArray + DateArray postgres.ColumnDateArray + TimestampArray postgres.ColumnTimestampArray + TimestamptzArray postgres.ColumnTimestampzArray + TimeArray postgres.ColumnTimeArray + TimetzArray postgres.ColumnTimezArray + IntervalArray postgres.ColumnIntervalArray + UUIDArray postgres.ColumnStringArray + MoodEnumArray postgres.ColumnStringArray + + AllColumns postgres.ColumnList + MutableColumns postgres.ColumnList + DefaultColumns postgres.ColumnList +} + +type SampleArraysTable struct { + sampleArraysTable + + EXCLUDED sampleArraysTable +} + +// AS creates new SampleArraysTable with assigned alias +func (a SampleArraysTable) AS(alias string) *SampleArraysTable { + return newSampleArraysTable(a.SchemaName(), a.TableName(), alias) +} + +// Schema creates new SampleArraysTable with assigned schema name +func (a SampleArraysTable) FromSchema(schemaName string) *SampleArraysTable { + return newSampleArraysTable(schemaName, a.TableName(), a.Alias()) +} + +// WithPrefix creates new SampleArraysTable with assigned table prefix +func (a SampleArraysTable) WithPrefix(prefix string) *SampleArraysTable { + return newSampleArraysTable(a.SchemaName(), prefix+a.TableName(), a.TableName()) +} + +// WithSuffix creates new SampleArraysTable with assigned table suffix +func (a SampleArraysTable) WithSuffix(suffix string) *SampleArraysTable { + return newSampleArraysTable(a.SchemaName(), a.TableName()+suffix, a.TableName()) +} + +func newSampleArraysTable(schemaName, tableName, alias string) *SampleArraysTable { + return &SampleArraysTable{ + sampleArraysTable: newSampleArraysTableImpl(schemaName, tableName, alias), + EXCLUDED: newSampleArraysTableImpl("", "excluded", ""), + } +} + +func newSampleArraysTableImpl(schemaName, tableName, alias string) sampleArraysTable { + var ( + IDColumn = postgres.IntegerColumn("id") + BoolArrayColumn = postgres.BoolArrayColumn("bool_array") + Int2ArrayPtrColumn = postgres.IntegerArrayColumn("int2_array_ptr") + Int4ArrayColumn = postgres.IntegerArrayColumn("int4_array") + Int8ArrayColumn = postgres.IntegerArrayColumn("int8_array") + NumericArrayColumn = postgres.FloatArrayColumn("numeric_array") + DecimalArrayColumn = postgres.FloatArrayColumn("decimal_array") + RealArrayColumn = postgres.FloatArrayColumn("real_array") + DoubleArrayColumn = postgres.FloatArrayColumn("double_array") + TextArrayColumn = postgres.StringArrayColumn("text_array") + VarcharArrayColumn = postgres.StringArrayColumn("varchar_array") + CharArrayColumn = postgres.StringArrayColumn("char_array") + ByteaArrayColumn = postgres.ByteaArrayColumn("bytea_array") + DateArrayColumn = postgres.DateArrayColumn("date_array") + TimestampArrayColumn = postgres.TimestampArrayColumn("timestamp_array") + TimestamptzArrayColumn = postgres.TimestampzArrayColumn("timestamptz_array") + TimeArrayColumn = postgres.TimeArrayColumn("time_array") + TimetzArrayColumn = postgres.TimezArrayColumn("timetz_array") + IntervalArrayColumn = postgres.IntervalArrayColumn("interval_array") + UUIDArrayColumn = postgres.StringArrayColumn("uuid_array") + MoodEnumArrayColumn = postgres.StringArrayColumn("mood_enum_array") + allColumns = postgres.ColumnList{IDColumn, BoolArrayColumn, Int2ArrayPtrColumn, Int4ArrayColumn, Int8ArrayColumn, NumericArrayColumn, DecimalArrayColumn, RealArrayColumn, DoubleArrayColumn, TextArrayColumn, VarcharArrayColumn, CharArrayColumn, ByteaArrayColumn, DateArrayColumn, TimestampArrayColumn, TimestamptzArrayColumn, TimeArrayColumn, TimetzArrayColumn, IntervalArrayColumn, UUIDArrayColumn, MoodEnumArrayColumn} + mutableColumns = postgres.ColumnList{BoolArrayColumn, Int2ArrayPtrColumn, Int4ArrayColumn, Int8ArrayColumn, NumericArrayColumn, DecimalArrayColumn, RealArrayColumn, DoubleArrayColumn, TextArrayColumn, VarcharArrayColumn, CharArrayColumn, ByteaArrayColumn, DateArrayColumn, TimestampArrayColumn, TimestamptzArrayColumn, TimeArrayColumn, TimetzArrayColumn, IntervalArrayColumn, UUIDArrayColumn, MoodEnumArrayColumn} + defaultColumns = postgres.ColumnList{IDColumn, Int4ArrayColumn, Int8ArrayColumn, TextArrayColumn} + ) + + return sampleArraysTable{ + Table: postgres.NewTable(schemaName, tableName, alias, allColumns...), + + //Columns + ID: IDColumn, + BoolArray: BoolArrayColumn, + Int2ArrayPtr: Int2ArrayPtrColumn, + Int4Array: Int4ArrayColumn, + Int8Array: Int8ArrayColumn, + NumericArray: NumericArrayColumn, + DecimalArray: DecimalArrayColumn, + RealArray: RealArrayColumn, + DoubleArray: DoubleArrayColumn, + TextArray: TextArrayColumn, + VarcharArray: VarcharArrayColumn, + CharArray: CharArrayColumn, + ByteaArray: ByteaArrayColumn, + DateArray: DateArrayColumn, + TimestampArray: TimestampArrayColumn, + TimestamptzArray: TimestamptzArrayColumn, + TimeArray: TimeArrayColumn, + TimetzArray: TimetzArrayColumn, + IntervalArray: IntervalArrayColumn, + UUIDArray: UUIDArrayColumn, + MoodEnumArray: MoodEnumArrayColumn, + + AllColumns: allColumns, + MutableColumns: mutableColumns, + DefaultColumns: defaultColumns, + } +} +`) +} diff --git a/tests/postgres/range_test.go b/tests/postgres/range_test.go index ec75999..cd2e583 100644 --- a/tests/postgres/range_test.go +++ b/tests/postgres/range_test.go @@ -53,8 +53,8 @@ func TestRangeTableSelect(t *testing.T) { table.SampleRanges.TimestampzRange.DIFFERENCE(tstzRange).AS("sample.tstz_diff"), table.SampleRanges.Int4Range.UPPER_BOUND().ADD(Int(5)).AS("sample.int4_upper"), table.SampleRanges.Int8Range.LOWER_BOUND().SUB(Int(12)).AS("sample.int8_lower"), - LOWER_BOUND[DateExpression](table.SampleRanges.DateRange), - UPPER_BOUND[NumericExpression](table.SampleRanges.NumRange).AS("sample.num_upper"), + LOWER_BOUND(table.SampleRanges.DateRange), + UPPER_BOUND(table.SampleRanges.NumRange).AS("sample.num_upper"), table.SampleRanges.TimestampRange.UPPER_BOUND(), table.SampleRanges.DateRange.IS_EMPTY().AS("sample.date_empty"), table.SampleRanges.TimestampRange.LOWER_INC().AS("sample.ts_low_inc"), diff --git a/tests/postgres/scan_test.go b/tests/postgres/scan_test.go index 37cbd8a..910bd09 100644 --- a/tests/postgres/scan_test.go +++ b/tests/postgres/scan_test.go @@ -3,6 +3,7 @@ package postgres import ( "context" "github.com/go-jet/jet/v2/internal/utils/ptr" + "github.com/lib/pq" "github.com/volatiletech/null/v8" "testing" "time" @@ -1020,7 +1021,7 @@ func TestScanIntoCustomBaseTypes(t *testing.T) { ReplacementCost MyFloat64 Rating *model.MpaaRating LastUpdate MyTime - SpecialFeatures *MyString + SpecialFeatures pq.StringArray Fulltext MyString } @@ -1032,14 +1033,12 @@ func TestScanIntoCustomBaseTypes(t *testing.T) { Film.FilmID.ASC(), ).LIMIT(3) - var films []model.Film - - err := stmt.Query(db, &films) + var myFilms []film + err := stmt.Query(db, &myFilms) require.NoError(t, err) - var myFilms []film - - err = stmt.Query(db, &myFilms) + var films []model.Film + err = stmt.Query(db, &films) require.NoError(t, err) require.Equal(t, testutils.ToJSON(films), testutils.ToJSON(myFilms)) @@ -1254,7 +1253,7 @@ var film1 = model.Film{ ReplacementCost: 20.99, Rating: &pgRating, LastUpdate: *testutils.TimestampWithoutTimeZone("2013-05-26 14:50:58.951", 3), - SpecialFeatures: ptr.Of("{\"Deleted Scenes\",\"Behind the Scenes\"}"), + SpecialFeatures: &pq.StringArray{"Deleted Scenes", "Behind the Scenes"}, Fulltext: "'academi':1 'battl':15 'canadian':20 'dinosaur':2 'drama':5 'epic':4 'feminist':8 'mad':11 'must':14 'rocki':21 'scientist':12 'teacher':17", } @@ -1270,7 +1269,7 @@ var film2 = model.Film{ ReplacementCost: 12.99, Rating: &gRating, LastUpdate: *testutils.TimestampWithoutTimeZone("2013-05-26 14:50:58.951", 3), - SpecialFeatures: ptr.Of(`{Trailers,"Deleted Scenes"}`), + SpecialFeatures: &pq.StringArray{"Trailers", "Deleted Scenes"}, Fulltext: `'ace':1 'administr':9 'ancient':19 'astound':4 'car':17 'china':20 'databas':8 'epistl':5 'explor':12 'find':15 'goldfing':2 'must':14`, } diff --git a/tests/postgres/select_json_test.go b/tests/postgres/select_json_test.go index 8691018..3ceadf6 100644 --- a/tests/postgres/select_json_test.go +++ b/tests/postgres/select_json_test.go @@ -358,8 +358,7 @@ func TestSelectQuickStartJSON(t *testing.T) { Actor.ActorID, Actor.FirstName, Actor.LastName, Actor.LastUpdate, SELECT_JSON_ARR( - Film.AllColumns.Except(Film.SpecialFeatures), - CAST(Film.SpecialFeatures).AS_TEXT().AS("SpecialFeatures"), + Film.AllColumns, SELECT_JSON_OBJ( Language.AllColumns, @@ -385,7 +384,11 @@ func TestSelectQuickStartJSON(t *testing.T) { Film. INNER_JOIN(FilmActor, FilmActor.FilmID.EQ(Film.FilmID)), ).WHERE( - FilmActor.ActorID.EQ(Actor.ActorID).AND(Film.Length.GT(Int32(180))), + AND( + FilmActor.ActorID.EQ(Actor.ActorID), + Film.Length.GT(Int32(180)), + String("Trailers").EQ(ANY(Film.SpecialFeatures)), + ), ).ORDER_BY( Film.FilmID.ASC(), ).AS("Films"), @@ -416,8 +419,8 @@ FROM ( film.replacement_cost AS "replacementCost", film.rating AS "rating", to_char(film.last_update, 'YYYY-MM-DD"T"HH24:MI:SS.USZ') AS "lastUpdate", + film.special_features AS "specialFeatures", film.fulltext AS "fulltext", - film.special_features::text AS "SpecialFeatures", ( SELECT row_to_json(language_records) AS "language_json" FROM ( @@ -441,7 +444,11 @@ FROM ( ) AS "Categories" FROM dvds.film INNER JOIN dvds.film_actor ON (film_actor.film_id = film.film_id) - WHERE (film_actor.actor_id = actor.actor_id) AND (film.length > 180::integer) + WHERE ( + (film_actor.actor_id = actor.actor_id) + AND (film.length > 180::integer) + AND ('Trailers'::text = ANY(film.special_features)) + ) ORDER BY film.film_id ASC ) AS films_records ) AS "Films" @@ -469,8 +476,8 @@ FROM ( return // char[n] columns whitespaces are trimmed when returned as json in cockroachdb } - //testutils.SaveJSONFile(dest, "./testdata/results/postgres/quick-start-json-dest2.json") - //testutils.AssertJSONFile(t, dest, "./testdata/results/postgres/quick-start-json-dest.json") + //testutils.SaveJSONFile(dest, "./testdata/results/postgres/quick-start-json-dest.json") + testutils.AssertJSONFile(t, dest, "./testdata/results/postgres/quick-start-json-dest.json") } func TestSelectJsonInReturning(t *testing.T) { diff --git a/tests/postgres/select_test.go b/tests/postgres/select_test.go index 6997223..5fdefab 100644 --- a/tests/postgres/select_test.go +++ b/tests/postgres/select_test.go @@ -4,6 +4,7 @@ import ( "context" "database/sql" "github.com/go-jet/jet/v2/internal/utils/ptr" + "github.com/lib/pq" "testing" "time" @@ -1852,7 +1853,7 @@ ORDER BY film.film_id ASC; Rating: &gRating, RentalDuration: 3, LastUpdate: *testutils.TimestampWithoutTimeZone("2013-05-26 14:50:58.951", 3), - SpecialFeatures: ptr.Of("{Trailers,\"Deleted Scenes\"}"), + SpecialFeatures: &pq.StringArray{"Trailers", "Deleted Scenes"}, Fulltext: "'ace':1 'administr':9 'ancient':19 'astound':4 'car':17 'china':20 'databas':8 'epistl':5 'explor':12 'find':15 'goldfing':2 'must':14", }) } @@ -2709,7 +2710,32 @@ FOR UPDATE OF "myFilm"; func TestSelectQuickStart(t *testing.T) { - var expectedSQL = ` + stmt := SELECT( + Actor.ActorID, Actor.FirstName, Actor.LastName, Actor.LastUpdate, // list of all actor columns (equivalent to Actor.AllColumns) + Film.AllColumns, // list of all film columns (equivalent to Film.FilmID, Film.Title, ...) + Language.AllColumns.Except(Language.LastUpdate), + Category.AllColumns, + ).FROM( + Actor. + INNER_JOIN(FilmActor, Actor.ActorID.EQ(FilmActor.ActorID)). // INNER JOIN Actor with FilmActor on condition Actor.ActorID = FilmActor.ActorID + INNER_JOIN(Film, Film.FilmID.EQ(FilmActor.FilmID)). // then with Film, Language, FilmCategory and Category. + INNER_JOIN(Language, Language.LanguageID.EQ(Film.LanguageID)). + INNER_JOIN(FilmCategory, FilmCategory.FilmID.EQ(Film.FilmID)). + INNER_JOIN(Category, Category.CategoryID.EQ(FilmCategory.CategoryID)), + ).WHERE( + AND( + Language.Name.EQ(Char(20)("English")), // String column Language.Name and Category.Name can be compared only with string expression + Category.Name.NOT_EQ(Text("Action")), + Film.Length.GT(Int32(180)), // Film.Length is integer column and can be compared only with integer expression + Film.Rating.NOT_EQ(enum.MpaaRating.R), + String("Trailers").EQ(ANY(Film.SpecialFeatures)), // arrays element type safety is also enforced + ), + ).ORDER_BY( + Actor.ActorID.ASC(), + Film.FilmID.ASC(), + ) + + testutils.AssertStatementSql(t, stmt, ` SELECT actor.actor_id AS "actor.actor_id", actor.first_name AS "actor.first_name", actor.last_name AS "actor.last_name", @@ -2729,7 +2755,6 @@ SELECT actor.actor_id AS "actor.actor_id", film.fulltext AS "film.fulltext", language.language_id AS "language.language_id", language.name AS "language.name", - language.last_update AS "language.last_update", category.category_id AS "category.category_id", category.name AS "category.name", category.last_update AS "category.last_update" @@ -2739,33 +2764,54 @@ FROM dvds.actor INNER JOIN dvds.language ON (language.language_id = film.language_id) INNER JOIN dvds.film_category ON (film_category.film_id = film.film_id) INNER JOIN dvds.category ON (category.category_id = film_category.category_id) -WHERE (((language.name = 'English'::char(20)) AND (category.name != 'Action'::text)) AND (film.length > 180::integer)) AND (film.rating != 'R') +WHERE ( + (language.name = $1::char(20)) + AND (category.name != $2::text) + AND (film.length > $3::integer) + AND (film.rating != 'R') + AND ($4::text = ANY(film.special_features)) + ) ORDER BY actor.actor_id ASC, film.film_id ASC; -` +`, "English", "Action", int32(180), "Trailers") - stmt := SELECT( - Actor.ActorID, Actor.FirstName, Actor.LastName, Actor.LastUpdate, // list of all actor columns (equivalent to Actor.AllColumns) - Film.AllColumns, // list of all film columns (equivalent to Film.FilmID, Film.Title, ...) - Language.AllColumns, - Category.AllColumns, - ).FROM( - Actor. - INNER_JOIN(FilmActor, Actor.ActorID.EQ(FilmActor.ActorID)). // INNER JOIN Actor with FilmActor on condition Actor.ActorID = FilmActor.ActorID - INNER_JOIN(Film, Film.FilmID.EQ(FilmActor.FilmID)). // then with Film, Language, FilmCategory and Category. - INNER_JOIN(Language, Language.LanguageID.EQ(Film.LanguageID)). - INNER_JOIN(FilmCategory, FilmCategory.FilmID.EQ(Film.FilmID)). - INNER_JOIN(Category, Category.CategoryID.EQ(FilmCategory.CategoryID)), - ).WHERE( - Language.Name.EQ(Char(20)("English")). // note that every column has type. - AND(Category.Name.NOT_EQ(Text("Action"))). // String column Language.Name and Category.Name can be compared only with string expression - AND(Film.Length.GT(Int32(180))). // Film.Length is integer column and can be compared only with integer expression - AND(Film.Rating.NOT_EQ(enum.MpaaRating.R)), - ).ORDER_BY( - Actor.ActorID.ASC(), - Film.FilmID.ASC(), - ) - - testutils.AssertDebugStatementSql(t, stmt, expectedSQL, "English", "Action", int32(180)) + testutils.AssertDebugStatementSql(t, stmt, ` +SELECT actor.actor_id AS "actor.actor_id", + actor.first_name AS "actor.first_name", + actor.last_name AS "actor.last_name", + actor.last_update AS "actor.last_update", + film.film_id AS "film.film_id", + film.title AS "film.title", + film.description AS "film.description", + film.release_year AS "film.release_year", + film.language_id AS "film.language_id", + film.rental_duration AS "film.rental_duration", + film.rental_rate AS "film.rental_rate", + film.length AS "film.length", + film.replacement_cost AS "film.replacement_cost", + film.rating AS "film.rating", + film.last_update AS "film.last_update", + film.special_features AS "film.special_features", + film.fulltext AS "film.fulltext", + language.language_id AS "language.language_id", + language.name AS "language.name", + category.category_id AS "category.category_id", + category.name AS "category.name", + category.last_update AS "category.last_update" +FROM dvds.actor + INNER JOIN dvds.film_actor ON (actor.actor_id = film_actor.actor_id) + INNER JOIN dvds.film ON (film.film_id = film_actor.film_id) + INNER JOIN dvds.language ON (language.language_id = film.language_id) + INNER JOIN dvds.film_category ON (film_category.film_id = film.film_id) + INNER JOIN dvds.category ON (category.category_id = film_category.category_id) +WHERE ( + (language.name = 'English'::char(20)) + AND (category.name != 'Action'::text) + AND (film.length > 180::integer) + AND (film.rating != 'R') + AND ('Trailers'::text = ANY(film.special_features)) + ) +ORDER BY actor.actor_id ASC, film.film_id ASC; +`) var dest []struct { model.Actor @@ -2783,7 +2829,6 @@ ORDER BY actor.actor_id ASC, film.film_id ASC; require.NoError(t, err) //testutils.SaveJSONFile(dest, "./testdata/results/postgres/quick-start-dest.json") - testutils.AssertJSONFile(t, dest, "./testdata/results/postgres/quick-start-dest.json") var dest2 []struct { @@ -2806,7 +2851,11 @@ func TestSelectQuickStartWithSubQueries(t *testing.T) { filmLogerThan180 := Film. SELECT(Film.AllColumns). - WHERE(Film.Length.GT(Int(180)).AND(Film.Rating.NOT_EQ(enum.MpaaRating.R))). + WHERE( + Film.Length.GT(Int(180)). + AND(Film.Rating.NOT_EQ(enum.MpaaRating.R)). + AND(String("Trailers").EQ(ANY(Film.SpecialFeatures))), + ). AsTable("films") filmID := Film.FilmID.From(filmLogerThan180) @@ -2822,7 +2871,7 @@ func TestSelectQuickStartWithSubQueries(t *testing.T) { stmt := SELECT( Actor.AllColumns, filmLogerThan180.AllColumns(), - Language.AllColumns, + Language.AllColumns.Except(Language.LastUpdate), categoriesNotAction.AllColumns(), ).FROM( Actor. @@ -3389,7 +3438,10 @@ func TestSelectRecursionScanNxM(t *testing.T) { "ReplacementCost": 20.99, "Rating": "PG", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\",\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Deleted Scenes", + "Behind the Scenes" + ], "Fulltext": "'academi':1 'battl':15 'canadian':20 'dinosaur':2 'drama':5 'epic':4 'feminist':8 'mad':11 'must':14 'rocki':21 'scientist':12 'teacher':17", "Actors": [ { @@ -3413,7 +3465,10 @@ func TestSelectRecursionScanNxM(t *testing.T) { "ReplacementCost": 9.99, "Rating": "R", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Deleted Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Deleted Scenes" + ], "Fulltext": "'anaconda':1 'australia':18 'confess':2 'dentist':8,11 'display':5 'fight':14 'girl':16 'lacklustur':4 'must':13", "Actors": [ { @@ -3461,7 +3516,10 @@ func TestSelectRecursionScanNxM(t *testing.T) { "ReplacementCost": 20.99, "Rating": "PG", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{\"Deleted Scenes\",\"Behind the Scenes\"}", + "SpecialFeatures": [ + "Deleted Scenes", + "Behind the Scenes" + ], "Fulltext": "'academi':1 'battl':15 'canadian':20 'dinosaur':2 'drama':5 'epic':4 'feminist':8 'mad':11 'must':14 'rocki':21 'scientist':12 'teacher':17", "Actors": null }, @@ -3477,7 +3535,10 @@ func TestSelectRecursionScanNxM(t *testing.T) { "ReplacementCost": 9.99, "Rating": "R", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers,\"Deleted Scenes\"}", + "SpecialFeatures": [ + "Trailers", + "Deleted Scenes" + ], "Fulltext": "'anaconda':1 'australia':18 'confess':2 'dentist':8,11 'display':5 'fight':14 'girl':16 'lacklustur':4 'must':13", "Actors": null } diff --git a/tests/postgres/values_test.go b/tests/postgres/values_test.go index bdb631c..f46ca29 100644 --- a/tests/postgres/values_test.go +++ b/tests/postgres/values_test.go @@ -172,7 +172,9 @@ ORDER BY film_values.title; "ReplacementCost": 15.99, "Rating": "R", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers}", + "SpecialFeatures": [ + "Trailers" + ], "Fulltext": "'airport':1 'ancient':18 'confront':14 'epic':4 'girl':11 'india':19 'monkey':16 'moos':8 'must':13 'pollock':2 'tale':5" }, "Title": "Airport Pollock", @@ -194,7 +196,9 @@ ORDER BY film_values.title; "ReplacementCost": 12.99, "Rating": "PG-13", "LastUpdate": "2013-05-26T14:50:58.951Z", - "SpecialFeatures": "{Trailers}", + "SpecialFeatures": [ + "Trailers" + ], "Fulltext": "'boat':20 'bright':1 'conquer':14 'encount':2 'fate':4 'feminist':11 'jet':19 'lumberjack':8 'must':13 'student':16 'yarn':5" }, "Title": "Bright Encounters", diff --git a/tests/testdata b/tests/testdata index 94f3504..0387785 160000 --- a/tests/testdata +++ b/tests/testdata @@ -1 +1 @@ -Subproject commit 94f3504ef8245b8f76ca391f068705ba1375c03b +Subproject commit 0387785d9e9ceacba2247d477181436f27bf2068