Exemplo n.º 1
0
        public void TestRightWayToSetupRelationshipsOk()
        {
            //SETUP
            var showlog = false;
            var options = SqliteInMemory.CreateOptionsWithLogging <EfCoreContext>(log =>
            {
                if (showlog)
                {
                    _output.WriteLine(log.Message);
                }
            });

            using (var context = new EfCoreContext(options))
            {
                context.Database.EnsureCreated();

                showlog = true;
                //ATTEMPT
                var book = new Book               //#A
                {                                 //#A
                    Title   = "Test",             //#A
                    Reviews = new List <Review>() //#A
                };                                //#A
                book.Reviews.Add(                 //#B
                    new Review {
                    NumStars = 1
                });                               //#B
                context.Add(book);                //#C
                context.SaveChanges();            //#D

                /*********************************************************
                #A This creates a new Book
                #B This adds a new Review to the Book's Reviews navigational property
                #C The Add method says that the entity instance should be Added to the appropriate row, with any relationships either added or updated
                #D The SaveChanges carries out the database update
                *********************************************************/

                //VERIFY
                var bookWithReview = context.Books.Include(x => x.Reviews).Single();
                bookWithReview.Reviews.Count.ShouldEqual(1);
            }
        }
        public void TestCreateBookWithExistingAuthorAttached()
        {
            //SETUP
            Author disconnectedAuthor;
            var    options = SqliteInMemory.CreateOptions <EfCoreContext>();

            using (var context = new EfCoreContext(options))
            {
                context.Database.EnsureCreated();
                context.SeedDatabaseFourBooks();

                //ATTEMPT
                disconnectedAuthor = context.Authors.First();
            }

            using (var context = new EfCoreContext(options))
            {
                var book = new Book
                {
                    Title       = "Test Book",
                    PublishedOn = DateTime.Today
                };
                context.Authors.Attach(disconnectedAuthor);
                book.AuthorsLink = new List <BookAuthor>
                {
                    new BookAuthor
                    {
                        Book   = book,
                        Author = disconnectedAuthor
                    }
                };

                //ATTEMPT
                context.Add(book);
                context.SaveChanges();

                //VERIFY
                context.Books.Count().ShouldEqual(5);
                context.Authors.Count().ShouldEqual(3);
            }
        }
        public void TestCreateBookWithReview()
        {
            //SETUP
            var options = SqliteInMemory.CreateOptions <EfCoreContext>();

            using (var context = new EfCoreContext(options))
            {
                context.Database.EnsureCreated();

                var book = new Book                         //#A
                {                                           //#A
                    Title       = "Test Book",              //#A
                    PublishedOn = DateTime.Today,           //#A
                    Reviews     = new List <Review>()       //#B
                    {
                        new Review                          //#C
                        {                                   //#C
                            NumStars  = 5,                  //#C
                            Comment   = "Great test book!", //#C
                            VoterName = "Mr U Test"         //#C
                        }
                    }
                };

                //ATTEMPT
                context.Add(book);                      //#D
                context.SaveChanges();                  //#E

                /******************************************************
                 #A This creates the book with the title "Test Book"
                 #B I create a new collection of Reviews
                 #C I add one review, with its content
                 #D It uses the .Add method to add the book to the application's DbContext property, Books
                 #E It calls the SaveChanges() method from the application's DbContext to update the database. It finds a new Book, which has a collection containing a new Review, so it adds both of these to the database
                 * *****************************************************/

                //VERIFY
                context.Books.Count().ShouldEqual(1);
                context.Set <Review>().Count().ShouldEqual(1);
            }
        }
        public void TestTestCreateBookWithExistingAuthorOk()
        {
            //SETUP
            var options = SqliteInMemory.CreateOptions <EfCoreContext>();

            using (var context = new EfCoreContext(options))
            {
                context.Database.EnsureCreated();
                context.SeedDatabaseFourBooks();
            }
            using (var context = new EfCoreContext(options))
            {
                //STAGE1                                        //#A
                var author     = context.Authors.First();       //#B
                var bookAuthor = new BookAuthor {
                    Author = author
                };                                                   //#C
                var book = new Book                                  //#D
                {                                                    //#D
                    Title       = "Test Book",                       //#D
                    AuthorsLink = new List <BookAuthor> {
                        bookAuthor
                    }                                                //#D
                };                                                   //#D

                //STAGE2
                context.Add(book);                                  //#E

                //STAGE3
                context.SaveChanges();                              //#F

                /*********************************************************
                 #A Each of the three stages start with a comment
                 #B This reads in an existing Author for the new book
                 #C This creates a new BookAuthor linking table ready to link to Book to the Author
                 #D This creates a Book, and fills in the AuthorsLink navigational property with a single entry, linking it to the existing Author
                 #E This is where you call the Add method, which tells EF Core that the Book needs to be added to the database.
                 #F SaveChanges now looks the all the tracked entities and works out how to update the database to achieve what you have asked it to do
                 ******************************************************/
            }
        }
Exemplo n.º 5
0
        public void TestDeleteBookWithDependentEntityCascadeDeleteOk()
        {
            //SETUP
            int bookId;
            var options = SqliteInMemory.CreateOptions <EfCoreContext>();

            using var context = new EfCoreContext(options);
            context.Database.EnsureCreated();
            var bookSetup = new Book
            {
                Title   = "Test Book",
                Reviews = new List <Review> {
                    new Review()
                }
            };

            context.Add(bookSetup);
            context.SaveChanges();
            bookId = bookSetup.BookId;
            context.Books.Count().ShouldEqual(1);
            context.Set <Review>().Count().ShouldEqual(1);

            context.ChangeTracker.Clear();

            //ATTEMPT
            var book = new Book {
                BookId = bookId
            };

            context.Remove(book);
            context.SaveChanges();

            context.ChangeTracker.Clear();

            //VERIFY

            context.ChangeTracker.Clear();

            context.Books.Count().ShouldEqual(0);
            context.Set <Review>().Count().ShouldEqual(0);
        }
Exemplo n.º 6
0
        public void TestBookQueryWithIncludes()
        {
            //SETUP
            var options = SqliteInMemory.CreateOptions <EfCoreContext>();

            using var context = new EfCoreContext(options);
            context.Database.EnsureCreated();
            var book4Reviews2Authors = EfTestData.CreateDummyBooks(5).Last();

            context.Add(book4Reviews2Authors);
            context.SaveChanges();

            //ATTEMPT
            var query = context.Books
                        .Include(x => x.Reviews)
                        .Include(x => x.AuthorsLink)
                        .ThenInclude(x => x.Author);

            //VERIFY
            _output.WriteLine(query.ToQueryString());
        }
Exemplo n.º 7
0
        public void TestDeleteBookNoRelationshipsOk()
        {
            //SETUP
            int bookId;
            var options = SqliteInMemory.CreateOptions <EfCoreContext>();

            using var context = new EfCoreContext(options);
            context.Database.EnsureCreated();
            var bookSetup = new Book {
                Title = "Test Book"
            };

            context.Add(bookSetup);
            context.SaveChanges();
            bookId = bookSetup.BookId;


            context.ChangeTracker.Clear();

            //ATTEMPT
            var book = new Book    //#A
            {
                BookId = bookId    //#B
            };

            context.Remove(book);  //#C
            context.SaveChanges(); //#D

            /*****************************************************
             #A This creates the entity class that we want to delete - in this case a Book
             #B This sets the primary key of the entity instance
             #C The call to Remove tells EF Core you want this entity/row to be deleted
             #D Then SaveChanges sends the command to the database to delete that row
             ****************************************************/

            context.ChangeTracker.Clear();

            //VERIFY
            context.Books.Count().ShouldEqual(0);
        }
Exemplo n.º 8
0
        public void TestIncludeSortSingle()
        {
            //SETUP
            var options = SqliteInMemory.CreateOptions <EfCoreContext>();

            using (var context = new EfCoreContext(options))
            {
                context.Database.EnsureCreated();
                var newBook = new Book
                {
                    AuthorsLink = new List <BookAuthor>
                    {
                        new BookAuthor {
                            Author = new Author {
                                Name = "Author2"
                            }, Order = 2
                        },
                        new BookAuthor {
                            Author = new Author {
                                Name = "Author1"
                            }, Order = 1
                        },
                    }
                };
                context.Add(newBook);
                context.SaveChanges();
            }
            using (var context = new EfCoreContext(options))
            {
                //ATTEMPT
                var query = context.Books
                            .Include(x => x.AuthorsLink.OrderBy(y => y.Order))
                            .ThenInclude(x => x.Author);
                var books = query.ToList();

                //VERIFY
                _output.WriteLine(query.ToQueryString());
                books.Single().AuthorsLink.Select(x => x.Author.Name).ShouldEqual(new[] { "Author1", "Author2" });
            }
        }
Exemplo n.º 9
0
        public void TestCreateBookWithExistingAuthorAttached()
        {
            //SETUP
            var options =
                this.NewMethodUniqueDatabaseSeeded4Books();

            Author disconnectedAuthor;

            using (var context = new EfCoreContext(options))
            {
                //ATTEMPT
                disconnectedAuthor = context.Authors.First();
            }

            using (var context = new EfCoreContext(options))
            {
                var book = new Book
                {
                    Title       = "Test Book",
                    PublishedOn = DateTime.Today
                };
                context.Authors.Attach(disconnectedAuthor);
                book.AuthorsLink = new List <BookAuthor>
                {
                    new BookAuthor
                    {
                        Book   = book,
                        Author = disconnectedAuthor
                    }
                };

                //ATTEMPT
                context.Add(book);
                context.SaveChanges();

                //VERIFY
                context.Books.Count().ShouldEqual(5);
                context.Authors.Count().ShouldEqual(3);
            }
        }
Exemplo n.º 10
0
        public void TestBookListReviewSaveChangesTimeOk(int numReviews)
        {
            //SETUP
            var options = SqliteInMemory.CreateOptions <EfCoreContext>();

            using var context = new EfCoreContext(options);
            context.Database.EnsureCreated();
            var book = CreateBookWithListReviews(numReviews);

            using (new TimeThings(_output, $"ADD BookListReview: {numReviews} entries"))
                context.Add(book);
            context.SaveChanges();

            using (new TimeThings(_output, $"1: BookListReview: {numReviews} entries"))
            {
                context.SaveChanges();
            }
            using (new TimeThings(_output, $"2: BookListReview: {numReviews} entries"))
            {
                context.SaveChanges();
            }
        }
Exemplo n.º 11
0
        public void TestDeletePriceOfferQuicklyOk()
        {
            //SETUP
            int priceOfferId;
            var options = SqliteInMemory.CreateOptions <EfCoreContext>();

            using var context = new EfCoreContext(options);
            context.Database.EnsureCreated();
            var book = new Book
            {
                Title     = "Test Book",
                Promotion = new PriceOffer {
                    NewPrice = 1
                }
            };

            context.Add(book);
            context.SaveChanges();
            priceOfferId = book.Promotion.PriceOfferId;
            context.Books.Count().ShouldEqual(1);
            context.PriceOffers.Count().ShouldEqual(1);

            context.ChangeTracker.Clear();

            //ATTEMPT
            var pOfferToDelete = new PriceOffer {
                PriceOfferId = priceOfferId
            };

            context.Remove(pOfferToDelete);
            context.SaveChanges();

            context.ChangeTracker.Clear();

            //VERIFY
            context.Books.Count().ShouldEqual(1);
            context.PriceOffers.Count().ShouldEqual(0);
        }
Exemplo n.º 12
0
        public void TestIncludeSortReviewsDisconnected()
        {
            //SETUP
            var options = SqliteInMemory.CreateOptions <EfCoreContext>();

            using (var context = new EfCoreContext(options))
            {
                context.Database.EnsureCreated();
                var newBook = new Book
                {
                    Reviews = new List <Review>
                    {
                        new Review {
                            NumStars = 2
                        }, new Review {
                            NumStars = 1
                        }, new Review {
                            NumStars = 3
                        }
                    }
                };
                context.Add(newBook);
                context.SaveChanges();
            }
            using (var context = new EfCoreContext(options))
            {
                //ATTEMPT
                var query = context.Books
                            .Include(x => x.Reviews.OrderBy(y => y.NumStars));
                var books = query.ToList();

                //VERIFY
                _output.WriteLine(query.ToQueryString());
                books.Single().Reviews.Select(x => x.NumStars).ShouldEqual(new[] { 1, 2, 3 });
                var hashSet = new HashSet <Review>(context.Set <Review>().ToList());
                hashSet.Select(x => x.NumStars).ShouldEqual(new[] { 2, 1, 3 });
            }
        }
        public void TestCreatePriceOffer()
        {
            //SETUP
            var options = SqliteInMemory.CreateOptions <EfCoreContext>();

            using (var context = new EfCoreContext(options))
            {
                context.Database.EnsureCreated();
                context.SeedDatabaseFourBooks();

                var orgPriceOffers = context.PriceOffers.Count();
                var book           = context.Books
                                     .First(p => p.Promotion == null); //#A

                //ATTEMPT
                context.Add(new PriceOffer                //#B
                {                                         //#C
                    BookId          = book.BookId,        //#C
                    NewPrice        = book.Price / 2,     //#C
                    PromotionalText = "Half price today!" //#C
                });                                       //#C
                context.SaveChanges();                    //#D

                /******************************************************
                 #A Here I find the book that I want to add the new PriceOffer to. It must NOT have an existing PriceOffer
                 #B I add the new PriceOffer to the PriceOffers table
                 #C This defines the PriceOffer. Note that you MUST include the BookId (previously EF Core filled that in)
                 #D SaveChanges adds the PriceOffer to the PriceOffers table
                 * *****************************************************/

                //VERIFY
                var bookAgain = context.Books
                                .Include(p => p.Promotion)
                                .Single(p => p.BookId == book.BookId);
                bookAgain.Promotion.ShouldNotBeNull();
                context.PriceOffers.Count().ShouldEqual(orgPriceOffers + 1);
            }
        }
Exemplo n.º 14
0
        public void TestDeletePriceOfferRemoveNullsNavigatinalLinkOk()
        {
            //SETUP
            var options = SqliteInMemory.CreateOptions <EfCoreContext>();

            using var context = new EfCoreContext(options);
            context.Database.EnsureCreated();
            var book = new Book
            {
                Title     = "Test Book",
                Promotion = new PriceOffer {
                    NewPrice = 1
                }
            };

            context.Add(book);
            context.SaveChanges();
            context.Books.Count().ShouldEqual(1);
            context.PriceOffers.Count().ShouldEqual(1);

            context.ChangeTracker.Clear();

            //ATTEMPT
            var bookWithPromotion = context.Books
                                    .Include(x => x.Promotion).Single();

            context.Remove(bookWithPromotion.Promotion);
            context.SaveChanges();
            bookWithPromotion.Promotion.ShouldBeNull();

            context.ChangeTracker.Clear();

            //VERIFY
            context.Books.Count().ShouldEqual(1);
            context.PriceOffers.Count().ShouldEqual(0);
        }
Exemplo n.º 15
0
        public async Task CorrectPaymentsSelected()
        {
            // Arrange
            var account  = new Account("asdf");
            var category = new Category("Test");
            var payment1 = new Payment(DateTime.Now, 20, PaymentType.Expense, account);
            var payment2 = new Payment(DateTime.Now, 30, PaymentType.Expense, account, category: category);
            var payment3 = new Payment(DateTime.Now, 40, PaymentType.Expense, account, category: category);

            context.Add(payment1);
            context.Add(payment2);
            context.Add(payment3);
            await context.SaveChangesAsync();

            // Act
            System.Collections.Generic.List <Payment> result = await new GetPaymentsForCategoryQuery.Handler(contextAdapterMock.Object).Handle(
                new GetPaymentsForCategoryQuery(
                    category.Id,
                    DateTime.Now.AddDays(-1),
                    DateTime.Now.AddDays(1)), default);

            // Assert
            result.Count.Should().Be(2);
        }
 public void Add(FormDictionary formDictionary)
 {
     _context.Add <FormDictionary>(formDictionary);
 }
Exemplo n.º 17
0
 public async Task<int> Add(UserTask task)
 {
    _context.Add(task);
    return await _context.SaveChangesAsync();
 }
        public void TestCopyOrderOk()
        {
            //SETUP
            var sqlOptions = SqliteInMemory.CreateOptions <EfCoreContext>();

            using (var context = new EfCoreContext(sqlOptions))
            {
                context.Database.EnsureCreated();

                var books = context.SeedDatabaseFourBooks();                 //#A
                var order = new Order                                        //#B
                {
                    CustomerId = Guid.Empty,                                 //#C
                    LineItems  = new List <LineItem>
                    {
                        new LineItem                                         //#D
                        {                                                    //#D
                            LineNum = 1, ChosenBook = books[0], NumBooks = 1 //#D
                        },                                                   //#D
                        new LineItem                                         //#E
                        {                                                    //#E
                            LineNum = 2, ChosenBook = books[1], NumBooks = 2 //#E
                        },                                                   //#E
                    }
                };
                context.Add(order);                                          //#F
                context.SaveChanges();                                       //#F

                /*************************************************************
                 #A For this test I add four books to use as test data
                 #B I create an Order with two LinItems that I want to copy
                 #C I set CustomerId to the default value so that the query filter lets me read the order back
                 #D I add the first LineNum linked to the first book
                 #E I add the second LineNum linked to the second book
                 #F I write this Order out to the database
                 **********************************************************/
            }
            using (var context = new EfCoreContext(sqlOptions))
            {
                //ATTEMPT
                var order = context.Orders                    //#A
                            .AsNoTracking()                   //#B
                            .Include(x => x.LineItems)        //#C
                                                              //#D
                            .Single();                        //#E

                order.OrderId = default;                      //#F
                order.LineItems.First().LineItemId = default; //#F
                order.LineItems.Last().LineItemId  = default; //#F
                context.Add(order);                           //#G
                context.SaveChanges();                        //#G

                /******************************************************
                 #A This is going to query the Orders table.
                 #B The AsNoTracking means the entities read in as not tracked, that means their State will be Detached
                 #C You include the LineItems as we want to copy those too
                 #D You do NOT add .ThenInclude(x => x.ChosenBook) to the query. If you did it would copy the Book entities and that not what we want
                 #E You take the Order that we want to copy
                 #F You reset the primary keys (Order and LineItem) to their default value. That will tell the database to generate new primary keys
                 #G Finally you write out the order, which then create a copy.
                 ****************************************************/
            }
            using (var context = new EfCoreContext(sqlOptions))
            {
                //VERIFY
                var orders = context.Orders
                             .Include(x => x.LineItems)
                             .ToList();
                orders.Count.ShouldEqual(2);
                orders[0].LineItems.Count.ShouldEqual(2);
                orders[1].LineItems.Count.ShouldEqual(2);
                for (int i = 0; i < 2; i++)
                {
                    orders[i].LineItems.OrderBy(x => x.LineNum).Select(x => x.BookId).ShouldEqual(new [] { 1, 2 });
                    orders[i].LineItems.OrderBy(x => x.LineNum).Select(x => x.NumBooks).ShouldEqual(new short[] { 1, 2 });
                    orders[i].LineItems.OrderBy(x => x.LineNum).Select(x => x.LineNum).ShouldEqual(new byte[] { 1, 2 });
                }
            }
        }
Exemplo n.º 19
0
 public void Add(MDRDocument mDRDocument)
 {
     _context.Add <MDRDocument>(mDRDocument);
 }
Exemplo n.º 20
0
 public void Add(Activity activity)
 {
     _context.Add <Activity>(activity);
 }
        public void TestCreateBookWithExistingAuthor_CheckThreeStagesOk()
        {
            //SETUP
            var options = SqliteInMemory.CreateOptions <EfCoreContext>();

            using (var context = new EfCoreContext(options))
            {
                context.Database.EnsureCreated();
                context.SeedDatabaseFourBooks();
            }
            using (var context = new EfCoreContext(options))
            {
                //STAGE1
                var author     = context.Authors.First();
                var bookAuthor = new BookAuthor {
                    Author = author
                };
                var book = new Book
                {
                    Title       = "Test Book",
                    AuthorsLink = new List <BookAuthor> {
                        bookAuthor
                    }
                };
                //Read the states
                context.Entry(author).State.ShouldEqual(EntityState.Unchanged);
                context.Entry(bookAuthor).State.ShouldEqual(EntityState.Detached);
                context.Entry(book).State.ShouldEqual(EntityState.Detached);
                //These navigational links have not been set up
                book.AuthorsLink.Single().Book.ShouldBeNull();
                author.BooksLink.ShouldBeNull();
                //tracked PK/FK values not set
                context.Entry(book).Property(nameof(Book.BookId)).CurrentValue.ShouldEqual(0);
                context.Entry(bookAuthor).Property(nameof(BookAuthor.BookId)).CurrentValue.ShouldEqual(0);
                context.Entry(bookAuthor).Property(nameof(BookAuthor.AuthorId)).CurrentValue.ShouldEqual(0);

                //STAGE2
                context.Add(book);
                //Read the states
                context.Entry(author).State.ShouldEqual(EntityState.Unchanged);
                context.Entry(bookAuthor).State.ShouldEqual(EntityState.Added);
                context.Entry(book).State.ShouldEqual(EntityState.Added);
                //Extra Navigational links filled in after call to Add
                book.AuthorsLink.Single().Book.ShouldEqual(book);
                author.BooksLink.Single().ShouldEqual(book.AuthorsLink.Single());
                //Real PKs/FKs
                book.BookId.ShouldEqual(0);
                book.AuthorsLink.Single().BookId.ShouldEqual(0);
                book.AuthorsLink.Single().AuthorId.ShouldEqual(author.AuthorId);
                //tracked PK/FK values of new entities should be negative for Added classes, or actual PK if read in/Unchanged
                var tempBookId = (int)context.Entry(bookAuthor).Property(nameof(BookAuthor.BookId)).CurrentValue;
                (tempBookId < 0).ShouldBeTrue();
                context.Entry(book).Property(nameof(Book.BookId)).CurrentValue.ShouldEqual(tempBookId);
                ((int)context.Entry(bookAuthor).Property(nameof(BookAuthor.AuthorId)).CurrentValue).ShouldEqual(author.AuthorId);

                //STAGE3
                context.SaveChanges();
                context.Entry(author).State.ShouldEqual(EntityState.Unchanged);
                context.Entry(bookAuthor).State.ShouldEqual(EntityState.Unchanged);
                context.Entry(book).State.ShouldEqual(EntityState.Unchanged);
                book.BookId.ShouldEqual(5);
                book.AuthorsLink.Single().BookId.ShouldEqual(book.BookId);
                book.AuthorsLink.Single().AuthorId.ShouldEqual(author.AuthorId);
            }
        }
Exemplo n.º 22
0
        public void TestInit()
        {
            var optionsBuilder = new DbContextOptionsBuilder <EfCoreContext>();

            optionsBuilder.UseSqlServer(ConfigurationManager.ConnectionStrings["DEV26"].ConnectionString);

            _dbCoreContext = new EfCoreContext(optionsBuilder.Options);

            _dbCoreContext.Database.EnsureCreated();

            // clean the DB
            _dbCoreContext.Database.ExecuteSqlCommand("DELETE FROM Reviews");
            _dbCoreContext.Database.ExecuteSqlCommand("DELETE FROM Books");

            // create initial test data
            var books = new[]
            {
                new Book()
                {
                    Author = "Vadim",
                    Title  = "Title 1",
                },
                new Book()
                {
                    Author = "Dmitry",
                    Title  = "Title 2",
                },
                new Book()
                {
                    Author = "Igor",
                    Title  = "Title 3",
                },
            };

            var reviews = new[]
            {
                new Review()
                {
                    Book       = books[0],
                    ReviewText = "Review 1",
                },
                new Review()
                {
                    Book       = books[0],
                    ReviewText = "Review 2",
                },
                new Review()
                {
                    Book       = books[1],
                    ReviewText = "Review 1",
                },
                new Review()
                {
                    Book       = books[1],
                    ReviewText = "Review 2",
                },
                new Review()
                {
                    Book       = books[2],
                    ReviewText = "Review 1",
                },
                new Review()
                {
                    Book       = books[2],
                    ReviewText = "Review 2",
                },
            };

            foreach (var book in books)
            {
                _dbCoreContext.Add(book);
            }

            foreach (var review in reviews)
            {
                _dbCoreContext.Add(review);
            }

            _dbCoreContext.SaveChanges();

            // stored proc for reads
            try
            {
                _dbCoreContext.Database.ExecuteSqlCommand("DROP PROCEDURE sp_ReadBooks");
            }
            catch
            {
                // intentionally left blank
            }

            _dbCoreContext.Database.ExecuteSqlCommand(@"
            CREATE PROCEDURE sp_ReadBooks
	                @id int = 0
                AS
                BEGIN
	                SET NOCOUNT ON;

                    if @id = 0
                    begin
                        SELECT * from Books;
                    end
                    else begin
	                    SELECT * from Books where Id = @id;
                    end
                END
            ");
        }