Change structure aliasing order.

This commit is contained in:
go-jet 2019-06-26 10:30:31 +02:00
parent 8be33b8774
commit b7ba58200e
9 changed files with 402 additions and 406 deletions

View file

@ -214,7 +214,7 @@ var dest []struct {
Films []struct { Films []struct {
model.Film model.Film
Language model.Language Language model.Language
Category []model.Category Categories []model.Category
} }
} }
``` ```
@ -263,7 +263,7 @@ fmt.Println(string(jsonText))
"Name": "English ", "Name": "English ",
"LastUpdate": "2006-02-15T10:02:19Z" "LastUpdate": "2006-02-15T10:02:19Z"
}, },
"Category": [ "Categories": [
{ {
"CategoryID": 8, "CategoryID": 8,
"Name": "Family", "Name": "Family",
@ -298,7 +298,7 @@ fmt.Println(string(jsonText))
"Name": "English ", "Name": "English ",
"LastUpdate": "2006-02-15T10:02:19Z" "LastUpdate": "2006-02-15T10:02:19Z"
}, },
"Category": [ "Categories": [
{ {
"CategoryID": 6, "CategoryID": 6,
"Name": "Documentary", "Name": "Documentary",
@ -319,8 +319,8 @@ In that case we can reuse above statement `stmt`, and just change our destinatio
var dest2 []struct { var dest2 []struct {
model.Category model.Category
Film []model.Film Films []model.Film
Actor []model.Actor Actors []model.Actor
} }
err = stmt.Query(db, &dest2) err = stmt.Query(db, &dest2)
@ -335,7 +335,7 @@ handleError(err)
"CategoryID": 8, "CategoryID": 8,
"Name": "Family", "Name": "Family",
"LastUpdate": "2006-02-15T09:46:27Z", "LastUpdate": "2006-02-15T09:46:27Z",
"Film": [ "Films": [
{ {
"FilmID": 499, "FilmID": 499,
"Title": "King Evolution", "Title": "King Evolution",
@ -367,7 +367,7 @@ handleError(err)
"Fulltext": "'bake':1 'cleopatra':2 'drama':5 'forens':8 'husband':12 'monasteri':20 'must':14 'overcom':15 'psychologist':9 'stun':4 'waitress':17" "Fulltext": "'bake':1 'cleopatra':2 'drama':5 'forens':8 'husband':12 'monasteri':20 'must':14 'overcom':15 'psychologist':9 'stun':4 'waitress':17"
} }
], ],
"Actor": [ "Actors": [
{ {
"ActorID": 1, "ActorID": 1,
"FirstName": "Penelope", "FirstName": "Penelope",
@ -418,6 +418,14 @@ handleError(err)
Complete code example can be found at [./examples/quick-start/quick-start.go](./examples/quick-start/quick-start.go) Complete code example can be found at [./examples/quick-start/quick-start.go](./examples/quick-start/quick-start.go)
This example represent probably the most common use case, but Jet offers much more. Like subqueries, INSERT, UPDATE, DELETE, LOCK statements and much more.
Detail info can be found at project wiki page.
# Benefits
TODO:
# Contributing # Contributing
# Versioning # Versioning

View file

@ -57,8 +57,8 @@ func main() {
model.Actor model.Actor
Films []struct { Films []struct {
model.Film model.Film
Language model.Language Language model.Language
Category []model.Category Categories []model.Category
} }
} }
@ -72,8 +72,8 @@ func main() {
var dest2 []struct { var dest2 []struct {
model.Category model.Category
Film []model.Film Films []model.Film
Actor []model.Actor Actors []model.Actor
} }
err = stmt.Query(db, &dest2) err = stmt.Query(db, &dest2)

View file

@ -139,7 +139,7 @@ func mapRowToSlice(scanContext *scanContext, groupKey string, slicePtrValue refl
if isGoBaseType(sliceElemType) { if isGoBaseType(sliceElemType) {
index := 0 index := 0
if structField != nil { if structField != nil {
tableName, columnName := getRefTableNameFrom(structField) tableName, columnName := getRefAlias(structField)
index = scanContext.columnIndex(tableName, columnName) index = scanContext.columnIndex(tableName, columnName)
if index < 0 { if index < 0 {
@ -297,7 +297,7 @@ func mapRowToStruct(scanContext *scanContext, groupKey string, structPtrValue re
structType := structPtrValue.Type().Elem() structType := structPtrValue.Type().Elem()
structValue := structPtrValue.Elem() structValue := structPtrValue.Elem()
tableName, _ := getRefTableNameFrom(structField) tableName, _ := getRefAlias(structField)
if tableName == "" { if tableName == "" {
tableName = structType.Name() tableName = structType.Name()
@ -365,30 +365,26 @@ func mapRowToStruct(scanContext *scanContext, groupKey string, structPtrValue re
return return
} }
func getRefTableNameFrom(structField *reflect.StructField) (table, column string) { func getRefAlias(structField *reflect.StructField) (table, column string) {
if structField == nil { if structField == nil {
return return
} }
sqlTag := structField.Tag.Get("sql") aliasTag := structField.Tag.Get("alias")
if sqlTag != "" { if aliasTag == "" {
tagInfo := tagInfo(sqlTag) return
return tagInfo.table, tagInfo.column
} }
if !structField.Anonymous { aliasParts := strings.Split(aliasTag, ".")
return structField.Name, ""
table = aliasParts[0]
if len(aliasParts) > 1 {
column = aliasParts[1]
} }
fieldType := indirectType(structField.Type) return
if fieldType.Kind() == reflect.Slice {
fieldType = fieldType.Elem()
}
return fieldType.Name(), ""
} }
func initializeValueIfNilPtr(value reflect.Value) { func initializeValueIfNilPtr(value reflect.Value) {
@ -612,7 +608,7 @@ func (s *scanContext) constructGroupKey(groupKeyInfo groupKeyInfo) string {
} }
func (s *scanContext) getGroupKeyInfo(structType reflect.Type, structField *reflect.StructField) groupKeyInfo { func (s *scanContext) getGroupKeyInfo(structType reflect.Type, structField *reflect.StructField) groupKeyInfo {
tableName, _ := getRefTableNameFrom(structField) tableName, _ := getRefAlias(structField)
if tableName == "" { if tableName == "" {
tableName = structType.Name() tableName = structType.Name()
@ -638,7 +634,7 @@ func (s *scanContext) getGroupKeyInfo(structType reflect.Type, structField *refl
if len(subType.indexes) != 0 || len(subType.subTypes) != 0 { if len(subType.indexes) != 0 || len(subType.subTypes) != 0 {
ret.subTypes = append(ret.subTypes, subType) ret.subTypes = append(ret.subTypes, subType)
} }
} else if tagInfo(field.Tag.Get("sql")).isPrimaryKey { } else if isPrimaryKey(field) {
index := s.columnIndex(tableName, field.Name) index := s.columnIndex(tableName, field.Name)
if index < 0 { if index < 0 {
@ -741,35 +737,11 @@ func (s *scanContext) rowElemValuePtr(index int) reflect.Value {
return newElem return newElem
} }
type sqlTagInfo struct { func isPrimaryKey(field reflect.StructField) bool {
isPrimaryKey bool
table string
column string
}
func tagInfo(tag string) sqlTagInfo { sqlTag := field.Tag.Get("sql")
sqlTags := strings.Split(tag, ",")
tagMap := map[string]string{}
for _, tag := range sqlTags { return sqlTag == "primary_key"
tagParts := strings.Split(tag, ":")
tagKey := tagParts[0]
tagValue := ""
if len(tagParts) > 1 {
tagValue = tagParts[1]
}
tagMap[tagKey] = tagValue
}
_, isPrimaryKey := tagMap["primary_key"]
return sqlTagInfo{
isPrimaryKey: isPrimaryKey,
table: tagMap["table"],
column: tagMap["column"],
}
} }
func indirectType(reflectType reflect.Type) reflect.Type { func indirectType(reflectType reflect.Type) reflect.Type {

View file

@ -83,7 +83,7 @@ func TestJoinEverything(t *testing.T) {
Genre model.Genre // track genre Genre model.Genre // track genre
MediaType model.MediaType // track media type MediaType model.MediaType // track media type
Playlists []model.Playlist `sql:"table:Playlist"` // list of playlist where track is used Playlists []model.Playlist // list of playlist where track is used
Invoices []struct { // list of invoices where track occurs Invoices []struct { // list of invoices where track occurs
model.Invoice model.Invoice
@ -94,7 +94,7 @@ func TestJoinEverything(t *testing.T) {
Employee *struct { // employee data for customer if exists Employee *struct { // employee data for customer if exists
model.Employee model.Employee
Manager *model.Employee Manager *model.Employee `alias:"Manager"`
} }
} }
} }

View file

@ -5,15 +5,15 @@ import (
"github.com/davecgh/go-spew/spew" "github.com/davecgh/go-spew/spew"
. "github.com/go-jet/jet" . "github.com/go-jet/jet"
"github.com/go-jet/jet/tests/.gentestdata/jetdb/test_sample/model" "github.com/go-jet/jet/tests/.gentestdata/jetdb/test_sample/model"
"github.com/go-jet/jet/tests/.gentestdata/jetdb/test_sample/table" . "github.com/go-jet/jet/tests/.gentestdata/jetdb/test_sample/table"
"gotest.tools/assert" "gotest.tools/assert"
"testing" "testing"
) )
func TestUUIDType(t *testing.T) { func TestUUIDType(t *testing.T) {
query := table.AllTypes. query := AllTypes.
SELECT(table.AllTypes.AllColumns). SELECT(AllTypes.AllColumns).
WHERE(table.AllTypes.UUID.EQ(String("a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11"))) WHERE(AllTypes.UUID.EQ(String("a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11")))
queryStr, args, err := query.Sql() queryStr, args, err := query.Sql()
@ -28,8 +28,8 @@ func TestUUIDType(t *testing.T) {
} }
func TestEnumType(t *testing.T) { func TestEnumType(t *testing.T) {
query := table.Person. query := Person.
SELECT(table.Person.AllColumns) SELECT(Person.AllColumns)
queryStr, args, err := query.Sql() queryStr, args, err := query.Sql()
@ -56,3 +56,63 @@ func TestEnumType(t *testing.T) {
spew.Dump(result2) spew.Dump(result2)
} }
func TestSelecSelfJoin1(t *testing.T) {
var expectedSql = `
SELECT employee.employee_id AS "employee.employee_id",
employee.first_name AS "employee.first_name",
employee.last_name AS "employee.last_name",
employee.employment_date AS "employee.employment_date",
employee.manager_id AS "employee.manager_id",
manager.employee_id AS "manager.employee_id",
manager.first_name AS "manager.first_name",
manager.last_name AS "manager.last_name",
manager.employment_date AS "manager.employment_date",
manager.manager_id AS "manager.manager_id"
FROM test_sample.employee
LEFT JOIN test_sample.employee AS manager ON (manager.employee_id = employee.manager_id)
ORDER BY employee.employee_id;
`
manager := Employee.AS("manager")
query := Employee.
LEFT_JOIN(manager, manager.EmployeeID.EQ(Employee.ManagerID)).
SELECT(
Employee.AllColumns,
manager.AllColumns,
).
ORDER_BY(Employee.EmployeeID)
assertStatementSql(t, query, expectedSql)
type Manager model.Employee
var dest []struct {
model.Employee
Manager *Manager
}
err := query.Query(db, &dest)
assert.NilError(t, err)
assert.Equal(t, len(dest), 8)
assert.DeepEqual(t, dest[0].Employee, model.Employee{
EmployeeID: 1,
FirstName: "Windy",
LastName: "Hays",
EmploymentDate: timestampWithTimeZone("1999-01-08 04:05:06.1 +0100 CET", 1),
ManagerID: nil,
})
assert.Assert(t, dest[0].Manager == nil)
assert.DeepEqual(t, dest[7].Employee, model.Employee{
EmployeeID: 8,
FirstName: "Salley",
LastName: "Lester",
EmploymentDate: timestampWithTimeZone("1999-01-08 04:05:06 +0100 CET", 1),
ManagerID: int32Ptr(3),
})
}

View file

@ -144,7 +144,7 @@ func TestScanToStruct(t *testing.T) {
t.Run("custom struct", func(t *testing.T) { t.Run("custom struct", func(t *testing.T) {
type Inventory struct { type Inventory struct {
InventoryID *int32 `sql:"unique"` InventoryID *int32 `sql:"primary_key"`
FilmID int16 FilmID int16
StoreID *int16 StoreID *int16
} }
@ -373,8 +373,8 @@ func TestScanToNestedStruct(t *testing.T) {
model.Film model.Film
Language model.Language Language model.Language
Language2 *model.Language Language2 *model.Language `alias:"Language.*"`
Language3 *Language3 `sql:"table:language"` Language3 *Language3 `alias:"language"`
Lang struct { Lang struct {
model.Language model.Language
} }
@ -394,7 +394,7 @@ func TestScanToNestedStruct(t *testing.T) {
assert.DeepEqual(t, dest.Film.Language, language1) assert.DeepEqual(t, dest.Film.Language, language1)
assert.DeepEqual(t, dest.Film.Lang.Language, language1) assert.DeepEqual(t, dest.Film.Lang.Language, language1)
assert.DeepEqual(t, dest.Film.Lang2.Language, language1) assert.DeepEqual(t, dest.Film.Lang2.Language, language1)
assert.DeepEqual(t, dest.Film.Language2, (*model.Language)(nil)) assert.DeepEqual(t, dest.Film.Language2, &language1)
assert.DeepEqual(t, model.Language(*dest.Film.Language3), language1) assert.DeepEqual(t, model.Language(*dest.Film.Language3), language1)
}) })
} }
@ -439,14 +439,18 @@ func TestScanToSlice(t *testing.T) {
query := Inventory. query := Inventory.
INNER_JOIN(Film, Inventory.FilmID.EQ(Film.FilmID)). INNER_JOIN(Film, Inventory.FilmID.EQ(Film.FilmID)).
INNER_JOIN(Store, Inventory.StoreID.EQ(Store.StoreID)). INNER_JOIN(Store, Inventory.StoreID.EQ(Store.StoreID)).
SELECT(Inventory.AllColumns, Film.AllColumns, Store.AllColumns). SELECT(
Inventory.AllColumns,
Film.AllColumns,
Store.AllColumns,
).
ORDER_BY(Inventory.InventoryID). ORDER_BY(Inventory.InventoryID).
LIMIT(10) LIMIT(10)
t.Run("struct with slice of ints", func(t *testing.T) { t.Run("struct with slice of ints", func(t *testing.T) {
var dest struct { var dest struct {
model.Film model.Film
IDs []int32 `sql:"table:inventory,column:inventory_id"` IDs []int32 `alias:"inventory.inventory_id"`
} }
err := query.Query(db, &dest) err := query.Query(db, &dest)
@ -463,7 +467,7 @@ func TestScanToSlice(t *testing.T) {
t.Run("slice of structs with slice of ints", func(t *testing.T) { t.Run("slice of structs with slice of ints", func(t *testing.T) {
var dest []struct { var dest []struct {
model.Film model.Film
IDs []int32 `sql:"table:inventory,column:inventory_id"` IDs []int32 `alias:"Inventory.inventory_id"`
} }
err := query.Query(db, &dest) err := query.Query(db, &dest)
@ -479,7 +483,7 @@ func TestScanToSlice(t *testing.T) {
t.Run("slice of structs with slice of pointer to ints", func(t *testing.T) { t.Run("slice of structs with slice of pointer to ints", func(t *testing.T) {
var dest []struct { var dest []struct {
model.Film model.Film
IDs []*int32 `sql:"table:inventory,column:inventory_id"` IDs []*int32 `alias:"inventory.InventoryId"`
} }
err := query.Query(db, &dest) err := query.Query(db, &dest)

View file

@ -7,8 +7,6 @@ import (
"github.com/go-jet/jet/tests/.gentestdata/jetdb/dvds/enum" "github.com/go-jet/jet/tests/.gentestdata/jetdb/dvds/enum"
"github.com/go-jet/jet/tests/.gentestdata/jetdb/dvds/model" "github.com/go-jet/jet/tests/.gentestdata/jetdb/dvds/model"
. "github.com/go-jet/jet/tests/.gentestdata/jetdb/dvds/table" . "github.com/go-jet/jet/tests/.gentestdata/jetdb/dvds/table"
model2 "github.com/go-jet/jet/tests/.gentestdata/jetdb/test_sample/model"
. "github.com/go-jet/jet/tests/.gentestdata/jetdb/test_sample/table"
"gotest.tools/assert" "gotest.tools/assert"
"testing" "testing"
) )
@ -490,61 +488,6 @@ LIMIT 1000;
assert.NilError(t, err) assert.NilError(t, err)
} }
func TestSelecSelfJoin1(t *testing.T) {
var expectedSql = `
SELECT employee.employee_id AS "employee.employee_id",
employee.first_name AS "employee.first_name",
employee.last_name AS "employee.last_name",
employee.employment_date AS "employee.employment_date",
employee.manager_id AS "employee.manager_id",
manager.employee_id AS "manager.employee_id",
manager.first_name AS "manager.first_name",
manager.last_name AS "manager.last_name",
manager.employment_date AS "manager.employment_date",
manager.manager_id AS "manager.manager_id"
FROM test_sample.employee
LEFT JOIN test_sample.employee AS manager ON (manager.employee_id = employee.manager_id)
ORDER BY employee.employee_id;
`
manager := Employee.AS("manager")
query := Employee.
LEFT_JOIN(manager, manager.EmployeeID.EQ(Employee.ManagerID)).
SELECT(Employee.AllColumns, manager.AllColumns).
ORDER_BY(Employee.EmployeeID)
assertStatementSql(t, query, expectedSql)
var dest []struct {
model2.Employee
Manager *model2.Employee
}
err := query.Query(db, &dest)
assert.NilError(t, err)
assert.Equal(t, len(dest), 8)
assert.DeepEqual(t, dest[0].Employee, model2.Employee{
EmployeeID: 1,
FirstName: "Windy",
LastName: "Hays",
EmploymentDate: timestampWithTimeZone("1999-01-08 04:05:06.1 +0100 CET", 1),
ManagerID: nil,
})
assert.Assert(t, dest[0].Manager == nil)
assert.DeepEqual(t, dest[7].Employee, model2.Employee{
EmployeeID: 8,
FirstName: "Salley",
LastName: "Lester",
EmploymentDate: timestampWithTimeZone("1999-01-08 04:05:06 +0100 CET", 1),
ManagerID: int32Ptr(3),
})
}
func TestSelectSelfJoin(t *testing.T) { func TestSelectSelfJoin(t *testing.T) {
expectedSql := ` expectedSql := `
SELECT f1.film_id AS "f1.film_id", SELECT f1.film_id AS "f1.film_id",
@ -647,63 +590,6 @@ LIMIT 1000;
assert.DeepEqual(t, films[0], thesameLengthFilms{"Alien Center", "Iron Moon", 46}) assert.DeepEqual(t, films[0], thesameLengthFilms{"Alien Center", "Iron Moon", 46})
} }
//
//type Manager staff
//
//type staff struct {
// StaffID int32 `sql:"unique"`
// FirstName string
// LastName string
// //Address *model.Address
// //Email *string
// //StoreID int16
// //Active bool
// //Username string
// //Password *string
// //LastUpdate time.Time
// *Manager //`sqlbuilder:"manager"`
//}
//
//func TestSelectSelfReferenceType(t *testing.T) {
//
// expectedSql := `
//SELECT DISTINCT staff.staff_id AS "staff.staff_id",
// staff.first_name AS "staff.first_name",
// staff.last_name AS "staff.last_name",
// address.address_id AS "address.address_id",
// address.address AS "address.address",
// address.address2 AS "address.address2",
// address.district AS "address.district",
// address.city_id AS "address.city_id",
// address.postal_code AS "address.postal_code",
// address.phone AS "address.phone",
// address.last_update AS "address.last_update",
// manager.staff_id AS "manager.staff_id",
// manager.first_name AS "manager.first_name"
//FROM dvds.staff
// JOIN dvds.address ON staff.address_id = address.address_id
// JOIN dvds.staff AS manager ON staff.staff_id = manager.staff_id;
//`
// manager := Staff.AS("manager")
//
// query := Staff.
// innerJoin(Address, Staff.AddressID.EQ(Address.AddressID)).
// innerJoin(manager, Staff.StaffID.EQ(manager.StaffID)).
// SELECT(Staff.StaffID, Staff.FirstName, Staff.LastName, Address.AllColumns, manager.StaffID, manager.FirstName).
// DISTINCT()
//
// assertStatementSql(t, query, expectedSql)
//
// staffs := []staff{}
//
// err := query.Query(db, &staffs)
//
// assert.NilError(t, err)
//
// fmt.Println(query.DebugSql())
// //spew.Dump(staffs)
//}
func TestSubQuery(t *testing.T) { func TestSubQuery(t *testing.T) {
expectedQuery := ` expectedQuery := `
SELECT actor.actor_id AS "actor.actor_id", SELECT actor.actor_id AS "actor.actor_id",
@ -1219,7 +1105,7 @@ FOR`
} }
} }
func TestForQuickStart(t *testing.T) { func TestQuickStart(t *testing.T) {
var expectedSql = ` var expectedSql = `
SELECT actor.actor_id AS "actor.actor_id", SELECT actor.actor_id AS "actor.actor_id",
@ -1286,24 +1172,90 @@ ORDER BY actor.actor_id ASC, film.film_id ASC;
Language model.Language Language model.Language
Category []model.Category Categories []model.Category
} }
} }
err := stmt.Query(db, &dest) err := stmt.Query(db, &dest)
assert.NilError(t, err) assert.NilError(t, err)
//jsonSave("./testdata/quick-start-dest.json", dest)
assertJson(t, "./testdata/quick-start-dest.json", dest) assertJson(t, "./testdata/quick-start-dest.json", dest)
var dest2 []struct { var dest2 []struct {
model.Category model.Category
Film []model.Film Films []model.Film
Actor []model.Actor Actors []model.Actor
} }
err = stmt.Query(db, &dest2) err = stmt.Query(db, &dest2)
assert.NilError(t, err) assert.NilError(t, err)
//jsonSave("./testdata/quick-start-dest2.json", dest2)
assertJson(t, "./testdata/quick-start-dest2.json", dest2)
}
func TestQuickStartWithSubQueries(t *testing.T) {
filmLogerThan180 := Film.
SELECT(Film.AllColumns).
WHERE(Film.Length.GT(Int(180))).
AsTable("films")
filmId := Film.FilmID.From(filmLogerThan180)
filmLanguageId := Film.LanguageID.From(filmLogerThan180)
categoriesNotAction := Category.
SELECT(Category.AllColumns).
WHERE(Category.Name.NOT_EQ(String("Action"))).
AsTable("categories")
categoryId := Category.CategoryID.From(categoriesNotAction)
stmt := Actor.
INNER_JOIN(FilmActor, Actor.ActorID.EQ(FilmActor.ActorID)).
INNER_JOIN(filmLogerThan180, filmId.EQ(FilmActor.FilmID)).
INNER_JOIN(Language, Language.LanguageID.EQ(filmLanguageId)).
INNER_JOIN(FilmCategory, FilmCategory.FilmID.EQ(filmId)).
INNER_JOIN(categoriesNotAction, categoryId.EQ(FilmCategory.CategoryID)).
SELECT(
Actor.AllColumns,
filmLogerThan180.AllColumns(),
Language.AllColumns,
categoriesNotAction.AllColumns(),
).ORDER_BY(
Actor.ActorID.ASC(),
filmId.ASC(),
)
var dest []struct {
model.Actor
Films []struct {
model.Film
Language model.Language
Categories []model.Category
}
}
err := stmt.Query(db, &dest)
assert.NilError(t, err)
//jsonSave("./testdata/quick-start-dest.json", dest)
assertJson(t, "./testdata/quick-start-dest.json", dest)
var dest2 []struct {
model.Category
Films []model.Film
Actors []model.Actor
}
err = stmt.Query(db, &dest2)
assert.NilError(t, err)
//jsonSave("./testdata/quick-start-dest2.json", dest2)
assertJson(t, "./testdata/quick-start-dest2.json", dest2) assertJson(t, "./testdata/quick-start-dest2.json", dest2)
} }

File diff suppressed because it is too large Load diff

View file

@ -3,7 +3,7 @@
"CategoryID": 8, "CategoryID": 8,
"Name": "Family", "Name": "Family",
"LastUpdate": "2006-02-15T09:46:27Z", "LastUpdate": "2006-02-15T09:46:27Z",
"Film": [ "Films": [
{ {
"FilmID": 499, "FilmID": 499,
"Title": "King Evolution", "Title": "King Evolution",
@ -35,7 +35,7 @@
"Fulltext": "'bake':1 'cleopatra':2 'drama':5 'forens':8 'husband':12 'monasteri':20 'must':14 'overcom':15 'psychologist':9 'stun':4 'waitress':17" "Fulltext": "'bake':1 'cleopatra':2 'drama':5 'forens':8 'husband':12 'monasteri':20 'must':14 'overcom':15 'psychologist':9 'stun':4 'waitress':17"
} }
], ],
"Actor": [ "Actors": [
{ {
"ActorID": 1, "ActorID": 1,
"FirstName": "Penelope", "FirstName": "Penelope",
@ -84,7 +84,7 @@
"CategoryID": 6, "CategoryID": 6,
"Name": "Documentary", "Name": "Documentary",
"LastUpdate": "2006-02-15T09:46:27Z", "LastUpdate": "2006-02-15T09:46:27Z",
"Film": [ "Films": [
{ {
"FilmID": 996, "FilmID": 996,
"Title": "Young Language", "Title": "Young Language",
@ -116,7 +116,7 @@
"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" "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"
} }
], ],
"Actor": [ "Actors": [
{ {
"ActorID": 3, "ActorID": 3,
"FirstName": "Ed", "FirstName": "Ed",
@ -189,7 +189,7 @@
"CategoryID": 12, "CategoryID": 12,
"Name": "Music", "Name": "Music",
"LastUpdate": "2006-02-15T09:46:27Z", "LastUpdate": "2006-02-15T09:46:27Z",
"Film": [ "Films": [
{ {
"FilmID": 721, "FilmID": 721,
"Title": "Reds Pocus", "Title": "Reds Pocus",
@ -236,7 +236,7 @@
"Fulltext": "'car':8 'confront':14 'duck':2 'fate':4 'monasteri':19 'must':13 'reflect':5 'scalawag':1 'teacher':11 'waitress':16" "Fulltext": "'car':8 'confront':14 'duck':2 'fate':4 'monasteri':19 'must':13 'reflect':5 'scalawag':1 'teacher':11 'waitress':16"
} }
], ],
"Actor": [ "Actors": [
{ {
"ActorID": 4, "ActorID": 4,
"FirstName": "Jennifer", "FirstName": "Jennifer",
@ -339,7 +339,7 @@
"CategoryID": 13, "CategoryID": 13,
"Name": "New", "Name": "New",
"LastUpdate": "2006-02-15T09:46:27Z", "LastUpdate": "2006-02-15T09:46:27Z",
"Film": [ "Films": [
{ {
"FilmID": 340, "FilmID": 340,
"Title": "Frontier Cabin", "Title": "Frontier Cabin",
@ -386,7 +386,7 @@
"Fulltext": "'abandon':19 'boat':8,16 'documentari':5 'fun':20 'hous':21 'man':11 'meet':14 'must':13 'runaway':1 'tenenbaum':2 'thought':4" "Fulltext": "'abandon':19 'boat':8,16 'documentari':5 'fun':20 'hous':21 'man':11 'meet':14 'must':13 'runaway':1 'tenenbaum':2 'thought':4"
} }
], ],
"Actor": [ "Actors": [
{ {
"ActorID": 5, "ActorID": 5,
"FirstName": "Johnny", "FirstName": "Johnny",
@ -471,7 +471,7 @@
"CategoryID": 11, "CategoryID": 11,
"Name": "Horror", "Name": "Horror",
"LastUpdate": "2006-02-15T09:46:27Z", "LastUpdate": "2006-02-15T09:46:27Z",
"Film": [ "Films": [
{ {
"FilmID": 535, "FilmID": 535,
"Title": "Love Suicides", "Title": "Love Suicides",
@ -503,7 +503,7 @@
"Fulltext": "'analyz':1 'chef':12 'desert':21 'display':5 'explor':8 'feminist':17 'hoosier':2 'must':14 'overcom':15 'pastri':11 'sahara':20 'thought':4" "Fulltext": "'analyz':1 'chef':12 'desert':21 'display':5 'explor':8 'feminist':17 'hoosier':2 'must':14 'overcom':15 'pastri':11 'sahara':20 'thought':4"
} }
], ],
"Actor": [ "Actors": [
{ {
"ActorID": 5, "ActorID": 5,
"FirstName": "Johnny", "FirstName": "Johnny",
@ -552,7 +552,7 @@
"CategoryID": 14, "CategoryID": 14,
"Name": "Sci-Fi", "Name": "Sci-Fi",
"LastUpdate": "2006-02-15T09:46:27Z", "LastUpdate": "2006-02-15T09:46:27Z",
"Film": [ "Films": [
{ {
"FilmID": 817, "FilmID": 817,
"Title": "Soldiers Evolution", "Title": "Soldiers Evolution",
@ -569,7 +569,7 @@
"Fulltext": "'confront':15 'evolut':2 'first':20 'lacklustur':4 'man':21 'must':14 'panorama':5 'pioneer':12 'shark':9 'soldier':1 'space':22 'station':23 'student':17" "Fulltext": "'confront':15 'evolut':2 'first':20 'lacklustur':4 'man':21 'must':14 'panorama':5 'pioneer':12 'shark':9 'soldier':1 'space':22 'station':23 'student':17"
} }
], ],
"Actor": [ "Actors": [
{ {
"ActorID": 5, "ActorID": 5,
"FirstName": "Johnny", "FirstName": "Johnny",
@ -630,7 +630,7 @@
"CategoryID": 15, "CategoryID": 15,
"Name": "Sports", "Name": "Sports",
"LastUpdate": "2006-02-15T09:46:27Z", "LastUpdate": "2006-02-15T09:46:27Z",
"Film": [ "Films": [
{ {
"FilmID": 841, "FilmID": 841,
"Title": "Star Operation", "Title": "Star Operation",
@ -677,7 +677,7 @@
"Fulltext": "'ancient':19 'china':20 'control':2 'documentari':5 'face':14 'feminist':11 'husband':8 'mad':16 'must':13 'scientist':17 'smoochi':1 'thrill':4" "Fulltext": "'ancient':19 'china':20 'control':2 'documentari':5 'face':14 'feminist':11 'husband':8 'mad':16 'must':13 'scientist':17 'smoochi':1 'thrill':4"
} }
], ],
"Actor": [ "Actors": [
{ {
"ActorID": 5, "ActorID": 5,
"FirstName": "Johnny", "FirstName": "Johnny",
@ -774,7 +774,7 @@
"CategoryID": 2, "CategoryID": 2,
"Name": "Animation", "Name": "Animation",
"LastUpdate": "2006-02-15T09:46:27Z", "LastUpdate": "2006-02-15T09:46:27Z",
"Film": [ "Films": [
{ {
"FilmID": 510, "FilmID": 510,
"Title": "Lawless Vision", "Title": "Lawless Vision",
@ -851,7 +851,7 @@
"Fulltext": "'ancient':18 'battl':14 'boat':11 'china':19 'drama':5 'feminist':16 'must':13 'pond':1 'seattl':2 'stun':4 'teacher':8" "Fulltext": "'ancient':18 'battl':14 'boat':11 'china':19 'drama':5 'feminist':16 'must':13 'pond':1 'seattl':2 'stun':4 'teacher':8"
} }
], ],
"Actor": [ "Actors": [
{ {
"ActorID": 9, "ActorID": 9,
"FirstName": "Joe", "FirstName": "Joe",
@ -996,7 +996,7 @@
"CategoryID": 10, "CategoryID": 10,
"Name": "Games", "Name": "Games",
"LastUpdate": "2006-02-15T09:46:27Z", "LastUpdate": "2006-02-15T09:46:27Z",
"Film": [ "Films": [
{ {
"FilmID": 597, "FilmID": 597,
"Title": "Moonwalker Fool", "Title": "Moonwalker Fool",
@ -1058,7 +1058,7 @@
"Fulltext": "'battl':15 'california':19 'chicago':1 'cow':9 'fate':4 'mad':8 'must':14 'north':2 'student':17 'waitress':12 'yarn':5" "Fulltext": "'battl':15 'california':19 'chicago':1 'cow':9 'fate':4 'mad':8 'must':14 'north':2 'student':17 'waitress':12 'yarn':5"
} }
], ],
"Actor": [ "Actors": [
{ {
"ActorID": 11, "ActorID": 11,
"FirstName": "Zero", "FirstName": "Zero",
@ -1209,7 +1209,7 @@
"CategoryID": 5, "CategoryID": 5,
"Name": "Comedy", "Name": "Comedy",
"LastUpdate": "2006-02-15T09:46:27Z", "LastUpdate": "2006-02-15T09:46:27Z",
"Film": [ "Films": [
{ {
"FilmID": 182, "FilmID": 182,
"Title": "Control Anthem", "Title": "Control Anthem",
@ -1256,7 +1256,7 @@
"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" "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"
} }
], ],
"Actor": [ "Actors": [
{ {
"ActorID": 19, "ActorID": 19,
"FirstName": "Bob", "FirstName": "Bob",
@ -1317,7 +1317,7 @@
"CategoryID": 7, "CategoryID": 7,
"Name": "Drama", "Name": "Drama",
"LastUpdate": "2006-02-15T09:46:27Z", "LastUpdate": "2006-02-15T09:46:27Z",
"Film": [ "Films": [
{ {
"FilmID": 473, "FilmID": 473,
"Title": "Jacket Frisco", "Title": "Jacket Frisco",
@ -1334,7 +1334,7 @@
"Fulltext": "'baloon':20 'chef':17 'conquer':14 'frisco':2 'husband':11 'insight':4 'jacket':1 'must':13 'pastri':16 'reflect':5 'woman':8" "Fulltext": "'baloon':20 'chef':17 'conquer':14 'frisco':2 'husband':11 'insight':4 'jacket':1 'must':13 'pastri':16 'reflect':5 'woman':8"
} }
], ],
"Actor": [ "Actors": [
{ {
"ActorID": 19, "ActorID": 19,
"FirstName": "Bob", "FirstName": "Bob",
@ -1401,7 +1401,7 @@
"CategoryID": 9, "CategoryID": 9,
"Name": "Foreign", "Name": "Foreign",
"LastUpdate": "2006-02-15T09:46:27Z", "LastUpdate": "2006-02-15T09:46:27Z",
"Film": [ "Films": [
{ {
"FilmID": 435, "FilmID": 435,
"Title": "Hotel Happiness", "Title": "Hotel Happiness",
@ -1478,7 +1478,7 @@
"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" "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"
} }
], ],
"Actor": [ "Actors": [
{ {
"ActorID": 23, "ActorID": 23,
"FirstName": "Sandra", "FirstName": "Sandra",
@ -1617,7 +1617,7 @@
"CategoryID": 4, "CategoryID": 4,
"Name": "Classics", "Name": "Classics",
"LastUpdate": "2006-02-15T09:46:27Z", "LastUpdate": "2006-02-15T09:46:27Z",
"Film": [ "Films": [
{ {
"FilmID": 180, "FilmID": 180,
"Title": "Conspiracy Spirit", "Title": "Conspiracy Spirit",
@ -1634,7 +1634,7 @@
"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" "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"
} }
], ],
"Actor": [ "Actors": [
{ {
"ActorID": 43, "ActorID": 43,
"FirstName": "Kirk", "FirstName": "Kirk",
@ -1665,7 +1665,7 @@
"CategoryID": 16, "CategoryID": 16,
"Name": "Travel", "Name": "Travel",
"LastUpdate": "2006-02-15T09:46:27Z", "LastUpdate": "2006-02-15T09:46:27Z",
"Film": [ "Films": [
{ {
"FilmID": 609, "FilmID": 609,
"Title": "Muscle Bright", "Title": "Muscle Bright",
@ -1697,7 +1697,7 @@
"Fulltext": "'baloon':21 'brotherhood':2 'chase':15 'epistl':5 'forens':17 'hunter':12 'must':14 'psychologist':18 'sumo':8 'sweet':1 'unbeliev':4 'wrestler':9" "Fulltext": "'baloon':21 'brotherhood':2 'chase':15 'epistl':5 'forens':17 'hunter':12 'must':14 'psychologist':18 'sumo':8 'sweet':1 'unbeliev':4 'wrestler':9"
} }
], ],
"Actor": [ "Actors": [
{ {
"ActorID": 72, "ActorID": 72,
"FirstName": "Sean", "FirstName": "Sean",