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 5b6ce8a..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" ) @@ -30,3 +29,7 @@ type DataType struct { 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 a60c01a..5b39110 100644 --- a/generator/postgres/query_set.go +++ b/generator/postgres/query_set.go @@ -66,23 +66,25 @@ select not attr.attnotnull as "column.isNullable", attr.attgenerated = 's' as "column.isGenerated", attr.atthasdef as "column.hasDefault", - attr.attndims as "dataType.dimensions", - (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 b941c05..5672d19 100644 --- a/generator/template/model_template.go +++ b/generator/template/model_template.go @@ -2,15 +2,17 @@ package template import ( "fmt" - "github.com/go-jet/jet/v2/generator/metadata" - "github.com/go-jet/jet/v2/internal/utils/dbidentifier" - "github.com/google/uuid" - "github.com/jackc/pgtype" "github.com/lib/pq" "path/filepath" "reflect" "strings" "time" + + "github.com/google/uuid" + "github.com/jackc/pgtype" + + "github.com/go-jet/jet/v2/generator/metadata" + "github.com/go-jet/jet/v2/internal/utils/dbidentifier" ) // Model is template for model files generation @@ -246,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)) @@ -267,21 +280,44 @@ 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{} { - // We don't support multi-dimensional arrays - if column.DataType.Dimensions > 1 { - return "" - } switch strings.ToLower(column.DataType.Name) { case "user-defined", "enum": @@ -348,14 +384,6 @@ func toGoType(column metadata.Column) interface{} { return pgtype.Int8range{} case "numrange": return pgtype.Numrange{} - case "bool[]": - return pq.BoolArray{} - case "integer[]", "int4[]": - return pq.Int32Array{} - case "bigint[]": - return pq.Int64Array{} - case "text[]", "jsonb[]", "json[]": - return pq.StringArray{} default: fmt.Println("- [Model ] Unsupported sql column '" + column.Name + " " + column.DataType.Name + "', using string instead.") return "" diff --git a/generator/template/sql_builder_template.go b/generator/template/sql_builder_template.go index 6b56b0f..0c4c66c 100644 --- a/generator/template/sql_builder_template.go +++ b/generator/template/sql_builder_template.go @@ -162,43 +162,33 @@ 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 && - columnMetaData.DataType.Kind != metadata.ArrayType { + switch columnMetaData.DataType.Kind { + case metadata.EnumType, metadata.UserDefinedType: + if columnMetaData.DataType.IsArray() { + return "StringArray" + } return "String" } - typeName := columnMetaData.DataType.Name - columnName := columnMetaData.Name + columnType := sqlToColumnType(columnMetaData) - if columnMetaData.DataType.Kind == metadata.ArrayType { + if columnMetaData.DataType.IsArray() { if columnMetaData.DataType.Dimensions > 1 { - fmt.Println("- [SQL Builder] Unsupported sql array with multiple dimensions column '" + columnName + " " + typeName + "', using StringColumn instead.") + fmt.Println("- [SQL Builder] Unsupported sql array with multiple dimensions column '" + + columnMetaData.Name + " " + columnMetaData.DataType.Name + "', using StringColumn instead.") return "String" } - c := sqlToColumnType(strings.TrimSuffix(typeName, "[]")) - - // These are the supported array types - if slices.Index([]string{"Bool", "String", "Integer"}, c) == -1 { - fmt.Println("- [SQL Builder] Unsupported sql array column '" + columnName + " " + typeName + "', using StringColumn instead.") - return "String" - } - - return c + "Array" - } - - columnType := sqlToColumnType(typeName) - if columnType == "" { - fmt.Println("- [SQL Builder] Unsupported sql column '" + columnName + " " + typeName + "', using StringColumn instead.") - return "String" + columnType = columnType + "Array" } return columnType } -func sqlToColumnType(typeName string) string { - switch strings.ToLower(typeName) { +// 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" case "smallint", "integer", "bigint", "int2", "int4", "int8", @@ -243,7 +233,8 @@ func sqlToColumnType(typeName string) string { case "numrange": return "NumericRange" default: - return "" + fmt.Println("- [SQL Builder] Unsupported sql column '" + columnMetaData.Name + " " + columnMetaData.DataType.Name + "', using StringColumn instead.") + return "String" } } diff --git a/internal/jet/array_expression.go b/internal/jet/array_expression.go index 66cc005..e0ab8dc 100644 --- a/internal/jet/array_expression.go +++ b/internal/jet/array_expression.go @@ -1,77 +1,77 @@ package jet -// ArrayExpression interface -type ArrayExpression[E Expression] interface { +// Array interface +type Array[E Expression] interface { Expression - EQ(rhs ArrayExpression[E]) BoolExpression - NOT_EQ(rhs ArrayExpression[E]) BoolExpression - LT(rhs ArrayExpression[E]) BoolExpression - GT(rhs ArrayExpression[E]) BoolExpression - LT_EQ(rhs ArrayExpression[E]) BoolExpression - GT_EQ(rhs ArrayExpression[E]) BoolExpression + 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 ArrayExpression[E]) BoolExpression - IS_CONTAINED_BY(rhs ArrayExpression[E]) BoolExpression - OVERLAP(rhs ArrayExpression[E]) BoolExpression - CONCAT(rhs ArrayExpression[E]) ArrayExpression[E] - CONCAT_ELEMENT(E) ArrayExpression[E] + 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) Expression + AT(expression IntegerExpression) E } type arrayInterfaceImpl[E Expression] struct { - parent ArrayExpression[E] + parent Array[E] } type BinaryBoolOp func(Expression, Expression) BoolExpression -func (a arrayInterfaceImpl[E]) EQ(rhs ArrayExpression[E]) BoolExpression { +func (a arrayInterfaceImpl[E]) EQ(rhs Array[E]) BoolExpression { return Eq(a.parent, rhs) } -func (a arrayInterfaceImpl[E]) NOT_EQ(rhs ArrayExpression[E]) BoolExpression { +func (a arrayInterfaceImpl[E]) NOT_EQ(rhs Array[E]) BoolExpression { return NotEq(a.parent, rhs) } -func (a arrayInterfaceImpl[E]) LT(rhs ArrayExpression[E]) BoolExpression { +func (a arrayInterfaceImpl[E]) LT(rhs Array[E]) BoolExpression { return Lt(a.parent, rhs) } -func (a arrayInterfaceImpl[E]) GT(rhs ArrayExpression[E]) BoolExpression { +func (a arrayInterfaceImpl[E]) GT(rhs Array[E]) BoolExpression { return Gt(a.parent, rhs) } -func (a arrayInterfaceImpl[E]) LT_EQ(rhs ArrayExpression[E]) BoolExpression { +func (a arrayInterfaceImpl[E]) LT_EQ(rhs Array[E]) BoolExpression { return LtEq(a.parent, rhs) } -func (a arrayInterfaceImpl[E]) GT_EQ(rhs ArrayExpression[E]) BoolExpression { +func (a arrayInterfaceImpl[E]) GT_EQ(rhs Array[E]) BoolExpression { return GtEq(a.parent, rhs) } -func (a arrayInterfaceImpl[E]) CONTAINS(rhs ArrayExpression[E]) BoolExpression { +func (a arrayInterfaceImpl[E]) CONTAINS(rhs Array[E]) BoolExpression { return Contains(a.parent, rhs) } -func (a arrayInterfaceImpl[E]) IS_CONTAINED_BY(rhs ArrayExpression[E]) BoolExpression { +func (a arrayInterfaceImpl[E]) IS_CONTAINED_BY(rhs Array[E]) BoolExpression { return IsContainedBy(a.parent, rhs) } -func (a arrayInterfaceImpl[E]) OVERLAP(rhs ArrayExpression[E]) BoolExpression { +func (a arrayInterfaceImpl[E]) OVERLAP(rhs Array[E]) BoolExpression { return Overlap(a.parent, rhs) } -func (a arrayInterfaceImpl[E]) CONCAT(rhs ArrayExpression[E]) ArrayExpression[E] { +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) ArrayExpression[E] { +func (a arrayInterfaceImpl[E]) CONCAT_ELEMENT(rhs E) Array[E] { return ArrayExp[E](NewBinaryOperatorExpression(a.parent, rhs, "||")) } -func (a arrayInterfaceImpl[E]) AT(expression IntegerExpression) Expression { - return arraySubscriptExpr(a.parent, expression) +func (a arrayInterfaceImpl[E]) AT(at IntegerExpression) E { + return CastToArrayElemType[E](a.parent, CustomExpression(a.parent, Token("["), at, Token("]"))) } type arrayExpressionWrapper[E Expression] struct { @@ -79,7 +79,7 @@ type arrayExpressionWrapper[E Expression] struct { Expression } -func newArrayExpressionWrap[E Expression](expression Expression) ArrayExpression[E] { +func newArrayExpressionWrap[E Expression](expression Expression) Array[E] { arrayExpressionWrapper := arrayExpressionWrapper[E]{Expression: expression} arrayExpressionWrapper.arrayInterfaceImpl.parent = &arrayExpressionWrapper return &arrayExpressionWrapper @@ -88,6 +88,49 @@ func newArrayExpressionWrap[E Expression](expression Expression) ArrayExpression // 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) ArrayExpression[E] { +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 index ed7b565..54e851e 100644 --- a/internal/jet/array_expression_test.go +++ b/internal/jet/array_expression_test.go @@ -1,7 +1,6 @@ package jet import ( - "github.com/lib/pq" "testing" ) @@ -11,7 +10,6 @@ func TestArrayExpressionEQ(t *testing.T) { func TestArrayExpressionNOT_EQ(t *testing.T) { assertClauseSerialize(t, table1ColStringArray.NOT_EQ(table2ColArray), "(table1.col_array_string != table2.col_array_string)") - assertClauseSerialize(t, table1ColStringArray.NOT_EQ(StringArray([]string{"x"})), "(table1.col_array_string != $1)", pq.StringArray{"x"}) } func TestArrayExpressionLT(t *testing.T) { @@ -32,12 +30,10 @@ func TestArrayExpressionGT_EQ(t *testing.T) { func TestArrayExpressionCONTAINS(t *testing.T) { assertClauseSerialize(t, table1ColStringArray.CONTAINS(table2ColArray), "(table1.col_array_string @> table2.col_array_string)") - assertClauseSerialize(t, table1ColStringArray.CONTAINS(StringArray([]string{"x"})), "(table1.col_array_string @> $1)", pq.StringArray{"x"}) } func TestArrayExpressionCONTAINED_BY(t *testing.T) { assertClauseSerialize(t, table1ColStringArray.IS_CONTAINED_BY(table2ColArray), "(table1.col_array_string <@ table2.col_array_string)") - assertClauseSerialize(t, table1ColStringArray.IS_CONTAINED_BY(StringArray([]string{"x"})), "(table1.col_array_string <@ $1)", pq.StringArray{"x"}) } func TestArrayExpressionOVERLAP(t *testing.T) { @@ -46,14 +42,27 @@ func TestArrayExpressionOVERLAP(t *testing.T) { func TestArrayExpressionCONCAT(t *testing.T) { assertClauseSerialize(t, table1ColStringArray.CONCAT(table2ColArray), "(table1.col_array_string || table2.col_array_string)") - assertClauseSerialize(t, table1ColStringArray.CONCAT(StringArray([]string{"x"})), "(table1.col_array_string || $1)", pq.StringArray{"x"}) } 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(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)) + 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 2f19eaf..5d63485 100644 --- a/internal/jet/column_types.go +++ b/internal/jet/column_types.go @@ -134,17 +134,21 @@ func IntegerColumn(name string) ColumnInteger { //------------------------------------------------------// type ColumnArray[E Expression] interface { - ArrayExpression[E] + Array[E] Column From(subQuery SelectTable) ColumnArray[E] - SET(stringExp ArrayExpression[E]) ColumnAssigment + SET(stringExp Array[E]) ColumnAssigment } type arrayColumnImpl[E Expression] struct { arrayInterfaceImpl[E] - ColumnExpressionImpl + *ColumnExpressionImpl +} + +func (a arrayColumnImpl[E]) fromImpl(subQuery SelectTable) Projection { + return a.From(subQuery) } func (a arrayColumnImpl[E]) From(subQuery SelectTable) ColumnArray[E] { @@ -155,10 +159,10 @@ func (a arrayColumnImpl[E]) From(subQuery SelectTable) ColumnArray[E] { return newArrayColumn } -func (a *arrayColumnImpl[E]) SET(stringExp ArrayExpression[E]) ColumnAssigment { +func (a *arrayColumnImpl[E]) SET(stringExp Array[E]) ColumnAssigment { return columnAssigmentImpl{ - column: a, - expression: stringExp, + column: a, + toAssign: stringExp, } } diff --git a/internal/jet/column_types_test.go b/internal/jet/column_types_test.go index 38d9e96..cf585e2 100644 --- a/internal/jet/column_types_test.go +++ b/internal/jet/column_types_test.go @@ -1,7 +1,6 @@ package jet import ( - "github.com/lib/pq" "testing" ) @@ -12,36 +11,30 @@ var subQuery = &selectTableImpl{ func TestNewArrayColumnString(t *testing.T) { stringArrayColumn := ArrayColumn[StringExpression]("colArray").From(subQuery) assertClauseSerialize(t, stringArrayColumn, `sub_query."colArray"`) - assertClauseSerialize(t, stringArrayColumn.EQ(StringArray([]string{"X"})), `(sub_query."colArray" = $1)`, pq.StringArray{"X"}) assertProjectionSerialize(t, stringArrayColumn, `sub_query."colArray" AS "colArray"`) arrayColumn2 := table1ColStringArray.From(subQuery) assertClauseSerialize(t, arrayColumn2, `sub_query."table1.col_array_string"`) - assertClauseSerialize(t, arrayColumn2.EQ(StringArray([]string{"X"})), `(sub_query."table1.col_array_string" = $1)`, pq.StringArray{"X"}) 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"`) - assertClauseSerialize(t, boolArrayColumn.EQ(BoolArray([]bool{true})), `(sub_query."colArrayBool" = $1)`, pq.BoolArray{true}) assertProjectionSerialize(t, boolArrayColumn, `sub_query."colArrayBool" AS "colArrayBool"`) arrayColumn2 := table1ColBoolArray.From(subQuery) assertClauseSerialize(t, arrayColumn2, `sub_query."table1.col_array_bool"`) - assertClauseSerialize(t, arrayColumn2.EQ(BoolArray([]bool{true})), `(sub_query."table1.col_array_bool" = $1)`, pq.BoolArray{true}) 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"`) - assertClauseSerialize(t, intArrayColumn.EQ(Int32Array([]int32{42})), `(sub_query."colArrayInt" = $1)`, pq.Int32Array{42}) assertProjectionSerialize(t, intArrayColumn, `sub_query."colArrayInt" AS "colArrayInt"`) arrayColumn2 := table1ColIntArray.From(subQuery) assertClauseSerialize(t, arrayColumn2, `sub_query."table1.col_array_int"`) - assertClauseSerialize(t, arrayColumn2.EQ(Int32Array([]int32{42})), `(sub_query."table1.col_array_int" = $1)`, pq.Int32Array{42}) assertProjectionSerialize(t, arrayColumn2, `sub_query."table1.col_array_int" AS "table1.col_array_int"`) } diff --git a/internal/jet/expression.go b/internal/jet/expression.go index af4851e..62e5aff 100644 --- a/internal/jet/expression.go +++ b/internal/jet/expression.go @@ -341,42 +341,3 @@ func (s *complexExpression) serialize(statement StatementType, out *SQLBuilder, func wrap(expressions ...Expression) Expression { return NewFunc("", expressions, nil) } - -type arraySubscriptExpression struct { - ExpressionInterfaceImpl - array Expression - subscript IntegerExpression -} - -func (a arraySubscriptExpression) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) { - if !contains(options, NoWrap) { - out.WriteString("(") - } - a.array.serialize(statement, out, FallTrough(options)...) // FallTrough here because complexExpression is just a wrapper - out.WriteString("[") - a.subscript.serialize(statement, out, FallTrough(options)...) // FallTrough here because complexExpression is just a wrapper - out.WriteString("]") - if !contains(options, NoWrap) { - out.WriteString(")") - } -} - -func arraySubscriptExpr(array Expression, subscript IntegerExpression) Expression { - arraySubscriptExpression := &arraySubscriptExpression{array: array, subscript: subscript} - arraySubscriptExpression.ExpressionInterfaceImpl.Parent = arraySubscriptExpression - - return arraySubscriptExpression -} - -type skipParenthesisWrap struct { - Expression -} - -func skipWrap(expression Expression) Expression { - return &skipParenthesisWrap{expression} -} - -// since the expression is a function parameter, there is no need to wrap it in parentheses -func (s *skipParenthesisWrap) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) { - s.Expression.serialize(statement, out, append(options, NoWrap)...) -} diff --git a/internal/jet/literal_expression.go b/internal/jet/literal_expression.go index 2a33fa5..b8baa51 100644 --- a/internal/jet/literal_expression.go +++ b/internal/jet/literal_expression.go @@ -2,7 +2,6 @@ package jet import ( "fmt" - "github.com/lib/pq" "time" ) @@ -161,66 +160,6 @@ func Decimal(value string) FloatExpression { return &floatLiteral } -// ---------------------------------------------------// - -type boolArrayLiteral struct { - arrayInterfaceImpl[BoolExpression] - literalExpressionImpl -} - -func BoolArray(values []bool) ArrayExpression[BoolExpression] { - l := boolArrayLiteral{} - l.literalExpressionImpl = *literal(pq.BoolArray(values)) - l.arrayInterfaceImpl.parent = &l - - return &l -} - -type integerArrayLiteral struct { - arrayInterfaceImpl[IntegerExpression] - literalExpressionImpl -} - -func Int64Array(values []int64) ArrayExpression[IntegerExpression] { - l := integerArrayLiteral{} - l.literalExpressionImpl = *literal(pq.Int64Array(values)) - l.arrayInterfaceImpl.parent = &l - return &l -} - -func Int32Array(values []int32) ArrayExpression[IntegerExpression] { - l := integerArrayLiteral{} - l.literalExpressionImpl = *literal(pq.Int32Array(values)) - l.arrayInterfaceImpl.parent = &l - return &l -} - -type stringArrayLiteral struct { - arrayInterfaceImpl[StringExpression] - literalExpressionImpl -} - -func StringArray(values []string) ArrayExpression[StringExpression] { - l := stringArrayLiteral{} - l.literalExpressionImpl = *literal(pq.StringArray(values)) - l.arrayInterfaceImpl.parent = &l - - return &l -} - -type unsafeArrayLiteral[E Expression] struct { - arrayInterfaceImpl[E] - literalExpressionImpl -} - -func UnsafeArray[E LiteralExpression](values []interface{}) ArrayExpression[E] { - l := unsafeArrayLiteral[E]{} - l.literalExpressionImpl = *literal(pq.Array(values)) - l.arrayInterfaceImpl.parent = &l - - return &l -} - // ---------------------------------------------------// type stringLiteral struct { stringInterfaceImpl diff --git a/internal/jet/operators.go b/internal/jet/operators.go index fa764b4..b56cb1b 100644 --- a/internal/jet/operators.go +++ b/internal/jet/operators.go @@ -22,15 +22,6 @@ func BIT_NOT(expr IntegerExpression) IntegerExpression { return newPrefixIntegerOperatorExpression(expr, "~") } -// ----------- Array operators -------------- // -func Any(lhs Expression, op BinaryBoolOp, rhs Expression) BoolExpression { - return op(lhs, Func("ANY", rhs)) -} - -func All(lhs Expression, op BinaryBoolOp, rhs Expression) BoolExpression { - return op(lhs, Func("ALL", rhs)) -} - //----------- Comparison operators ---------------// // EXISTS checks for existence of the rows in subQuery diff --git a/internal/jet/sql_builder.go b/internal/jet/sql_builder.go index c52b9b2..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 @@ -249,8 +248,6 @@ func (s *SQLBuilder) argToString(value interface{}) string { case string: return stringQuote(bindVal) - case []string: - return stringArrayQuote(bindVal) case []byte: return stringQuote(string(bindVal)) case uuid.UUID: @@ -278,19 +275,6 @@ func (s *SQLBuilder) argToString(value interface{}) string { } } -func stringArrayQuote(val []string) string { - var sb strings.Builder - sb.WriteString(`'{`) - for i := 0; i < len(val); i++ { - if i > 0 { - sb.WriteString(`, `) - } - sb.WriteString(stringDoubleQuote(val[i])) - } - sb.WriteString(`}'`) - return sb.String() -} - func integerTypesToString(value interface{}) string { switch bindVal := value.(type) { case int: @@ -339,7 +323,3 @@ func shouldQuoteIdentifier(identifier string) bool { func stringQuote(value string) string { return `'` + strings.Replace(value, "'", "''", -1) + `'` } - -func stringDoubleQuote(value string) string { - return `"` + strings.Replace(value, `"`, `""`, -1) + `"` -} diff --git a/internal/jet/string_expression.go b/internal/jet/string_expression.go index 569aa3b..5d373ca 100644 --- a/internal/jet/string_expression.go +++ b/internal/jet/string_expression.go @@ -17,9 +17,6 @@ type StringExpression interface { BETWEEN(min, max StringExpression) BoolExpression NOT_BETWEEN(min, max StringExpression) BoolExpression - ANY_EQ(rhs ArrayExpression[StringExpression]) BoolExpression - ALL_EQ(rhs ArrayExpression[StringExpression]) BoolExpression - CONCAT(rhs Expression) StringExpression LIKE(pattern StringExpression) BoolExpression @@ -75,14 +72,6 @@ func (s *stringInterfaceImpl) NOT_BETWEEN(min, max StringExpression) BoolExpress return NewBetweenOperatorExpression(s.root, min, max, true) } -func (i *stringInterfaceImpl) ANY_EQ(rhs ArrayExpression[StringExpression]) BoolExpression { - return Any(i.parent, Eq, rhs) -} - -func (i *stringInterfaceImpl) ALL_EQ(rhs ArrayExpression[StringExpression]) BoolExpression { - return All(i.parent, Eq, rhs) -} - func (s *stringInterfaceImpl) CONCAT(rhs Expression) StringExpression { return newBinaryStringOperatorExpression(s.root, rhs, StringConcatOperator) } diff --git a/internal/jet/string_expression_test.go b/internal/jet/string_expression_test.go index 830937f..0f461ac 100644 --- a/internal/jet/string_expression_test.go +++ b/internal/jet/string_expression_test.go @@ -76,14 +76,6 @@ func TestStringNOT_REGEXP_LIKE(t *testing.T) { assertClauseSerialize(t, table3StrCol.NOT_REGEXP_LIKE(String("JOHN"), true), "(table3.col2 NOT REGEXP $1)", "JOHN") } -func TestStringANY_EQ(t *testing.T) { - assertClauseSerialize(t, table2ColStr.ANY_EQ(table1ColStringArray), "(table2.col_str = ANY(table1.col_array_string))") -} - -func TestStringALL_EQ(t *testing.T) { - assertClauseSerialize(t, table2ColStr.ALL_EQ(table1ColStringArray), "(table2.col_str = ALL(table1.col_array_string))") -} - func TestStringExp(t *testing.T) { assertClauseSerialize(t, StringExp(table2ColFloat), "table2.col_float") assertClauseSerialize(t, StringExp(table2ColFloat).NOT_LIKE(String("abc")), "(table2.col_float NOT LIKE $1)", "abc") 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/columns.go b/postgres/columns.go index 5943246..01af0d7 100644 --- a/postgres/columns.go +++ b/postgres/columns.go @@ -112,21 +112,3 @@ type ColumnInt8Range jet.ColumnRange[jet.Int8Expression] // Int8RangeColumn creates named range with range column var Int8RangeColumn = jet.RangeColumn[jet.Int8Expression] - -// ColumnStringArray is interface of column -type ColumnStringArray jet.ColumnArray[jet.StringExpression] - -// StringArrayColumn creates named string array column -var StringArrayColumn = jet.ArrayColumn[jet.StringExpression] - -// ColumnIntegerArray is interface of column -type ColumnIntegerArray jet.ColumnArray[jet.IntegerExpression] - -// IntegerArrayColumn creates named integer array column -var IntegerArrayColumn = jet.ArrayColumn[jet.IntegerExpression] - -// ColumnBoolArray is interface of column -type ColumnBoolArray jet.ColumnArray[jet.BoolExpression] - -// BoolArrayColumn creates named bool array column -var BoolArrayColumn = jet.ArrayColumn[jet.BoolExpression] diff --git a/postgres/expressions.go b/postgres/expressions.go index 5ee75cd..f332aee 100644 --- a/postgres/expressions.go +++ b/postgres/expressions.go @@ -2,33 +2,24 @@ 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 // BoolExpression interface type BoolExpression = jet.BoolExpression -// BoolArrayExpression interface -type BoolArrayExpression = jet.ArrayExpression[BoolExpression] - // StringExpression interface type StringExpression = jet.StringExpression type ByteaExpression = jet.BlobExpression -// StringArrayExpression interface -type StringArrayExpression = jet.ArrayExpression[StringExpression] - // NumericExpression interface type NumericExpression = jet.NumericExpression // IntegerExpression interface type IntegerExpression = jet.IntegerExpression -// IntegerArrayExpression interface -type IntegerArrayExpression = jet.ArrayExpression[IntegerExpression] - // FloatExpression is interface type FloatExpression = jet.FloatExpression @@ -185,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..5907360 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, beginAt ...IntegerExpression) IntegerExpression { + return IntExp(Func("ARRAY_POSITION", optionalAppend([]Expression{arr, elem}, beginAt)...)) +} + +// 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/insert_statement_test.go b/postgres/insert_statement_test.go index bb4bbd8..5ace301 100644 --- a/postgres/insert_statement_test.go +++ b/postgres/insert_statement_test.go @@ -175,30 +175,27 @@ RETURNING table1.col1 AS "table1.col1", } func TestInsert_ON_CONFLICT_ON_CONSTRAINT(t *testing.T) { - stmt := table1.INSERT(table1Col1, table1ColBool, table1ColStringArray). - VALUES("one", "two", "three"). - VALUES("1", "2", "3"). - ON_CONFLICT().ON_CONSTRAINT("idk_primary_key").DO_UPDATE( - SET(table1ColBool.SET(Bool(false)), - table2ColInt.SET(Int(1)), - table1ColStringArray.SET(StringArray([]string{"one"})), - ColumnList{table1Col1, table1ColBool, table1ColStringArray}.SET(jet.ROW(Int(2), String("two"), StringArray([]string{"two"}))), - ).WHERE(table1Col1.GT(Int(2))), - ). - RETURNING(table1Col1, table1ColBool, table1ColStringArray) + stmt := table1.INSERT(table1Col1, table1ColBool). + VALUES("one", "two"). + VALUES("1", "2"). + ON_CONFLICT().ON_CONSTRAINT("idk_primary_key"). + DO_UPDATE( + SET(table1ColBool.SET(Bool(false)), + table2ColInt.SET(Int(1)), + ColumnList{table1Col1, table1ColBool}.SET(ROW(Int(2), String("two"))), + ).WHERE(table1Col1.GT(Int(2)))). + RETURNING(table1Col1, table1ColBool) assertDebugStatementSql(t, stmt, ` -INSERT INTO db.table1 (col1, col_bool, col_string_array) -VALUES ('one', 'two', 'three'), - ('1', '2', '3') +INSERT INTO db.table1 (col1, col_bool) +VALUES ('one', 'two'), + ('1', '2') ON CONFLICT ON CONSTRAINT idk_primary_key DO UPDATE SET col_bool = FALSE::boolean, col_int = 1, - col_string_array = '{"one"}', - (col1, col_bool, col_string_array) = ROW(2, 'two'::text, '{"two"}') + (col1, col_bool) = ROW(2, 'two'::text) WHERE table1.col1 > 2 RETURNING table1.col1 AS "table1.col1", - table1.col_bool AS "table1.col_bool", - table1.col_string_array AS "table1.col_string_array"; + table1.col_bool AS "table1.col_bool"; `) } diff --git a/postgres/literal.go b/postgres/literal.go index 40e4fc3..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" @@ -11,11 +13,6 @@ func Bool(value bool) BoolExpression { return CAST(jet.Bool(value)).AS_BOOL() } -// BoolArray creates new bool array literal expression -func BoolArray(elements []bool) BoolArrayExpression { - return jet.BoolArray(elements) -} - // Int is constructor for 64 bit signed integer expressions literals. var Int = jet.Int @@ -73,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. // @@ -85,11 +85,6 @@ func String(value string) StringExpression { return CAST(jet.String(value)).AS_TEXT() } -// StringArray creates new string array literal expression -func StringArray(elements []string) StringArrayExpression { - return jet.StringArray(elements) -} - // Text is a parameter constructor for the PostgreSQL text type. This constructor also adds an // explicit placeholder type cast to text in the generated query, such as `$3::text`. // Example usage: @@ -134,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 { @@ -195,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/tests/postgres/alltypes_test.go b/tests/postgres/alltypes_test.go index 994e21b..d7338fe 100644 --- a/tests/postgres/alltypes_test.go +++ b/tests/postgres/alltypes_test.go @@ -1,15 +1,13 @@ package postgres import ( - "database/sql" - "github.com/lib/pq" "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" @@ -46,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 @@ -55,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) @@ -117,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 @@ -259,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{} @@ -875,10 +868,7 @@ FROM ( err := stmtJson.QueryContext(ctx, db, &destSelectJson) require.NoError(t, err) - testutils.PrintJson(destSelectJson) - require.Equal(t, dest, destSelectJson) - }) } @@ -1583,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', @@ -2250,7 +2238,7 @@ var allTypesRow0 = model.AllTypes{ TextArrayPtr: &pq.StringArray{"breakfast", "consulting"}, TextArray: pq.StringArray{"breakfast", "consulting"}, JsonbArray: pq.StringArray{`{"a": 1, "b": 2}`, `{"a": 3, "b": 4}`}, - TextMultiDimArrayPtr: testutils.StringPtr("{{meeting,lunch},{training,presentation}}"), + TextMultiDimArrayPtr: ptr.Of("{{meeting,lunch},{training,presentation}}"), TextMultiDimArray: "{{meeting,lunch},{training,presentation}}", MoodPtr: &moodSad, Mood: model.Mood_Happy, diff --git a/tests/postgres/array_test.go b/tests/postgres/array_test.go new file mode 100644 index 0000000..ef13a73 --- /dev/null +++ b/tests/postgres/array_test.go @@ -0,0 +1,719 @@ +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"), //newer postgres versions + ARRAY_POSITIONS(stringArray, String("text")).AS("position"), + 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_POSITIONS($37::text[], $38::text) AS "position", + ARRAY_PREPEND($39::text, sample_arrays.text_array) AS "prepend", + ARRAY_REMOVE($40::boolean[], $41::boolean) AS "remove", + ARRAY_REPLACE(sample_arrays.varchar_array, $42::text, $43::text) AS "replace", + ARRAY_TO_STRING(sample_arrays.mood_enum_array, $44::text) AS "to_string", + ARRAY_UPPER(sample_arrays.int8_array, $45) AS "upper", + CARDINALITY(sample_arrays.double_array) AS "cardinality" +FROM test_sample.sample_arrays +WHERE sample_arrays.bool_array @> $46::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 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": [ + 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 7c787b8..20d76c1 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) 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 e130abc..910bd09 100644 --- a/tests/postgres/scan_test.go +++ b/tests/postgres/scan_test.go @@ -2,8 +2,8 @@ package postgres import ( "context" - "github.com/lib/pq" "github.com/go-jet/jet/v2/internal/utils/ptr" + "github.com/lib/pq" "github.com/volatiletech/null/v8" "testing" "time" @@ -1007,7 +1007,6 @@ func TestScanIntoCustomBaseTypes(t *testing.T) { type MyFloat32 float32 type MyFloat64 float64 type MyString string - type MyStringArray pq.StringArray type MyTime = time.Time type film struct { @@ -1022,13 +1021,12 @@ func TestScanIntoCustomBaseTypes(t *testing.T) { ReplacementCost MyFloat64 Rating *model.MpaaRating LastUpdate MyTime - SpecialFeatures MyStringArray + SpecialFeatures pq.StringArray Fulltext MyString } - // We'll skip special features, because it's a slice and it does not implement sql.Scanner stmt := SELECT( - Film.AllColumns.Except(Film.SpecialFeatures), + Film.AllColumns, ).FROM( Film, ).ORDER_BY( 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 6203a13..5fdefab 100644 --- a/tests/postgres/select_test.go +++ b/tests/postgres/select_test.go @@ -2710,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", @@ -2730,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" @@ -2740,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 @@ -2798,7 +2843,7 @@ ORDER BY actor.actor_id ASC, film.film_id ASC; require.NoError(t, err) }) - //testutils.SaveJSONFile(dest, "./testdata/results/postgres/quick-start-dest2.json") + //testutils.SaveJSONFile(dest2, "./testdata/results/postgres/quick-start-dest2.json") testutils.AssertJSONFile(t, dest2, "./testdata/results/postgres/quick-start-dest2.json") } @@ -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. 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